mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 06:00:46 +00:00
Implement super-smart STM calculations, #84
It's excellent now, also fixed inventory not returning all of my 6k items (sigh)
This commit is contained in:
@@ -313,12 +313,12 @@ namespace ArchiSteamFarm {
|
||||
uint appID = 0;
|
||||
Steam.Item.EType type = Steam.Item.EType.Unknown;
|
||||
|
||||
string hashName = description["market_hash_name"].ToString();
|
||||
string hashName = description["market_hash_name"].Value;
|
||||
if (!string.IsNullOrEmpty(hashName)) {
|
||||
appID = GetAppIDFromMarketHashName(hashName);
|
||||
}
|
||||
|
||||
string descriptionType = description["type"].ToString();
|
||||
string descriptionType = description["type"].Value;
|
||||
if (!string.IsNullOrEmpty(descriptionType)) {
|
||||
type = GetItemType(descriptionType);
|
||||
}
|
||||
@@ -460,94 +460,107 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
JObject jObject = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && jObject == null; i++) {
|
||||
jObject = await WebBrowser.UrlGetToJObject(SteamCommunityURL + "/my/inventory/json/" + Steam.Item.SteamAppID + "/" + Steam.Item.SteamContextID + "?trading=1").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (jObject == null) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerable<JToken> descriptions = jObject.SelectTokens("$.rgDescriptions.*");
|
||||
if (descriptions == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>> descriptionMap = new Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>>();
|
||||
foreach (JToken description in descriptions) {
|
||||
string classIDString = description["classid"].ToString();
|
||||
if (string.IsNullOrEmpty(classIDString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ulong classID;
|
||||
if (!ulong.TryParse(classIDString, out classID) || classID == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string instanceIDString = description["instanceid"].ToString();
|
||||
if (string.IsNullOrEmpty(instanceIDString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ulong instanceID;
|
||||
if (!ulong.TryParse(instanceIDString, out instanceID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(classID, instanceID);
|
||||
if (descriptionMap.ContainsKey(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint appID = 0;
|
||||
Steam.Item.EType type = Steam.Item.EType.Unknown;
|
||||
|
||||
string hashName = description["market_hash_name"].ToString();
|
||||
if (!string.IsNullOrEmpty(hashName)) {
|
||||
appID = GetAppIDFromMarketHashName(hashName);
|
||||
}
|
||||
|
||||
string descriptionType = description["type"].ToString();
|
||||
if (!string.IsNullOrEmpty(descriptionType)) {
|
||||
type = GetItemType(descriptionType);
|
||||
}
|
||||
|
||||
descriptionMap[key] = new Tuple<uint, Steam.Item.EType>(appID, type);
|
||||
}
|
||||
|
||||
IEnumerable<JToken> items = jObject.SelectTokens("$.rgInventory.*");
|
||||
if (descriptions == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<Steam.Item> result = new HashSet<Steam.Item>();
|
||||
foreach (JToken item in items) {
|
||||
|
||||
Steam.Item steamItem;
|
||||
|
||||
try {
|
||||
steamItem = JsonConvert.DeserializeObject<Steam.Item>(item.ToString());
|
||||
} catch (JsonException e) {
|
||||
Logging.LogGenericException(e, Bot.BotName);
|
||||
continue;
|
||||
ushort nextPage = 0;
|
||||
while (true) {
|
||||
JObject jObject = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && jObject == null; i++) {
|
||||
jObject = await WebBrowser.UrlGetToJObject(SteamCommunityURL + "/my/inventory/json/" + Steam.Item.SteamAppID + "/" + Steam.Item.SteamContextID + "?trading=1&start=" + nextPage).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (steamItem == null) {
|
||||
continue;
|
||||
if (jObject == null) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return null;
|
||||
}
|
||||
|
||||
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(steamItem.ClassID, steamItem.InstanceID);
|
||||
|
||||
Tuple<uint, Steam.Item.EType> description;
|
||||
if (descriptionMap.TryGetValue(key, out description)) {
|
||||
steamItem.RealAppID = description.Item1;
|
||||
steamItem.Type = description.Item2;
|
||||
IEnumerable<JToken> descriptions = jObject.SelectTokens("$.rgDescriptions.*");
|
||||
if (descriptions == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
result.Add(steamItem);
|
||||
Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>> descriptionMap = new Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>>();
|
||||
foreach (JToken description in descriptions) {
|
||||
string classIDString = description["classid"].ToString();
|
||||
if (string.IsNullOrEmpty(classIDString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ulong classID;
|
||||
if (!ulong.TryParse(classIDString, out classID) || classID == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string instanceIDString = description["instanceid"].ToString();
|
||||
if (string.IsNullOrEmpty(instanceIDString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ulong instanceID;
|
||||
if (!ulong.TryParse(instanceIDString, out instanceID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(classID, instanceID);
|
||||
if (descriptionMap.ContainsKey(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint appID = 0;
|
||||
Steam.Item.EType type = Steam.Item.EType.Unknown;
|
||||
|
||||
string hashName = description["market_hash_name"].ToString();
|
||||
if (!string.IsNullOrEmpty(hashName)) {
|
||||
appID = GetAppIDFromMarketHashName(hashName);
|
||||
}
|
||||
|
||||
string descriptionType = description["type"].ToString();
|
||||
if (!string.IsNullOrEmpty(descriptionType)) {
|
||||
type = GetItemType(descriptionType);
|
||||
}
|
||||
|
||||
descriptionMap[key] = new Tuple<uint, Steam.Item.EType>(appID, type);
|
||||
}
|
||||
|
||||
IEnumerable<JToken> items = jObject.SelectTokens("$.rgInventory.*");
|
||||
if (descriptions == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (JToken item in items) {
|
||||
|
||||
Steam.Item steamItem;
|
||||
|
||||
try {
|
||||
steamItem = JsonConvert.DeserializeObject<Steam.Item>(item.ToString());
|
||||
} catch (JsonException e) {
|
||||
Logging.LogGenericException(e, Bot.BotName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (steamItem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(steamItem.ClassID, steamItem.InstanceID);
|
||||
|
||||
Tuple<uint, Steam.Item.EType> description;
|
||||
if (descriptionMap.TryGetValue(key, out description)) {
|
||||
steamItem.RealAppID = description.Item1;
|
||||
steamItem.Type = description.Item2;
|
||||
}
|
||||
|
||||
result.Add(steamItem);
|
||||
}
|
||||
|
||||
bool more;
|
||||
if (!bool.TryParse(jObject["more"].ToString(), out more) || !more) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ushort.TryParse(jObject["more_start"].ToString(), out nextPage)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldAcceptTrade(tradeOffer)) {
|
||||
if (await ShouldAcceptTrade(tradeOffer).ConfigureAwait(false)) {
|
||||
Logging.LogGenericInfo("Accepting trade: " + tradeOffer.TradeOfferID, Bot.BotName);
|
||||
await Bot.ArchiWebHandler.AcceptTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false);
|
||||
} else {
|
||||
@@ -127,7 +127,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldAcceptTrade(Steam.TradeOffer tradeOffer) {
|
||||
private async Task<bool> ShouldAcceptTrade(Steam.TradeOffer tradeOffer) {
|
||||
if (tradeOffer == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -158,10 +158,64 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This STM trade SHOULD be fine
|
||||
// Potential TODO: Ensure that our inventory in fact has proper amount of both received and given cards
|
||||
// This way we could calculate amounts before and after trade, ensuring that we're in fact trading dupes and not 1 + 2 -> 0 + 3
|
||||
return true;
|
||||
// At this point we're sure that STM trade is valid
|
||||
// Now check if it's worth for us to do the trade
|
||||
HashSet<Steam.Item> inventory = await Bot.ArchiWebHandler.GetMyTradableInventory().ConfigureAwait(false);
|
||||
if (inventory == null || inventory.Count == 0) {
|
||||
return true; // OK, assume that this trade is valid, we can't check our EQ
|
||||
}
|
||||
|
||||
// Get appIDs we're interested in
|
||||
HashSet<uint> appIDs = new HashSet<uint>();
|
||||
foreach (Steam.Item item in tradeOffer.ItemsToGive) {
|
||||
appIDs.Add(item.RealAppID);
|
||||
}
|
||||
|
||||
// Now remove from our inventory all items we're NOT interested in
|
||||
inventory.RemoveWhere(item => !appIDs.Contains(item.RealAppID));
|
||||
|
||||
// Now let's create a map which maps items to their amount in our EQ
|
||||
Dictionary<Tuple<ulong, ulong>, uint> amountMap = new Dictionary<Tuple<ulong, ulong>, uint>();
|
||||
foreach (Steam.Item item in inventory) {
|
||||
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(item.ClassID, item.InstanceID);
|
||||
|
||||
uint amount;
|
||||
if (amountMap.TryGetValue(key, out amount)) {
|
||||
amountMap[key] = amount + item.Amount;
|
||||
} else {
|
||||
amountMap[key] = item.Amount;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate our value of items to give
|
||||
uint itemsToGiveDupesValue = 0;
|
||||
foreach (Steam.Item item in tradeOffer.ItemsToGive) {
|
||||
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(item.ClassID, item.InstanceID);
|
||||
|
||||
uint amount;
|
||||
if (!amountMap.TryGetValue(key, out amount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
itemsToGiveDupesValue += amount;
|
||||
}
|
||||
|
||||
// Calculate our value of items to receive
|
||||
uint itemsToReceiveDupesValue = 0;
|
||||
foreach (Steam.Item item in tradeOffer.ItemsToReceive) {
|
||||
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(item.ClassID, item.InstanceID);
|
||||
|
||||
uint amount;
|
||||
if (!amountMap.TryGetValue(key, out amount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
itemsToReceiveDupesValue += amount;
|
||||
}
|
||||
|
||||
// Trade is worth for us if we're in total trading more of our dupes for less of our dupes (or at least same amount)
|
||||
// Which means that itemsToGiveDupesValue should be at least itemsToReceiveDupesValue
|
||||
return itemsToGiveDupesValue >= itemsToReceiveDupesValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user