- Home /
How to manage inventory 'objects' in C# for behind the scenes inventory stuff
In C# I have a static BaseLoot class that uses a dictionary to store predefined loot stats and attributes, using the loots type as an index.
Each time I instantiate a real piece of loot in the game world, it has an instance of a Loot class which derives its initial properties from looking up what they should be in the BaseLoot dictionary.
When the item is picked up, I add the object itself (i.e code object, instance of the Loot class) to a dictionary representing the characters inventory, (or subsequently a chests contents).
This is great as I can use all my accessors to retrieve or modify the item from within the inventory. But if there were 100's of items in the game world all being kept track of in this manner, does that scale? Does that make sense as a way to handle this in the code? Or does it make more sense to serialise the items stats, store them in a global RealItems dictionary with a unique Id, and in the players inventory just store the id? Then recreate the object whenever I want to operate on it?
Do either of those make sense as designs? Or am I barking up the wrong tree completely?
I have been through a number of tutorials on inventories but I get the idea that the tutorials I have seen are really just creating something that "works" in order to show some basic concepts, rather than designing and writing a system to be robust / extendable / manageable etc in the future. That said, I have no interest in over-complicating it just for the sake of it.
Im not new to programming, but Im fairly new to C#. So I can see ways to do stuff and generally make things work, but I dont have the C# experience to know straight away if theres a better way.
Answer by Hanseshadow.du · Jan 30, 2012 at 04:20 PM
Most new MMO's use object referencing. You have a master table of objects and their properties and you reference the object's ID. This allows you to use a database to store data more efficiently. It also allows for versioning of objects across the entire game, without leaving items (called "pre-patch" items) that have out of date properties.
If you need customization, you make a new object and slot it into the object. In that case, you would have the primary object's ID a slotted object ID (or group of ID's) inside it.
Inventory systems include visible inventory, overloaded inventory, store sales inventory (for buy-back purposes in case of accidental sales), trade inventory, equipped inventory, etc. Some systems have pet inventory slots, a mount slot for what object you're riding, and even an inventory for the mount itself for what it's wearing.
Inventory can be very complex! :)
Hey, thanks for the informative response. When you say "You have a master table of objects and their properties" do you mean described in the code and stored in memory, or some kind of file based db queries going on while the game is running to retrieve specific objects? Im familier with versioning content using db's but not considered this as a viable approach for items in an RPG. Interesting...
I've dealt with this using an Excel spreadsheet for an older $$anonymous$$$$anonymous$$O and assigned specific ID's in the spreadsheet.
In a newer $$anonymous$$$$anonymous$$O that came out in 2009, we used a SQL database for object appearances, descriptions, costs, etc. and linked database tables together to describe different aspects of the items (ie: fire based resistance items all pointed to a fire resistance property, which had a particle effect associated with it and combat formulas for the resistance itself).
So do you suggest database queries during game play to retrieve items? Or is common practice to populate a dictionary or similar at the start of the game?
Runtime queries or caching depends on how many items you are going to have and how much memory your objects will take up. If you have objects that take up 1k of memory and have 1000 objects, I'd use a combination of queries and caching, so you aren't hitting the db so often.
Cool. Horses for courses kind of thing. Thanks for the responses.
Answer by jc_lvngstn · Jan 31, 2012 at 05:11 PM
My online project I've been experimenting with does this: Server launches and loads everything from the database. Each item in the database knows certain core properties, and has a reference to others. I have a table for things like item type. Everything has a unique id (int), I never expect to have more than 2 billion items.
When I read everything in, I use a dictionary to store the item by its id, for very quick access. Type data is stored according to type. I use dictionaries a lot, arrays when it makes sense. Array access is much faster than dictionary access...but I don't know that I'm willing to make that change yet, I have to see a real need manifest itself first.
As far as storage...I always keep an eye out on doing things more efficiently. I do have some breathing room, my server is a 64 bit C# app.
So, data is only ever read from the database upon server start, from then on it resides in memory. I expect to use separate threads to update the database at specific intervals.
When you mention keeping track of items in the game...do you really actively have to track a lot of items? In my project, most of my items are in containers...and the ones that are not are either equipped by the player, or sparse in the world. Items that are in containers don't really need be managed as much as stored items (at least in my situation).
Hey, thanks for the info. That's really helpful.
Re tracking items, once an item has had any interaction with the player then I need to track them as specific entities whether they are in the world on the ground, or in an inventory of some sort (player, chest, mount etc), as any interaction with the player will likely mean the items stats have changed and the game revolves around this kind of thing. So once a player has had contact with an item its not enough to just reference an example of that item type in a master database - it needs to be a real record somewhere with stats and modifications for that specific instance of the item - irrespective of whether it is equiped, thrown to the floor, or stored in a chest.
Hence my question of whether I should maintain each of these items as code objects (as in, instances of a loot class) at run time in say a dictionary, or whether I should be looking to use a database or some other means of tracking them.
From the responses so far I think I can see that there's no right solution, but it depends on the quantity of items and size of the objects.
I've done a couple mobile apps. I'm very leery of not storing everything in a database, due to a possible interruption at any time. If I develop a mobile app, I try to make sure everything is backed up. I only keep information in memory that I absolutely need to run the game and can be discarded without an impact on the player.
In the case of a PC, I am much less concerned about losing data. I would store information in both the db and in data structures. PC players are trained to use save systems. :)
Answer by NGKrush1 · Mar 14, 2012 at 12:23 AM
Hi Fred,
I'm trying to do something very similair to your question, but don't have the coding experience to really get it rolling.
I'm looking for a direction on how to tackle dictionaries giving items stats and attributes. How do I set this up? My idea now:
-create a baseitem class with an ID and default stats. -create a dictionary class with the "database" of the stats for all the items in the game (between 100-200).
as I am making a small point n click-ish game, where (some)items can be picked up and dropped in specific places (containers) I believe I would need a seperate class collecting the location data for each item ID. so:
-create a itemlocation class with the locations of each item in the game.
finally: -a menu class to visualize each of these items in the (for example)OnGUI when you open one of these containers.
Answer by jc_lvngstn · Mar 14, 2012 at 01:40 AM
Looking over this, I have some thoughts that might help. It sounds like this is for a multiplayer environment, so here is how I would handle this.
First, I would have a table (or file, or whatever) that defines my item TYPES and their default values.
Type Name DefaultStr DefaultInt DefaultWis DefaultValue
1 Axe 5 0 0 3
2 Bow 2 3 0 7
3 Biscuit 0 1 2 3
In code (I use C#), I'd have my server read in the data into a dictionary of ItemTypes, by Id.
So, I would have an ItemType class, that stored the type, name, default bonuses, etc. For each item type, I would store its data into a new instance of the itemtype class.
I would then store the itemtypes into a dictionary, with the item type being the key:
Dictionary<int, ItemType> itemTypesByType = new ....
I'm using an int as the key, I don't expect you will have more than 2 billion types of items eh?
For items: ItemBase (or whatever), but I wouldn't derive this from the ItemType. Instead, I would do something like this:
public class ItemBase
{
private ItemType _ItemType;
private int _Id;
public ItemBase(int id, int type)
{
_Id = id;
_ItemType = itemTypesByType[type];
}
}
That way, the item knows its default info...it doesn't have to derive from it. I prefer this sort of thing to a lot of oo layers, personally.
Also, notice I assigned an item id. Your server would assign new ids to each item created. From then on, that unique id is assigned to that unique item in the 'world'.
If you want stuff stored in containers, like a player inventory, a barrel, etc, you will need each item in the world to also have an OwnerId. This would be another int value. It would be the id of the item that "owns" or stores the item. So let's say you have a barrel in the world. Id = 1, owner = 0 (it sits on the ground). You have an apple, id=2. You put it in the barrel. The apple's ownerid would be set to the barrel, or 1. If your player has an id (it should), then you would just assign the item owner id to the player id.
So, each ItemBase will also now need a list of children.
List<int> childItems;
This list is not stored in the database, only in memory. We don't need to store an items children, because we store the parent (ownerid) for each item. When the server "loads" everything, it would need to load all world items into memory, then do another pass to assign children to parents. This will probably take all of 5 milliseconds.
When the server/game/whatever starts, it would assign all items belonging to each parent as a child.
You mentioned concern about performance. This may not be an issue, because...
When the server tells the client to create an apple on the ground, the client creates an apple gameobject. It addsd the gameobject to a dictionary (I am a big fan of dictionaries), which tracks gameobject by item id.
Dictionary<int, GameObject> gameObjectsByItemId;
Great, now for any item, I can immediately retrieve its gameobject. When the player picks up the apple, the server assigns the player as the owner. The client removes the apple from the VISIBLE game world (since it is in a container now). The server also adds the apple id (2) to the player's list of child items. A very quick operation.
Also, track gameobjects in reverse:
Dictionary<GameObject, int> ItemIdsByGameObject;
What does this do? If the player selects any gameobject we created (an apple, a barrel, whatever), we can immediately get the item id. So player clicks on a gameobject. We get the item id this way. Assume the gameObject variable holds the targetted gameobject, which we found via raycast.
int itemID = ItemIdsByGameObject(gameObject);
Now, the client asks the server to change the item's ownership, while it hides it from view.
When you want the game to display the model/gameobject for a particular item, it's easy: Define a list (dictionary if you want haha) where you have a prefab reference, with the item TYPE being the key.
Dictionary<int, GameObject> PrefabsByItemType;
You would do this to add the apple when the client initializes:
PrefabsByItemType.Add(appleItemType, applePrefab);
Where appleitemtype is the type value in the first table for an apple, and the applePrefab is the reference to the apple prefab in Unity. You could do this with the inspector, or just in code.
So, when the server says "Draw an apple", you know that the apple type is X, and you can just do this:
Instantiate(PrefabsByItemType[X], position, blah blah).
I've read up on dictionaries a lot...and they are fast. Not as fast as direct array access, but arrays are not as dynamic to use either. And...this stuff is happening in less than milliseconds. Unless you are picking and dumping BOATLOADS of stuff, a LOT...it may never be an issue. Also...space...is it that big a deal? Let's say you have 10000 different types of items in your game. If each item type takes up...heck, let's say 100 bytes. That's, what...1 meg of memory. On a desktop...your pc won't even care where it went. Granted, more memory is used for the reference to the variables, but still. Unless you are creating a mobile app, memory for your internal item tracking probably isn't a big deal.
Anyway...not sure if I answered your questions...any of them :) Take it for what it is worth. What you end up having are two tables: 1 for each type of item, and its default values, name, etc 1 for each item you create in the game. Each item knows its item type and owner. You can also store its position, rotation, etc.
When the client connects, the server will need to send it the list of all item types.
Use dictionaries to track things like gameobjects by their item id, create an item of a particular type from a specific prefab, and so forth. I hope this helps someone. Heck, it may even be correct :)
Only just seen this - thanks. Really informative and helpful. Not been on the forums for ages.
I know this is an old question, but just wanted to clarify your great answer jc_lvngstn.
At the end you say
"Use dictionaries to track things like gameobjects by their item id, create an item of a particular type from a specific prefab, and so forth."
Do you mean to create a prefab for every possilble Item type and then when you initially load a list of itemTypes, you use these as the basis for creating different variations of that item?
For example if you had an ItemType Sword, and you had 10 different types of swords would you represent these as just 10 different instances of the sword type in the gameworld (using itemBase and changing its stats accordingly), or would you specifically make 10 different itemTypes for each sword (ie. itemType:longsword,broadsword,shortsword etc.) which also means 10 different prefabs for each sword type.
Are using lots of different prefabs an issue?
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How can I delete an item from this inventory system? 1 Answer
Inventory problems (C#) [edited to be more clear] 1 Answer
Adding Item to an Inventory. 1 Answer