public static void OnMarketingMessage(SteamUser.MarketingMessageCallback callback) { foreach (var message in callback.Messages) { // TODO: Move this query outside this loop using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `ID` FROM `MarketingMessages` WHERE `ID` = @ID", new MySqlParameter("ID", message.ID))) { if (Reader.Read()) { continue; } } if (message.Flags == EMarketingMessageFlags.None) { IRC.SendMain("New marketing message:{0} {1}", Colors.DARK_BLUE, message.URL); } else { IRC.SendMain("New marketing message:{0} {1} {2}({3})", Colors.DARK_BLUE, message.URL, Colors.DARK_GRAY, message.Flags.ToString().Replace("Platform", string.Empty)); } DbWorker.ExecuteNonQuery("INSERT INTO `MarketingMessages` (`ID`, `Flags`) VALUES (@ID, @Flags)", new MySqlParameter("@ID", message.ID), new MySqlParameter("@Flags", message.Flags) ); } }
private void OnLicenseListCallback(SteamApps.LicenseListCallback licenseList) { if (licenseList.Result != EResult.OK) { Log.WriteError("Steam", "Unable to get license list: {0}", licenseList.Result); return; } Log.WriteInfo("Steam", "{0} Licenses: {1}", licenseList.LicenseList.Count, string.Join(", ", licenseList.LicenseList.Select(lic => lic.PackageID))); var timeNow = DateTime.Now; foreach (var license in licenseList.LicenseList) { if (license.PackageID != 0 && !OwnedPackages.Contains(license.PackageID) && timeNow.Subtract(license.TimeCreated).TotalSeconds < 600) { IRC.SendMain("New license granted: {0}{1}{2} -{3} {4} {5}({6}, {7})", Colors.OLIVE, SteamProxy.GetPackageName(license.PackageID), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetPackageURL(license.PackageID), Colors.NORMAL, license.LicenseType, license.PaymentMethod ); } OwnedPackages.Add(license.PackageID); } // TODO: Probably should handle deletions too, for OwnedPackages }
private void OnSystemMessage(IPacketGCMsg packetMsg) { var msg = new ClientGCMsgProtobuf <CMsgSystemBroadcast>(packetMsg).Body; Log.WriteInfo(Name, "Message: {0}", msg.message); IRC.SendMain("{0}{1}{2} system message:{3} {4}", Colors.OLIVE, SteamProxy.GetAppName(AppID), Colors.NORMAL, Colors.OLIVE, msg.message); }
private void OnVersionUpdate(IPacketGCMsg packetMsg) { var msg = new ClientGCMsgProtobuf <CMsgGCServerVersionUpdated>(packetMsg).Body; Log.WriteInfo(Name, "GC version changed ({0} -> {1})", LastVersion, msg.server_version); IRC.SendMain("{0}{1}{2} server version changed:{3} {4} {5}(from {6})", Colors.OLIVE, SteamProxy.GetAppName(AppID), Colors.NORMAL, Colors.OLIVE, msg.server_version, Colors.DARK_GRAY, LastVersion); LastVersion = (int)msg.server_version; }
private void OnLoggedOff(SteamUser.LoggedOffCallback callback) { Timer.Stop(); Log.WriteInfo("Steam", "Logged out of Steam: {0}", callback.Result); IRC.SendMain("Logged out of Steam: {0}{1}{2}. See{3} http://steamstat.us", Colors.OLIVE, callback.Result, Colors.NORMAL, Colors.DARK_BLUE); IRC.SendEmoteAnnounce("logged out of Steam: {0}", callback.Result); GameCoordinator.UpdateStatus(0, callback.Result.ToString()); }
private static void OnSillyCrashHandler(object sender, UnhandledExceptionEventArgs args) { var e = (Exception)args.ExceptionObject; Log.WriteError("Unhandled Exception", "{0} (is terminating: {1})\n{2}", e.Message, args.IsTerminating, e.StackTrace); if (args.IsTerminating) { IRC.SendMain("Hey, xPaw and Alram, I'm crashing over here!!"); Cleanup(); } }
private void OnItemSchemaUpdate(IPacketGCMsg packetMsg) { var msg = new ClientGCMsgProtobuf <CMsgUpdateItemSchema>(packetMsg).Body; if (LastSchemaVersion != 0 && LastSchemaVersion != msg.item_schema_version) { Log.WriteInfo(Name, "Schema change from {0} to {1}", LastSchemaVersion, msg.item_schema_version); IRC.SendMain("{0}{1}{2} item schema updated: {3}{4}{5} -{6} {7}", Colors.OLIVE, SteamProxy.GetAppName(AppID), Colors.NORMAL, Colors.DARK_GRAY, msg.item_schema_version.ToString("X4"), Colors.NORMAL, Colors.DARK_BLUE, msg.items_game_url); } LastSchemaVersion = msg.item_schema_version; #if DEBUG Log.WriteDebug(Name, msg.items_game_url); #endif }
private void OnWelcome(IPacketGCMsg packetMsg) { Timer.Stop(); int version = -1; // TF2 GC is not in sync if (AppID == 440) { var msg = new ClientGCMsgProtobuf <SteamKit2.GC.TF2.Internal.CMsgServerWelcome>(packetMsg).Body; version = (int)msg.active_version; } else { var msg = new ClientGCMsgProtobuf <CMsgClientWelcome>(packetMsg).Body; version = (int)msg.version; } Log.WriteInfo(Name, "New GC session ({0} -> {1})", LastVersion, version); string message = string.Format("New {0}{1}{2} GC session", Colors.OLIVE, SteamProxy.GetAppName(AppID), Colors.NORMAL); if (LastVersion == -1 || LastVersion == version) { message += string.Format(" {0}(version {1})", Colors.DARK_GRAY, version); } else { message += string.Format(" {0}(version changed from {1} to {2})", Colors.DARK_GRAY, LastVersion, version); } if (LastVersion != -1 && (LastVersion != version || LastStatus != GCConnectionStatus.GCConnectionStatus_HAVE_SESSION)) { IRC.SendMain(message); } IRC.SendAnnounce(message); LastVersion = version; LastStatus = GCConnectionStatus.GCConnectionStatus_HAVE_SESSION; UpdateStatus(AppID, LastStatus.ToString()); }
private void OnLoggedOn(SteamUser.LoggedOnCallback callback) { GameCoordinator.UpdateStatus(0, callback.Result.ToString()); if (callback.Result == EResult.AccountLogonDenied) { Console.Write("STEAM GUARD! Please enter the auth code sent to the email at {0}: ", callback.EmailDomain); AuthCode = Console.ReadLine().Trim(); return; } if (callback.Result != EResult.OK) { Log.WriteInfo("Steam", "Failed to login: {0}", callback.Result); IRC.SendEmoteAnnounce("failed to log in: {0}", callback.Result); Thread.Sleep(TimeSpan.FromSeconds(2)); return; } Log.WriteInfo("Steam", "Logged in, current Valve time is {0}", callback.ServerTime.ToString("R")); IRC.SendMain("Logged in to Steam. Valve time: {0}{1}", Colors.DARK_GRAY, callback.ServerTime.ToString("R")); IRC.SendEmoteAnnounce("logged in."); if (Settings.IsFullRun) { if (PreviousChange == 1) { GetPICSChanges(); } } else { Timer.Start(); } }
private void OnDisconnected(SteamClient.DisconnectedCallback callback) { if (!IsRunning) { Timer.Stop(); Log.WriteInfo("Steam", "Disconnected from Steam"); return; } if (Timer.Enabled) { IRC.SendMain("Disconnected from Steam. See{0} http://steamstat.us", Colors.DARK_BLUE); } Timer.Stop(); GameCoordinator.UpdateStatus(0, EResult.NoConnection.ToString()); if (SteamProxy.Instance.IRCRequests.Count > 0) { foreach (var request in SteamProxy.Instance.IRCRequests) { CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2}: Your request failed.", Colors.OLIVE, request.Command.Nickname, Colors.NORMAL); } SteamProxy.Instance.IRCRequests.Clear(); } const uint RETRY_DELAY = 15; Log.WriteInfo("Steam", "Disconnected from Steam. Retrying in {0} seconds...", RETRY_DELAY); IRC.SendEmoteAnnounce("disconnected from Steam. Retrying in {0} seconds...", RETRY_DELAY); Thread.Sleep(TimeSpan.FromSeconds(RETRY_DELAY)); Client.Connect(); }
public void OnPICSChanges(SteamApps.PICSChangesCallback callback) { // Print any apps importants first var important = callback.AppChanges.Keys.Intersect(ImportantApps); if (important.Count() > 5) { IRC.SendMain("{0}{1}{2} important apps updated -{3} {4}", Colors.OLIVE, important.Count(), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetChangelistURL(callback.CurrentChangeNumber)); } else { foreach (var app in important) { IRC.SendMain("Important app update: {0}{1}{2} -{3} {4}", Colors.OLIVE, GetAppName(app), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetAppURL(app, "history")); } } // And then important packages important = callback.PackageChanges.Keys.Intersect(ImportantSubs); if (important.Count() > 5) { IRC.SendMain("{0}{1}{2} important packages updated -{3} {4}", Colors.OLIVE, important.Count(), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetChangelistURL(callback.CurrentChangeNumber)); } else { foreach (var package in important) { IRC.SendMain("Important package update: {0}{1}{2} -{3} {4}", Colors.OLIVE, GetPackageName(package), Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetPackageURL(package, "history")); } } // Group apps and package changes by changelist, this will seperate into individual changelists var appGrouping = callback.AppChanges.Values.GroupBy(a => a.ChangeNumber); var packageGrouping = callback.PackageChanges.Values.GroupBy(p => p.ChangeNumber); // Join apps and packages back together based on changelist number var changeLists = Utils.FullOuterJoin(appGrouping, packageGrouping, a => a.Key, p => p.Key, (a, p, key) => new { ChangeNumber = key, Apps = a.ToList(), Packages = p.ToList(), }, new EmptyGrouping <uint, SteamApps.PICSChangesCallback.PICSChangeData>(), new EmptyGrouping <uint, SteamApps.PICSChangesCallback.PICSChangeData>()) .OrderBy(c => c.ChangeNumber); foreach (var changeList in changeLists) { var appCount = changeList.Apps.Count; var packageCount = changeList.Packages.Count; string Message = string.Format("Changelist {0}{1}{2} {3}({4:N0} apps and {5:N0} packages){6} -{7} {8}", Colors.OLIVE, changeList.ChangeNumber, Colors.NORMAL, Colors.DARK_GRAY, appCount, packageCount, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetChangelistURL(changeList.ChangeNumber) ); var changesCount = appCount + packageCount; if (changesCount >= 50) { IRC.SendMain(Message); } IRC.SendAnnounce("{0}»{1} {2}", Colors.RED, Colors.NORMAL, Message); // If this changelist is very big, freenode will hate us forever if we decide to print all that stuff if (changesCount > 500) { IRC.SendAnnounce("{0} This changelist is too big to be printed in IRC, please view it on our website", Colors.RED); continue; } string name; if (appCount > 0) { foreach (var app in changeList.Apps) { name = GetAppName(app.ID, true); if (string.IsNullOrEmpty(name)) { name = string.Format("{0}{1}{2}", Colors.GREEN, app.ID, Colors.NORMAL); } else { name = string.Format("{0}{1}{2} - {3}", Colors.LIGHT_GRAY, app.ID, Colors.NORMAL, name); } IRC.SendAnnounce(" App: {0}{1}", name, app.NeedsToken ? StringNeedToken : string.Empty); } } if (packageCount > 0) { foreach (var package in changeList.Packages) { name = GetPackageName(package.ID, true); if (string.IsNullOrEmpty(name)) { name = string.Format("{0}{1}{2}", Colors.GREEN, package.ID, Colors.NORMAL); } else { name = string.Format("{0}{1}{2} - {3}", Colors.LIGHT_GRAY, package.ID, Colors.NORMAL, name); } IRC.SendAnnounce(" Package: {0}{1}{2}", name, package.NeedsToken ? StringNeedToken : string.Empty, Steam.Instance.OwnedPackages.Contains(package.ID) ? StringCheckmark : string.Empty ); } } } }
public void OnClanState(SteamFriends.ClanStateCallback callback) { if (callback.Events.Count == 0 && callback.Announcements.Count == 0) { return; } string groupName = callback.ClanName; string message; if (string.IsNullOrEmpty(groupName)) { groupName = Steam.Instance.Friends.GetClanName(callback.ClanID); // Check once more, because that can fail too if (string.IsNullOrEmpty(groupName)) { groupName = "Group"; Log.WriteError("IRC Proxy", "ClanID: {0} - no group name", callback.ClanID); } } foreach (var announcement in callback.Announcements) { message = string.Format("{0}{1}{2} announcement: {3}{4}{5} -{6} http://steamcommunity.com/gid/{7}/announcements/detail/{8}", Colors.OLIVE, groupName, Colors.NORMAL, Colors.GREEN, announcement.Headline, Colors.NORMAL, Colors.DARK_BLUE, callback.ClanID, announcement.ID ); IRC.SendMain(message); // Additionally send announcements to steamlug channel if (callback.ClanID.Equals(SteamLUG)) { IRC.SendSteamLUG(message); } Log.WriteInfo("Group Announcement", "{0} \"{1}\"", groupName, announcement.Headline); } foreach (var groupEvent in callback.Events) { if (groupEvent.JustPosted) { message = string.Format("{0}{1}{2} event: {3}{4}{5} -{6} http://steamcommunity.com/gid/{7}/events/{8} {9}({10})", Colors.OLIVE, groupName, Colors.NORMAL, Colors.GREEN, groupEvent.Headline, Colors.NORMAL, Colors.DARK_BLUE, callback.ClanID, groupEvent.ID, Colors.DARK_GRAY, groupEvent.EventTime.ToString() ); // Send events only to steamlug channel if (callback.ClanID.Equals(SteamLUG)) { IRC.SendSteamLUG(message); } else { IRC.SendMain(message); } Log.WriteInfo("Group Announcement", "{0} Event \"{1}\"", groupName, groupEvent.Headline); } } }
private static void DownloadManifest(ManifestJob request) { DepotManifest depotManifest = null; string lastError = string.Empty; // CDN is very random, just keep trying for (var i = 0; i <= 5; i++) { try { depotManifest = CDNClient.DownloadManifest(request.DepotID, request.ManifestID, request.Server, request.DepotKey, request.CDNToken); break; } catch (Exception e) { lastError = e.Message; } } if (depotManifest == null) { Log.WriteError("Depot Processor", "Failed to download depot manifest for depot {0} (jobs still in queue: {1}) ({2}: {3})", request.DepotID, ManifestJobs.Count - 1, request.Server, lastError); if (SteamProxy.Instance.ImportantApps.Contains(request.ParentAppID)) { IRC.SendMain("Important depot update: {0}{1}{2} -{3} failed to download depot manifest", Colors.OLIVE, request.DepotName, Colors.NORMAL, Colors.RED); } return; } if (SteamProxy.Instance.ImportantApps.Contains(request.ParentAppID)) { IRC.SendMain("Important depot update: {0}{1}{2} -{3} {4}", Colors.OLIVE, request.DepotName, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetDepotURL(request.DepotID, "history")); } var sortedFiles = depotManifest.Files.OrderBy(f => f.FileName, StringComparer.OrdinalIgnoreCase); bool shouldHistorize = false; var filesNew = new List <DepotFile>(); var filesOld = new Dictionary <string, DepotFile>(); foreach (var file in sortedFiles) { System.Text.Encoding.UTF8.GetString(file.FileHash); var depotFile = new DepotFile { Name = file.FileName.Replace('\\', '/'), Size = file.TotalSize, Chunks = file.Chunks.Count, Flags = (int)file.Flags }; // TODO: Ideally we would check if filehash is not empty if (!file.Flags.HasFlag(EDepotFileFlag.Directory)) { depotFile.Hash = string.Concat(Array.ConvertAll(file.FileHash, x => x.ToString("X2"))); } filesNew.Add(depotFile); } using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Files` FROM `Depots` WHERE `DepotID` = @DepotID LIMIT 1", new MySqlParameter("DepotID", request.DepotID))) { if (Reader.Read()) { string files = Reader.GetString("Files"); if (!string.IsNullOrEmpty(files)) { shouldHistorize = true; var _filesOld = JsonConvert.DeserializeObject <List <DepotFile> >(files); filesOld = _filesOld.ToDictionary(x => x.Name); } } } DbWorker.ExecuteNonQuery("UPDATE `Depots` SET `Files` = @Files WHERE `DepotID` = @DepotID", new MySqlParameter("@DepotID", request.DepotID), new MySqlParameter("@Files", JsonConvert.SerializeObject(filesNew, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore })) ); if (shouldHistorize) { var filesAdded = new List <string>(); foreach (var file in filesNew) { if (filesOld.ContainsKey(file.Name)) { var oldFile = filesOld[file.Name]; if (oldFile.Size != file.Size) { MakeHistory(request, file.Name, "modified", oldFile.Size, file.Size); } else if (file.Hash != null && oldFile.Hash != null && !file.Hash.Equals(oldFile.Hash)) { MakeHistory(request, file.Name, "modified", oldFile.Size, file.Size); } filesOld.Remove(file.Name); } else { // We want to historize modifications first, and only then deletions and additions filesAdded.Add(file.Name); } } foreach (var file in filesOld) { MakeHistory(request, file.Value.Name, "removed"); } foreach (string file in filesAdded) { MakeHistory(request, file, "added"); } } lock (ManifestJobs) { Log.WriteDebug("Depot Processor", "DepotID: Processed {0} (jobs still in queue: {1})", request.DepotID, ManifestJobs.Count - 1); } }
private void TryProcess(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo) { string packageName = string.Empty; var apps = new Dictionary <uint, string>(); using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `Value` FROM `SubsInfo` INNER JOIN `KeyNamesSubs` ON `SubsInfo`.`Key` = `KeyNamesSubs`.`ID` WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID))) { while (Reader.Read()) { CurrentData.Add(DbWorker.GetString("Name", Reader), DbWorker.GetString("Value", Reader)); } } using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name` FROM `Subs` WHERE `SubID` = @SubID LIMIT 1", new MySqlParameter("@SubID", SubID))) { if (Reader.Read()) { packageName = DbWorker.GetString("Name", Reader); } } using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID`, `Type` FROM `SubsApps` WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID))) { while (Reader.Read()) { apps.Add(Reader.GetUInt32("AppID"), Reader.GetString("Type")); } } var kv = productInfo.KeyValues.Children.FirstOrDefault(); if (kv["name"].Value != null) { if (string.IsNullOrEmpty(packageName)) { DbWorker.ExecuteNonQuery("INSERT INTO `Subs` (`SubID`, `Name`) VALUES (@SubID, @Name) ON DUPLICATE KEY UPDATE `Name` = @Name", new MySqlParameter("@SubID", SubID), new MySqlParameter("@Name", kv["name"].Value) ); MakeHistory("created_sub"); MakeHistory("created_info", DATABASE_NAME_TYPE, string.Empty, kv["name"].Value); } else if (!packageName.Equals(kv["name"].Value)) { DbWorker.ExecuteNonQuery("UPDATE `Subs` SET `Name` = @Name WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID), new MySqlParameter("@Name", kv["name"].Value) ); MakeHistory("modified_info", DATABASE_NAME_TYPE, packageName, kv["name"].Value); } } foreach (KeyValue section in kv.Children) { string sectionName = section.Name.ToLower(); if (string.IsNullOrEmpty(sectionName) || sectionName.Equals("packageid") || sectionName.Equals("name")) { // Ignore common keys continue; } if (sectionName.Equals("appids") || sectionName.Equals("depotids")) { string type = sectionName.Replace("ids", string.Empty); // Remove "ids", so we get app from appids and depot from depotids uint typeID = (uint)(type.Equals("app") ? 0 : 1); // TODO: Remove legacy 0/1 and replace with type foreach (KeyValue childrenApp in section.Children) { uint appID = uint.Parse(childrenApp.Value); // Is this appid already in this package? if (apps.ContainsKey(appID)) { // Is this appid's type the same? if (apps[appID] != type) { DbWorker.ExecuteNonQuery("UPDATE `SubsApps` SET `Type` = @Type WHERE `SubID` = @SubID AND `AppID` = @AppID", new MySqlParameter("@SubID", SubID), new MySqlParameter("@AppID", appID), new MySqlParameter("@Type", type) ); MakeHistory("added_to_sub", typeID, apps[appID].Equals("app") ? "0" : "1", childrenApp.Value); } apps.Remove(appID); } else { DbWorker.ExecuteNonQuery("INSERT INTO `SubsApps` (`SubID`, `AppID`, `Type`) VALUES(@SubID, @AppID, @Type) ON DUPLICATE KEY UPDATE `Type` = @Type", new MySqlParameter("@SubID", SubID), new MySqlParameter("@AppID", appID), new MySqlParameter("@Type", type) ); MakeHistory("added_to_sub", typeID, string.Empty, childrenApp.Value); AppProcessor.MakeHistory(appID, ChangeNumber, "added_to_sub", typeID, string.Empty, SubID.ToString()); if (SteamProxy.Instance.ImportantApps.Contains(appID)) { IRC.SendMain("Important app {0}{1}{2} was added to package {3}{4}{5} -{6} {7}", Colors.OLIVE, SteamProxy.GetAppName(appID), Colors.NORMAL, Colors.OLIVE, packageName, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetPackageURL(SubID, "history") ); } } } } else if (sectionName.Equals("extended")) { string keyName; foreach (KeyValue children in section.Children) { if (children.Children.Count > 0) { Log.WriteError("Sub Processor", "SubID {0} has childen in extended section", SubID); } keyName = string.Format("{0}_{1}", sectionName, children.Name); ProcessKey(keyName, children.Name, children.Value); } } else if (section.Children.Count > 0) { sectionName = string.Format("root_{0}", sectionName); ProcessKey(sectionName, sectionName, DbWorker.JsonifyKeyValue(section), true); } else if (!string.IsNullOrEmpty(section.Value)) { string keyName = string.Format("root_{0}", sectionName); ProcessKey(keyName, sectionName, section.Value); } } foreach (string keyName in CurrentData.Keys) { if (!keyName.StartsWith("website", StringComparison.Ordinal)) { uint ID = GetKeyNameID(keyName); DbWorker.ExecuteNonQuery("DELETE FROM `SubsInfo` WHERE `SubID` = @SubID AND `Key` = @KeyNameID", new MySqlParameter("@SubID", SubID), new MySqlParameter("@KeyNameID", ID) ); MakeHistory("removed_key", ID, CurrentData[keyName]); } } foreach (var app in apps) { DbWorker.ExecuteNonQuery("DELETE FROM `SubsApps` WHERE `SubID` = @SubID AND `AppID` = @AppID AND `Type` = @Type", new MySqlParameter("@SubID", SubID), new MySqlParameter("@AppID", app.Key), new MySqlParameter("@Type", app.Value) ); uint typeID = (uint)(app.Value.Equals("app") ? 0 : 1); // TODO: Remove legacy 0/1 and replace with type MakeHistory("removed_from_sub", typeID, app.Key.ToString()); AppProcessor.MakeHistory(app.Key, ChangeNumber, "removed_from_sub", typeID, SubID.ToString()); if (SteamProxy.Instance.ImportantApps.Contains(app.Key)) { IRC.SendMain("Important app {0}{1}{2} was removed from package {3}{4}{5} -{6} {7}", Colors.OLIVE, SteamProxy.GetAppName(app.Key), Colors.NORMAL, Colors.OLIVE, packageName, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetPackageURL(SubID, "history") ); } } #if DEBUG if (kv["name"].Value == null) { if (string.IsNullOrEmpty(packageName)) // We don't have the package in our database yet { // Don't do anything then Log.WriteError("Sub Processor", "Got a package without a name, and we don't have it in our database: {0}", SubID); } else { ////MakeHistory("deleted_sub", "0", packageName, "", true); Log.WriteError("Sub Processor", "Got a package without a name, but we have it in our database: {0}", SubID); } } #endif }