Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved The best way to send reference through NetworkVariable

Discussion in 'Multiplayer' started by prusavo, Jun 21, 2023.

  1. prusavo

    prusavo

    Joined:
    Jun 4, 2023
    Posts:
    1
    Hello!
    I have a question about my inventory system.
    So far everything is working great but I am just not very sure about my latest decision. It feels a little bit off.

    Each player has his own inventory which is shared across the network. So players can trade etc.
    I created a struct called Inventory and it holds a list of items in inventory.

    Code (CSharp):
    1. public struct Inventory {
    2.    private int capacity;
    3.    private List<InventoryItem> items;
    4. }
    5.  
    6. private struct InventoryItem {
    7.    private int itemId;
    8.    private int count;
    9.    private int position;
    10. }
    The thing that I don't feel very good about is the itemId in InventoryItem.
    If there was no multiplayer I would simple use "private Item item" instead.

    Basically I have ScriptableObject Item and I've made many Items as prefabs where I must specify the id specifically for each item I've created. The example looks like this:
    upload_2023-6-21_23-28-40.png

    Later when I want to access data from inventory I must use some kind of MapperService that has Dictionary<int, Item> which return Item based on id provided.

    Is this a good approach or should I change something?
    It would be very nice for me if I could avoid manually writing id for each item. So no mistakes can happen just by some stupid typo of mine.

    Thank you for your advices.
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    The best way to send a reference over the network is to find a way that does not require sending a reference. You only want to send data, and as little as possible. Thus looking up an item by an integer ID is preferable to (trying to) pack an entire object and send it as a "reference" (which is technically not possible, the reference will be a different object on the other end anyway).

    You could write an editor script or have a ScriptableSingleton<T> in the editor that holds a static currentId value which you retrieve and increment whenever you create a new Item.

    You could also make that totally dynamic: upon entering playmode or making a build, use AssetDatabase to find all assets of type "Item", give each a unique Id (all of them, regardless of whether they already have one assigned), and construct the Dictionary<int, Item> while you go through the items.

    You should not have to rely on a detail like Diamond always having Id 2. It's going to be a "Diamond" so you'll look it up by type instead or in addition, meaning you'll have another Dictionary<Item, int> for the reverse mapping where necessary.
     
    CodeNinja- and firebird721 like this.
  3. firebird721

    firebird721

    Joined:
    Jun 8, 2022
    Posts:
    71
    THAx!

    And if i want missile launcher to have refernce for the gameobject of the playership ? do it clientrpc instead of sending networkvarible(that is not possible anyway...)
     
  4. MrBigly

    MrBigly

    Joined:
    Oct 30, 2017
    Posts:
    208
    I can share what I have done, and yes using a dictionary<id, ref> is fine. (DISCLAIMER: I have written my own netcode, but I think you could use the same ideas with NGO.)

    Every Asset in my game that instantiates will self registers in its Start() to a singleton registry of Asset identifiers, which is simply a Dictionary<ushort, AssetPrefab>. The identifiers have the range [0100..FFFF]. (Player identifiers hold the range [0000..00FF]). They are automatically generated by the code whenevere an Asset is instantiated.

    The identifier value to be assigned to the next Asset resets to 0x0100 at the start of each match prior to the loading of the map itself. The map loading must instantiate any Assets that are part of the map; then the Pawns and their loadout Assets are instantiated later during Pawn spawning. All Clients have the same map and same loadouts, so their identifiers are deterministic at the time of instantiation.

    I would never allow typing in an identifier during development nor during game play. That doesn't make sense. (And at the moment, I don't see the identifier in the inspector, but that is something I have on my TODO list as a read only field.)

    If I want to reference a class of Assets, say a frag grenade, I would use the enum Identifiers.Frag. I cannot compile the code if I misspell the enum item, so I cannot typo a bug into the code.

    As for RPC, I haven't implemented an RPC feature at this time in my netcode, because I haven't really needed one yet. I set a property value and the netcode layer replicates it across the wire as I need it to. (In practice, a property setter can be thought of as an RPC call for my netcode.)

    Hope this helps.


    EDIT 8/26/23: Some updates. I changed the way my pawn spawns with loadouts. Instead of deterministically deriving identifiers for the loadouts, I send a spawn message to all clients well ahead of the spawn action with all loadout types and their identifiers. All Clients then know what to spawn and what identifiers to assign the pawn and the loadouts attached to the spawn. This makes for a flexible spawn mechanism where I can have any number and any types of loadouts upon spawning a pawn. And the pawn instantiates on the Clients upon receiving their first Pawn state message from the Authority.

    I have implemented a read only field with the Asset identifier in the inspector, it wasn't difficult to do, just had to follow a video, about 30 minutes max implementation.

    I still use property setters as a pseudo RPC call mechanism, warming up to the idea of a natural syntactical RPC method, but not sure how to implement it without doing the NfGO approach, which I am not a fan of. Their approach seems to be assuming too much making a rigid and thus fragile approach.
     
    Last edited: Aug 26, 2023
    CodeNinja- and firebird721 like this.