Jump to content
McKay Development

Dr. McKay

Administrator
  • Posts

    3395
  • Joined

  • Last visited

Reputation Activity

  1. Like
    Dr. McKay got a reaction from Robert Lutece in Identifying Steam Items   
    Sometimes it can be a little confusing to identify a specific item in the Steam economy. There are several different types of IDs present in one particular item, and a lot of vague terminology. This guide aims to clear all that up for you.

    For starters, the "official" term for a Steam item is an asset. When I say a "Steam item", I mean a particular copy of an item. I'm not referring to the item's definition, name, image, or anything. I'm referring to a specific, unique copy of the item.

    In a general sense, every item on Steam must be owned by an app. An "app" is a game, software, or whatever on Steam. Every app has its own unique AppID. You can find a particular game's AppID by going to its store page or community hub and looking at the URL. For example, TF2's AppID is 440 so TF2's store page can be found at http://store.steampowered.com/app/440. CS:GO's is 730, Dota 2's is 570, and so on. Note that Steam Community items, Steam gifts, and other "Steam" items are owned by the "Steam" app, which has AppID 753. To identify an item, you'll need the AppID of the game which owns it.

    Of course, the AppID alone isn't enough. You also need two other IDs. Have you ever noticed how some games have multiple inventories, which appear in a drop-down list? An example is the Steam inventory, which has sub-inventories for "Community", "Gifts", "Coupons", etc. These "sub-inventories" are called contexts, and each context has its own context ID. If a game doesn't have a drop-down menu to select a context, that doesn't mean that it's without contexts. That only means that it has one single visible context. That single context still has an ID. For all current Valve games, the context ID for the publicly-visible context is 2.

    Context IDs can be a bit tricky. It's entirely up to the game's developer to determine how they work. For example, Valve games take the "single shared inventory" model in which there's one context ID which is shared by everyone. Under this model, an item belongs to one particular context and never leaves that context. Consequently, the item's context ID never changes. It is, however, possible for game developers to create contexts in any way they choose. For example, Spiral Knights uses the "per-character inventory" model in which everyone who plays the game has their own context IDs for their characters. Creating a new character creates a new context ID. This means that when an item is traded between users, its context ID will change as it moved out of a particular character's inventory.

    Those are the two different types of "containers" in the Steam economy. Apps own contexts, and contexts own assets. Every asset on Steam has, in addition to its AppID and context ID, an asset ID which is guaranteed to be unique inside of a given AppID+ContextID combination. Notice that this means that asset IDs are not unique across all of Steam. They aren't even unique across a particular app. They are only unique inside of a given context. For example, there could be two items with asset ID 1 in the same game, as long as they have different context IDs. An item's asset ID may be referred to as "assetid" or just plain "id".

    Context IDs and asset IDs are assigned by the game developer and can follow any pattern. They can change when traded or not. They may both be up to 64 bits in size. Consequently, Steam returns them (like all other 64-bit values) in JSON as strings.

    Still following? All of what we've learned so far leads us to this conclusion: in order to uniquely identify an item, you need its AppID, its context ID, and its asset ID. Once you have these three things, only then can you uniquely identify it. In fact, this is how you link to a particular item in a user's inventory: steamcommunity.com/profiles/steamid/inventory#appid_contextid_assetid. Here's an example: https://steamcommunity.com/id/DoctorMcKay/inventory#440_2_134161610

    What are these "classid" and "instanceid" values though?
    The observant reader may have noticed that there are two more IDs attached to a particular item which I haven't mentioned. These are the "classid" and "instanceid". These IDs are used to map an asset to its description.

    What's a description? A description is what you need in order to actually display an item. An item's description contains its name, image, color, market_name, whether it's tradable or not, whether it's marketable or not, and more. There are many endpoints on Steam which return JSON objects representing assets that only contain the asset's AppID, context ID, asset ID, classid, instanceid, and amount. An item's amount is how big of a stack it is. Unstackable items always have an amount of 1. Stackable items (such as Steam gems) may have a larger amount. Stacked items always have the same asset ID.

    What's the difference between a classid and an instanceid? In a nutshell, a classid "owns" an instanceid. The classid is all you need to get a general overview of an item. For example, items with the same classid will pretty much always have the same name and image. The instanceid allows you to get finer details such as how many kills are on a strange/StatTrak weapon, or custom names/descriptions.

    You can turn a classid/instanceid pair into a description using the GetAssetClassInfo WebAPI method. Notice that the instanceid is actually optional: if you only have a classid that's fine, you just won't get finer details for the item.

    Name? Market Name? Market Hash Name?
    Every asset on Steam has a name. Without a name, there's nothing to show in your inventory. The item's name is the name property of its description. The item's name may be localized if the game's developer has set it up to be.

    Every marketable item also has a "market name". This name may be the same as—or different from—the item's regular name. The item's market name is the market_name property of its description. This is the name that's displayed in the Steam Community Market when the item is up for sale. Why the distinction? There are some items which have value-affecting data that isn't in their name; for example, CS:GO skins have 5 different tiers of "wear", which isn't in their names. The wear tier is appended to each skin's market name however, so that the different tiers of wear are separated in the market. The market name may be localized or not, and may not exist at all if the item isn't marketable. It's up to the game's developer.

    Finally, every marketable item also has a "market hash name", available under the market_hash_name property. This name is supposed to be the English version of the item's market name, but in practice it may vary. For example, Steam Community items prepend the AppID of the originating app to each item's market hash name, but not to the market name. The market hash name is never localized, and may not exist if the item isn't marketable. Again, it's up to the game's developer. You can view the Community Market listings for any marketable item using this URL formula: steamcommunity.com/market/listings/appid/market_hash_name. Here's an example: https://steamcommunity.com/market/listings/440/Mann%20Co.%20Supply%20Crate%20Key

    Note that the Community Market has no concept of contexts. Consequently, market [hash] names are unique for a particular "class" of items per-app (and by extension per-context). This means that for marketable items, two items with identical market hash names will be worth roughly the same (with some exceptions, like unusual TF2 items).

    Questions?
    Ask below. I'm happy to help!
  2. Like
    Dr. McKay got a reaction from Coyeks in How to only accept CSGO keys in 'newOffer'   
    offer.itemsToReceive contains an array of the items you'd receive if you accepted this offer. For each item in this array, check appid to make sure it's CS:GO and name to make sure it's a key. For example:
    var allItemsAreGood = offer.itemsToReceive.every(function(item) { return item.appid == 730 && item.name == "CS:GO Case Key"; });
  3. Like
    Dr. McKay got a reaction from jazz in Custom Storage Engine   
    If that works it's a fluke. You should pass an Error to the callback, like this:
    callback(new Error("File not found"));
  4. Like
    Dr. McKay got a reaction from jazz in bind ip to node-steam-user   
    No. No Steam services support IPv6 at the present time.
  5. Like
    Dr. McKay got a reaction from Frost Byte in How to go from Steam64 to Steam username (the name currently used on steam)   
    Your problem is that getPersonas expects an array as the first argument, and you aren't passing it an array. What you want to do is client.getPersonas([steamID], function(personas) { /* etc */ });
     
    Also in this case, the callback is essentially mandatory for you. getPersonas doesn't return anything. The data is only available inside the callback. In your case, you want something like this:
    client.getPersonas([steamID], function(personas) { var persona = personas[steamID.getSteamID64()]; var name = persona ? persona.player_name : ("[" + steamID.getSteamID64() + "]"); // the player's name is now available as name });
  6. Like
    Dr. McKay reacted to Frost Byte in How to go from Steam64 to Steam username (the name currently used on steam)   
    I found out myself!
     
    You already have the properties and methods from the steam handlers in your own steam-user library. So there I don't need a specific handler like 'friends' to send a message. I can just ask your steam-user object (in my case I called it client) and ask for the chatMessage method.
     
    Right? Well it works for me now 
     
    Yeah, it really works. And I managed to only use your node-steam-user library with all it's functions + your node-steamcommunity library!
  7. Like
    Dr. McKay got a reaction from TextDynasty in Decline Trade Hold   
    https://github.com/DoctorMcKay/node-steam-user#chatmessagerecipient-message-type
  8. Like
    Dr. McKay got a reaction from TextDynasty in Decline Trade Hold   
    offer.getUserDetails(function(err, me, them) {
    if (err) {
    throw err;
    }

    if (them.escrowDays > 0) {
    offer.decline();
    }
    });
  9. Like
    Dr. McKay got a reaction from Santa in Deleting from poll data   
    It's not really recommended to manipulate poll data. TradeOfferManager's job is to emit newOffer once per incoming offer. Errors can be frustrating but it's your responsibility to make sure that they're dealt with properly.
     
    You could use offerList to check for offers that should have already been accepted (probably want to keep a list of offers you've attempted to accept and the timestamp so you don't try to accept an offer too frequently).
  10. Like
    Dr. McKay got a reaction from TextDynasty in cannot declined the wrong offer   
    You aren't assigning anything to BuyKey and FromRef1. forEach doesn't return anything.
     
    Also, further on down you're using = when you want to use ==
  11. Like
    Dr. McKay got a reaction from mtn in bind ip to node-steam-user & node-steamcommunity   
    The constructor is new SteamCommunity()
  12. Like
    Dr. McKay reacted to adma in cannot declined the wrong offer   
    I don't know what you are trying to do with the comma operator, but by the looks of it you want to use the and operator (&&) in your if (onlyKeys, onlyRef) checks...
     
    if (onlyKeys2, onlyRef2) âž¡ if (onlyKeys2 && onlyRef2)
     
    In regards to your declining offer thing... its probably to do with your lack of curly braces surrounding if and else e.g
    if (x && y) { // code } else { // code } Not ...
    if (x && y) // code else // code What do these lines do/mean?
    'refAmount = offer.itemsToGive.length == keyAmount * buyprice'
    'refAmount = offer.itemsToReceive.length == keyAmount * sellprice'
     
    Also, unless you want the refAmount and keyAmount to be global, you should really declare them with var ... keyAmount = offer.itemsToGive.length âž¡ var keyAmount =  offer.itemsToGive.length
     
    Even though I am new to coding/scripting and I can see your code is very untidy/messy...
     
    PS: What is offers.on('newOffer') ? and why is trade offer manager newOffer listener nested inside this???
  13. Like
    Dr. McKay got a reaction from boxxy in Will I get 7 day penality ?   
    If you're using two-factor authentication (via SDA or whatever), then there's no new-device cooldown, so no.
     
    But if you aren't, then the answer is still no because "devices" are remembered by sentry files. Your sentry file is saved by steam-user in your appdata directory, so it will always be reused on the same machine (until you reformat or whatever).
  14. Like
    Dr. McKay got a reaction from MrRobot in Error: HTTP error 302 on editProfile()   
    Thanks, live in v3.27.1.
  15. Like
    Dr. McKay got a reaction from adma in newOffer triggered on real trade   
    Check fromRealTimeTrade and abort if it's true in newOffer.
  16. Like
    Dr. McKay got a reaction from adma in Listening for accepted trade offer from real trade   
    https://github.com/DoctorMcKay/node-steam-tradeoffer-manager/wiki/Real-Time-Trades
  17. Like
    Dr. McKay got a reaction from GHOST in relogin to steam   
    Yes.
  18. Like
    Dr. McKay reacted to adma in Listening for accepted trade offer from real trade   
    I honestly can't believe how prompt you were with implementing this. Thanks very much McKay!
  19. Like
    Dr. McKay got a reaction from MrRobot in node-steamcommunity v3.26.1   
    Right.... you didn't see anything..... <_>
  20. Like
    Dr. McKay got a reaction from MrRobot in httpRequest with store.steampowered.com   
    You're kind of meant to use steam-store for store.steampowered.com requests, but I could see how it would be more useful to have that available in steamcommunity, especially since steam-store doesn't offer the HTTP stuff. This is now available in 3.26.0.
  21. Like
    Dr. McKay got a reaction from yellowish in Minimal code to stay logged in forever...   
    That all looks fine to me. sessionExpired is only emitted when a request you make fails because you aren't logged in. It doesn't check automatically, it only checks whenever the library makes a request somewhere.
     
    Starting a new confirmation checker without stopping the old one is just fine. It'll stop an old one if you call it while one is running.
     
    I recommend updating to v3.23.1 if you're going to use webchat.
  22. Like
    Dr. McKay got a reaction from MrRobot in A few Questions   
    Only Valve knows the answer to that, but out of the interest of everyone I'd avoid registering accounts super quickly.
    No idea.
    Not possible through steam-user at this time, but would be possible to implement. Couldn't give you a timeframe, though.
  23. Like
    Dr. McKay got a reaction from MrRobot in A few Questions   
    Okay, the timeframe was a bit sooner than expected. You can now change account email (which trade bans you for 5 days) and password (no trade ban) in v3.13.0.
  24. Like
    Dr. McKay got a reaction from KiTa in Cannot read property 'escrowDays' of undefined   
    No, that's the actual solution. Errors are a fact of life (especially when you're working with Steam). You need to handle them, or else you'll crash.
  25. Like
    Dr. McKay got a reaction from KiTa in Cannot read property 'escrowDays' of undefined   
    You aren't checking the error. In every callback, if err is truthy, then there was an error and all other arguments are undefined.
×
×
  • Create New...