Search Unity

How are you handling character inventory?

Discussion in 'NetCode for ECS' started by Blargenflargle, Jun 20, 2022.

  1. Blargenflargle

    Blargenflargle

    Joined:
    Feb 24, 2019
    Posts:
    92
    Title.
    Currently I have a type called ItemSlot that looks like this:

    Code (CSharp):
    1. [GhostComponent]
    2. ItemSlot : DynamicBuffer
    3. {
    4.     [GhostField]
    5.     public int slot;
    6.     [GhostField]
    7.     public Entity item;
    8. }
    This is more or less the basis of my inventory system. Items can be any arbitrary data since they're attached to an entity. All items are ghost entities whose components are synced only to the items owner. If you didn't know, Entity fields can be synced over in the manner shown above if the Entity fields value is a ghost. However inventory systems are a lot more then the item slots. I'm running into some trouble imagining how to structure the other features. Moving an item between two slots seems more complicated then it should be. Moving an item safely between player inventories (for trading for example) seems very complicated. This seems like something that is much easier to do in the GO world and I am considering forgoing ECS almost entirely for my Inventory system.

    Do I lack imagination? It seems as though this is a DOTS-unfriendly problem. Not impossible but not worth the trouble. After all, even if I had 1000 CCUs what are the odds more then 10 players would be manipulating their inventory at any given frame? It's not like transforms for monsters where, depending on the AI, I could expect 900 of 1000 transforms to actually be changing at any given frame.

    As a side note, there are probably 20 high quality GameObject inventory solutions on the asset store. I'd shell out $20-50 for a Netcode enabled fully featured inventory solution.
     
  2. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    992
    Is the item entity unique per item ? Meaning it's reused in multiple inventories.

    It seems you designed the inventory from the player perspective. player has a list of items.
    What if you designed it the other way around one item has one owner ? In that case the transfer to a oner player is just changing the item owner so the transaction is atomic/single operation.

    Does your items have a physical existence in the world ? Are they rendered on the ground ? If not do they really have to be entities ?

    The top action I can think of for an inventory are not too frequent, do you really need it to use dots ? Maybe the most performance intensive operation is sorting the inventory which doesn't happen often.

    What type of inventory are your planning ? Simple 1 item one slot WoW style or slot are item dependent Diablo style ? Can you stack items ?
    For me inventory management is not something that is well suited for a dots development style. Which does not mean that items themselves can't be done with dots in mind to play nice with the other game system which may be relevant to make using dots like a combat system or event the rendered equipment on the character.
     
  3. Blargenflargle

    Blargenflargle

    Joined:
    Feb 24, 2019
    Posts:
    92
    I really like the idea of an item as having an owner, or a "inventorySlot" component which defines an entity for the inventory it's in and an int for the slot. This neatly solves the problem of item duplication, but it seems to come with other problems. Now items are strictly linked to 1 slot in 1 inventory, but it becomes much harder to make sure there is only 1 item per slot. I suppose you could run some kind of hybrid system, where the item has a component on it defining it's owner and inventory slot, and then also "registers" itself to an inventory slot buffer on the entity when you try to move it.

    I considered items as simple structs instead of entities but that seems more cumbersome. There are things entities do besides being performant that I want for my items. The most important thing is items as ghost entities. This has a lot of implications for ease of use. For instance, displaying tooltips to the client is very simple. If items were structs, sending the item data to the player would be very complicated and need a lot of different rpcs to build the arrays of data that represent the item. With ghosts I simply tag the components as ghosts that only send data to their owner and make the owner of the entity the player that owns the item. I can make a component that defines which model to load for the armor, attach it to the entity, make it send to everyone, and the player model will be automatically visually updated.

    In the end, items as structs would have me defining and handling upwards of 10-20 rpcs just for building items, changing items, moving items, etc. It's not even like I could avoid ecs while doing this; sending rpcs requires creating an entity. It is possible that some hybrid approach is more usable, such as handling items as ghost entities but inventories as structs with arrays in them.

    I am going for a WoW style where each item takes up 1 slot. I think if I were doing a Diablo style inventory I would almost certainly take a hybrid approach.
     
  4. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    992
    Regarding the tooltip, it is of no use to the server side. Why take bandwidth to synchronize that data ?

    I have not deep dive in net code yet but for me the way to think is always to split your data in two groups. Simulation data which is use by the server (and the client for prediction/interpolation) and the presentation fat which is only usefully for the client.

    This even applies to entities. For instance my ability system make use of scriptable object to define abilities. Part of that scriptable object is converted to entities like how much damage the effect does, how long does it take to cast and so on. But the things like the name or description of the ability and even the icon representing the ability stay in the scriptable object. That scriptable object is used for display on the client unsung the UI toolkit. I even have translation and can update it through addressables.

    Same thing could be said about item inventory.
    Yes the server need to know who has which object in which slots. But does it really make use of the tooltip content ? The only use I could see is sorting by name but even that I feel is not critical and can be left to the client authority removing the need for the server to know about the name.

    It come down again to what is performance critical or has to play with performance critical things.

    The inventory has not critical performance implications in my opinion. Items on the other hand could have if they can be equiped or consumed and that impact the combat system calculations. (Of course it depends on how you implement things).

    Having the item/owner relationship in one direction or the other is up to you. Each have their benefits and drawbacks. Having a bidirectional relationship (what you call hybrid) only compound the drawbacks of both in my opinion.

    You'll also have to think of the implications on persisting that data.