Properly resolve #3358

This commit is contained in:
Łukasz Domeradzki
2024-12-20 14:17:53 +01:00
parent b251598ca4
commit 7dc3d16666
4 changed files with 25 additions and 19 deletions

View File

@@ -342,7 +342,7 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
return;
}
HashSet<uint> packageIDs = bot.OwnedPackageIDs.Where(static package => (Config?.SecretPackageIDs.Contains(package.Key) != true) && ((package.Value.PaymentMethod != EPaymentMethod.AutoGrant) || (Config?.SkipAutoGrantPackages == false))).Select(static package => package.Key).ToHashSet();
HashSet<uint> packageIDs = bot.OwnedPackages.Where(static package => (Config?.SecretPackageIDs.Contains(package.Key) != true) && ((package.Value.PaymentMethod != EPaymentMethod.AutoGrant) || (Config?.SkipAutoGrantPackages == false))).Select(static package => package.Key).ToHashSet();
HashSet<uint> appIDsToRefresh = [];
@@ -644,7 +644,7 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
return;
}
ulong contributorSteamID = ASF.GlobalConfig is { SteamOwnerID: > 0 } && new SteamID(ASF.GlobalConfig.SteamOwnerID).IsIndividualAccount ? ASF.GlobalConfig.SteamOwnerID : Bot.Bots.Values.Where(static bot => bot.SteamID > 0).MaxBy(static bot => bot.OwnedPackageIDs.Count)?.SteamID ?? 0;
ulong contributorSteamID = ASF.GlobalConfig is { SteamOwnerID: > 0 } && new SteamID(ASF.GlobalConfig.SteamOwnerID).IsIndividualAccount ? ASF.GlobalConfig.SteamOwnerID : Bot.Bots.Values.Where(static bot => bot.SteamID > 0).MaxBy(static bot => bot.OwnedPackages.Count)?.SteamID ?? 0;
if (contributorSteamID == 0) {
ASF.ArchiLogger.LogGenericError(Strings.FormatSubmissionNoContributorSet(nameof(ASF.GlobalConfig.SteamOwnerID)));

View File

@@ -257,8 +257,13 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
public string? Nickname { get; private set; }
[JsonIgnore]
[Obsolete($"Use {nameof(OwnedPackages)} instead, this property will be removed in the future version")]
[PublicAPI]
public FrozenDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)> OwnedPackageIDs { get; private set; } = FrozenDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)>.Empty;
public FrozenDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)> OwnedPackageIDs => OwnedPackages.Values.ToFrozenDictionary(static entry => entry.PackageID, static entry => (entry.PaymentMethod, entry.TimeCreated));
[JsonIgnore]
[PublicAPI]
public FrozenDictionary<uint, SteamApps.LicenseListCallback.License> OwnedPackages { get; private set; } = FrozenDictionary<uint, SteamApps.LicenseListCallback.License>.Empty;
[JsonInclude]
[JsonRequired]
@@ -1112,7 +1117,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
ArgumentOutOfRangeException.ThrowIfZero(appID);
ArgumentOutOfRangeException.ThrowIfNegative(hoursPlayed);
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(appID, OwnedPackageIDs.Keys);
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(appID, OwnedPackages.Keys);
if ((packageIDs == null) || (packageIDs.Count == 0)) {
return (0, DateTime.MaxValue, true);
@@ -1122,7 +1127,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
DateTime mostRecent = DateTime.MinValue;
foreach (uint packageID in packageIDs) {
if (!OwnedPackageIDs.TryGetValue(packageID, out (EPaymentMethod PaymentMethod, DateTime TimeCreated) packageData)) {
if (!OwnedPackages.TryGetValue(packageID, out SteamApps.LicenseListCallback.License? packageData)) {
continue;
}
@@ -1147,7 +1152,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
DateTime safePlayableBefore = DateTime.UtcNow.AddMonths(-RegionRestrictionPlayableBlockMonths);
foreach (uint packageID in packageIDs) {
if (!OwnedPackageIDs.TryGetValue(packageID, out (EPaymentMethod PaymentMethod, DateTime TimeCreated) ownedPackageData)) {
if (!OwnedPackages.TryGetValue(packageID, out SteamApps.LicenseListCallback.License? ownedPackageData)) {
// We don't own that packageID, keep checking
continue;
}
@@ -2849,7 +2854,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
Trading.OnDisconnected();
FirstTradeSent = false;
OwnedPackageIDs = FrozenDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)>.Empty;
OwnedPackages = FrozenDictionary<uint, SteamApps.LicenseListCallback.License>.Empty;
EResult lastLogOnResult = LastLogOnResult;
@@ -3173,17 +3178,18 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
Commands.OnNewLicenseList();
Dictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)> ownedPackageIDs = new();
Dictionary<uint, SteamApps.LicenseListCallback.License> ownedPackages = new();
Dictionary<uint, ulong> packageAccessTokens = new();
Dictionary<uint, uint> packagesToRefresh = new();
bool hasNewEntries = false;
foreach (SteamApps.LicenseListCallback.License license in callback.LicenseList.GroupBy(static license => license.PackageID, static (_, licenses) => licenses.OrderByDescending(static license => license.TimeCreated).First())) {
ownedPackageIDs[license.PackageID] = (license.PaymentMethod, license.TimeCreated);
// We want to record only the most relevant entry, therefore we apply ordering here so we end up preferably with the most recent non-borrowed entry
foreach (SteamApps.LicenseListCallback.License license in callback.LicenseList.OrderByDescending(static license => license.LicenseFlags.HasFlag(ELicenseFlags.Borrowed)).ThenBy(static license => license.TimeCreated)) {
ownedPackages[license.PackageID] = license;
if (!OwnedPackageIDs.ContainsKey(license.PackageID)) {
if (!OwnedPackages.ContainsKey(license.PackageID)) {
hasNewEntries = true;
}
@@ -3197,7 +3203,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
}
}
OwnedPackageIDs = ownedPackageIDs.ToFrozenDictionary();
OwnedPackages = ownedPackages.ToFrozenDictionary();
if (packageAccessTokens.Count > 0) {
ASF.GlobalDatabase.RefreshPackageAccessTokens(packageAccessTokens);

View File

@@ -1496,11 +1496,11 @@ public sealed class CardsFarmer : IAsyncDisposable, IDisposable {
foreach (Game game in GamesToFarm) {
DateTime redeemDate = DateTime.MinValue;
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(game.AppID, Bot.OwnedPackageIDs.Keys);
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(game.AppID, Bot.OwnedPackages.Values.Where(static package => !package.LicenseFlags.HasFlag(ELicenseFlags.Borrowed)).Select(static package => package.PackageID));
if (packageIDs != null) {
foreach (uint packageID in packageIDs) {
if (!Bot.OwnedPackageIDs.TryGetValue(packageID, out (EPaymentMethod PaymentMethod, DateTime TimeCreated) packageData)) {
if (!Bot.OwnedPackages.TryGetValue(packageID, out SteamApps.LicenseListCallback.License? packageData)) {
Bot.ArchiLogger.LogNullError(packageData);
return;

View File

@@ -666,7 +666,7 @@ public sealed class Commands {
switch (type.ToUpperInvariant()) {
case "A" or "APP": {
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(gameID, Bot.OwnedPackageIDs.Keys, 1);
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(gameID, Bot.OwnedPackages.Values.Where(static package => !package.LicenseFlags.HasFlag(ELicenseFlags.Borrowed)).Select(static package => package.PackageID), 1);
if (packageIDs is { Count: > 0 }) {
response.AppendLine(FormatBotResponse(Strings.FormatBotAddLicense($"app/{gameID}", $"{EResult.Fail}/{EPurchaseResultDetail.AlreadyPurchased}")));
@@ -690,7 +690,7 @@ public sealed class Commands {
break;
}
default: {
if (Bot.OwnedPackageIDs.ContainsKey(gameID)) {
if (Bot.OwnedPackages.TryGetValue(gameID, out SteamApps.LicenseListCallback.License? package) && !package.LicenseFlags.HasFlag(ELicenseFlags.Borrowed)) {
response.AppendLine(FormatBotResponse(Strings.FormatBotAddLicense($"sub/{gameID}", $"{EResult.Fail}/{EPurchaseResultDetail.AlreadyPurchased}")));
break;
@@ -2020,7 +2020,7 @@ public sealed class Commands {
switch (type.ToUpperInvariant()) {
case "A" or "APP" when uint.TryParse(game, out uint appID) && (appID > 0):
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(appID, Bot.OwnedPackageIDs.Keys, 1);
HashSet<uint>? packageIDs = ASF.GlobalDatabase?.GetPackageIDs(appID, Bot.OwnedPackages.Values.Where(static package => !package.LicenseFlags.HasFlag(ELicenseFlags.Borrowed)).Select(static package => package.PackageID), 1);
if (packageIDs?.Count > 0) {
if ((gamesOwned != null) && gamesOwned.TryGetValue(appID, out string? cachedGameName)) {
@@ -2087,7 +2087,7 @@ public sealed class Commands {
continue;
case "S" or "SUB" when uint.TryParse(game, out uint packageID) && (packageID > 0):
if (Bot.OwnedPackageIDs.ContainsKey(packageID)) {
if (Bot.OwnedPackages.TryGetValue(packageID, out SteamApps.LicenseListCallback.License? package) && !package.LicenseFlags.HasFlag(ELicenseFlags.Borrowed)) {
result[$"sub/{packageID}"] = packageID.ToString(CultureInfo.InvariantCulture);
response.AppendLine(FormatBotResponse(Strings.FormatBotOwnedAlready($"sub/{packageID}")));
} else {
@@ -2658,7 +2658,7 @@ public sealed class Commands {
bool alreadyHandled = false;
foreach (Bot innerBot in Bot.Bots.Where(bot => (bot.Value != currentBot) && (!redeemFlags.HasFlag(ERedeemFlags.SkipInitial) || (bot.Value != Bot)) && !triedBots.Contains(bot.Value) && !rateLimitedBots.Contains(bot.Value) && bot.Value.IsConnectedAndLoggedOn && ((access >= EAccess.Owner) || ((steamID != 0) && (bot.Value.GetAccess(steamID) >= EAccess.Operator))) && ((items.Count == 0) || items.Keys.Any(packageID => !bot.Value.OwnedPackageIDs.ContainsKey(packageID)))).OrderBy(static bot => bot.Key, Bot.BotsComparer).Select(static bot => bot.Value)) {
foreach (Bot innerBot in Bot.Bots.Where(bot => (bot.Value != currentBot) && (!redeemFlags.HasFlag(ERedeemFlags.SkipInitial) || (bot.Value != Bot)) && !triedBots.Contains(bot.Value) && !rateLimitedBots.Contains(bot.Value) && bot.Value.IsConnectedAndLoggedOn && ((access >= EAccess.Owner) || ((steamID != 0) && (bot.Value.GetAccess(steamID) >= EAccess.Operator))) && ((items.Count == 0) || items.Keys.Any(packageID => !bot.Value.OwnedPackages.ContainsKey(packageID)))).OrderBy(static bot => bot.Key, Bot.BotsComparer).Select(static bot => bot.Value)) {
CStore_RegisterCDKey_Response? redeemResponse = await innerBot.Actions.RedeemKey(key).ConfigureAwait(false);
if (redeemResponse == null) {