Syncing a List<Class> attached to a GameObject.

Hey,

I am trying to get the contents of an ItemContainer to be synced with all the clients in the game. I have a List<Item> and whenever a specific container/ GameObject [it has a photonView attached] is open, the contents of the container is showed to the player (these are GUI elements).

Basically what I do now is, whenever an item is looted from the box, it is added to the players inventory and then a RPC is called to remove it from all the other player's boxes. This works fine if all the players are in the server at the same time.

But, if another player joins, he does not receive these updates (and the items will still be there, because right now they are created on start, also tried with OnPhotonInstantiate, but same result), since the RPCs have not been called on his machine.

How do I sync this list, which a private list in a script attached to a prefab gameobject with all the clients? (preferably it syncs on every time the item list changes, but it is also possible to sync it only for the new player, and then still use the RPCs to change the state).

Suggestions are appreciated, thanks !
Maarten

Comments

  • As it's a temporary thing, I'd send the list again when someone joins. I don't have the code open but you should be able to send a RPC to only one player (the new one).
    It doesn't make a lot of sense to put this in the cache, I'd say but that would be another option. Using a buffered RPC would be ok but only if you cleared the list from time to time.
  • Thanks, I'm calling an RPC right now, which should handle the thing correctly. Just one problem, I get the error that Unity can not serialize the data (I am sending a List<certain class> as the RPC parameters). After looking it up, I found out I need to add a custom serializetype to CustomTypes.cs, so that's what I am doing:
    private static byte&#91;&#93; SerializeString(object customobject)
    {
    	string str = (string)customobject;
    	byte&#91;&#93; bytes = new byte&#91;str.Length * sizeof(char)&#93;;
       	System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        	return bytes;
    }
    	
    private static byte&#91;&#93; DeserializeString(byte&#91;&#93; bytes)
    {
    	char&#91;&#93; chars = new char&#91;bytes.Length / sizeof(char)&#93;;
        	System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    	return new string(chars);
    }
    

    This gives me an error in the Deserialize function, and it tells me: Cannot implicitly convert byte[] to string. This is really hard for me, since I am new to C# scripting. Is it possible at all to (De)serialize a string <-> byte[] over the network?
  • Maybe it's simply this: List<T> is not supported as serializable data.
    Make it an array of your custom data and it should be fine.

    See "Operation Content - Serializable Types":
    http://doc.exitgames.com/photon-server/ ... t-Protocol
    (we added custom types meanwhile, so this is not fully up to date)
  • MaarX
    edited August 2012
    I'm really lost. I've been trying on to making my class serializable, couldn't do it.

    When I try to make my list an array, it doesn't work either.
  • Basically when a client connects, I call the following code:
    void Start(){
    // We tell the MasterClient that a new client is in the server
    photonView.RPC ("SyncLootListInit", PhotonTargets.MasterClient);}
    

    Then the masterclient will receive this:
    &#91;RPC&#93;
    void SyncLootListInit(){
    // We create a new list (and we use the string class), for the sake of debugging
    List&lt;string&gt; l = new List&lt;string&gt;();
    l.Add("One");
    // We then send our list, converted to an array to All the clients
    photonView.RPC("SyncLootList", PhotonTargets.All, l.ToArray());
    

    So far, so good. Now we are going to receive the parameter "l.ToArray()" in our "SyncLootList" function:
    &#91;RPC&#93;
    void SyncLootList (string&#91;&#93; inc){
    List&lt;string&gt; l0 = new List&lt;string&gt;(inc);
    List&lt;string&gt; l2 = inc.ToList(); // We use System.Linq to make this conversion
    }
    

    I'd say it works.. However it does not, the error is in the void SyncLootList parameters (the last function):

    "PhotonView with ID xxxx has no method "SyncLootList" that takes 1 argument(s): String"

    Shouldn't this be easy?
  • I've got it working. Basically, I have created a database, where every item in the list gets it's unique ID. When I send the list over the internet, I send an int[] (string[] didn't work). It works fine right now ! :)

    Edit: I was very silly, I did not define the length of the string array, I think. But sending integers over the network is way faster, I suppose!

    Thanks for the support.
  • I can reproduce the problem with the string[] and know it's cause: A RPC has a object[] parameter. Due to this, we don't know if you want to pass a string[] or several string parameters (which just happen to look like an array).

    We will take a look when we can. Good that you have a workaround.
    Another would be to call the RPC with a new object[] containing your string[] like so:
    photonView.RPC("ChatArray", PhotonTargets.Others, new object&#91;&#93; {new string&#91;&#93; { "one", "two" }});
    

    You are right, the integers are usually far less bytes to send, so if you don't get in trouble with that, keep them.