Unity 3D Multiplayer

Hello everyone, I have a unique issue that I ran into working with the Unity UNET which I cannot seem to find a solution online.

So it is kind of a multiplayer survival game and I can't get the inventories to sync over the network. The inventory contains a list of items which is a "Item" class and unity doesn't seem to have an easy way to sync a list. [SyncVar] only works for simple variables.

Any help would be appreciated.

Comments

  • edited
    Thanked by 1Zaphire
  • [Command] to the server then [Rpc] to all the clients
    Thanked by 1Zaphire
  • Blackson said:
    [Command] to the server then [Rpc] to all the clients
    I cannot send custom classes with Command and RPC.

    @Elyaradine I have had a look at SyncLists but I had difficulty with it. Maybe I used it incorrectly but I will have another try at it

  • @Zaphire, you can use the SyncListStruct.

    Theres an example of it here: http://docs.unity3d.com/Manual/UNetStateSync.html

    You can create a function in you item class to return a struct of the values you want to send.
    Thanked by 1Zaphire
  • Well I have gotten further but I have ran into another issue.

    I have made an inventory class that can be any of the following.
    public enum InventoryType { Toolbelt, Backpack, Tools, Fuel, Input, Output, Storage}


    The problem is that I might have 2 inventories attached to the player such as toolbelt and backpack. When I use [ClientRpc] it doesn't care which one of the 2 instances it is called from and it calls the first inventory on that object instead of both.

    If the [ClientRpc] fired on all the inventories then I could have checked if it was the correct type but now it keeps calling the Backpack inventory when I try add something to the Toolbelt inventory.
  • I have finally found a way to get it to work. Using the way I did in the past or with synclists didn't really matter as long as the inventories on the server is correct. The way to do it with multiple inventories on a single object was by sending the inventorytype to the [Command] and then choosing the correct inventory on the server's side.

    Problem was that when there is 5 inventories on a single object just one of those [Command] functions will be called and on the incorrect target that you specified so then the server will just work with the correct inventory.

    Here is the code for those that ever get stuck on the same issue.
    using UnityEngine;
    using UnityEngine.Networking;
    using System.Collections;
    
    public class Inventory : NetworkBehaviour {
    
        public enum InventoryType { Toolbelt, Backpack, Tools, Fuel, Input, Output, Storage }
        public class SyncListItems : SyncListStruct<Item> {}
        public SyncListItems items = new SyncListItems();
        public int slotAmount = 6;
    
        public InventoryType inventoryType = InventoryType.Storage;
    
        protected virtual void Start()
        {
            if (isLocalPlayer)
            {
                CmdInitializeInventory(inventoryType);
            }
        }
    
        public override void OnStartClient()
        {
            items.Callback = ItemChanged;
        }
    
        protected virtual void ItemChanged(SyncList<Item>.Operation op, int itemIndex)
        {
            Debug.Log("Item changed: " + op + " , " + itemIndex + ", " + items[itemIndex].amount);
        }
    
        public virtual void AddItem(int itemId, string name)
        {
            CmdAddItem(itemId, name,inventoryType);
        }
    
        [Command]
        protected virtual void CmdAddItem(int itemId, string name, InventoryType invType)
        {
            Inventory tmpInv = GetInventoryOfType(invType);
            bool added = false;
            for (int i = 0; i < tmpInv.items.Count; i++)
            {
                if (tmpInv.items[i].id == itemId)
                {
                    Item tmpItem = tmpInv.items[i];
                    tmpItem.amount++;
                    tmpInv.items[i] = tmpItem;
                    added = true;
                }
            }
    
            if (!added)
            {
                tmpInv.items.Add(new Item(itemId, name, 1));
            }
        }
    
        [Command]
        protected virtual void CmdInitializeInventory(InventoryType invType)
        {
            Inventory tmpInv = GetInventoryOfType(invType);
            for (int i = 0; i < tmpInv.slotAmount; i++)
            {
                tmpInv.items.Add(new Item(i, "test" + i, 1));
            }
        }
    
        Inventory GetInventoryOfType(InventoryType type)
        {
            foreach (Inventory inv in gameObject.GetComponents<Inventory>())
            {
                if (inv.inventoryType == type)
                {
                    return inv;
                }
            }
            return null;
        }
    }
    
    public struct Item
    {
        public int id;
        public string name;
        public int amount;
    
        public Item(int id, string name, int amount)
        {
            this.id = id;
            this.name = name;
            this.amount = amount;
        }
    }
Sign In or Register to comment.