Muhammad Waqas
Muhammad Waqas

Reputation: 87

How can I synchronize a List like a SyncVar in Unity?

I want to synchronize a List across the network like when using the SyncVar attribute in Unity. Is that possible to do?

When we write a class that extends NetworkBehaviour it allows us to use SyncVar on variables:

[SyncVar(hook = "OnHealthChange")]
public int currentHealth = maxHealth;

In same way is it possible to do something similar with a List? This doesn't work:

[SyncVar(hook = "TimeDiff")]
public List<RoomPlayerInfo> listRoomPlayerInfo = new List<RoomPlayerInfo> ();

I tried that line of code but it showed me the following error in console:

Error 1: UNetWeaver error: SyncVar [System.Collections.Generic.List`1 GameManager::listRoomPlayerInfo] cannot have generic parameters. UnityEngine.Debug:LogError(Object) Unity.UNetWeaver.Log:Error(String) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/Program.cs:20) Unity.UNetWeaver.NetworkBehaviourProcessor:ProcessSyncVars() (at C:/buildslave/unity/build/Extensions/Networking/Weaver/UNetBehaviourProcessor.cs:1838) Unity.UNetWeaver.NetworkBehaviourProcessor:Process() (at C:/buildslave/unity/build/Extensions/Networking/Weaver/UNetBehaviourProcessor.cs:53) Unity.UNetWeaver.Weaver:ProcessNetworkBehaviourType(TypeDefinition) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/UNetWeaver.cs:1064) Unity.UNetWeaver.Weaver:CheckNetworkBehaviour(TypeDefinition) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/UNetWeaver.cs:1549) Unity.UNetWeaver.Weaver:Weave(String, IEnumerable`1, IAssemblyResolver, String, String, String) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/UNetWeaver.cs:1658) Unity.UNetWeaver.Weaver:WeaveAssemblies(IEnumerable`1, IEnumerable`1, IAssemblyResolver, String, String, String) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/UNetWeaver.cs:1748) Unity.UNetWeaver.Program:Process(String, String, String, String[], String[], IAssemblyResolver, Action`1, Action`1) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/Program.cs:34) UnityEditor.Scripting.Serialization.Weaver:WeaveUnetFromEditor(String, String, String, String, Boolean)

Error2: Failure generating network code. UnityEditor.Scripting.Serialization.Weaver:WeaveUnetFromEditor(String, String, String, String, Boolean)

Error3: MissingReferenceException: The object of type 'Object' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object. UnityEditor.Editor.IsEnabled () (at C:/buildslave/unity/build/Editor/Mono/Inspector/Editor.cs:589) UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1151) UnityEditor.InspectorWindow.DrawEditors (UnityEditor.Editor[] editors) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1028) UnityEditor.InspectorWindow.OnGUI () (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:352) System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)

Upvotes: 1

Views: 8105

Answers (1)

Serlite
Serlite

Reputation: 12258

Looking at the documentation for SyncVar, this line seems quite relevant:

Only simple values can be marked as [SyncVars]. The type of the SyncVar variable cannot be from an external DLL or assembly.

As such, a generic List can't be marked as a SyncVar, because it's not contained within the Unity assembly. However, there are other options - Unity includes several collection types that can be used for synchronizing across the network.

In your case, it sounds like you need the SyncListStruct collection, which allows you to synchronize a list of user-defined struct instances. (Of course, that means RoomPlayerInfo needs to be a struct, which may entail a bit of code rewrite.)

For example, your code might look like:

// Define a new class which inherits from the generic SyncListStruct
public class RoomPlayerInfoList : SyncListStruct<RoomPlayerInfo> {}

// [...]

public class PlayerNetworkingScript : NetworkBehaviour
{
    public RoomPlayerInfoList listRoomPlayerInfo = new RoomPlayerInfoList();

    // If necessary, define and attach a callback to the collection for when it changes
    private void RoomPlayerInfoListChanged(Operation op, int itemIndex) {
    }

    void Start() {
        listRoomPlayerInfo.Callback = RoomPlayerInfoListChanged;
    }
}

Hope this helps! Let me know if you have any questions.

Upvotes: 2

Related Questions