I’m trying to network a variable which is a class “Player” for an online quiz game the class looks like this:
[System.Serializable]
public class Player
{
public string name;
public int scoreToAdd;
public int scoreTotal;
public List<int> indexesOfGuesses;
public Commenter playerChatConnection;
public PlayerType playerType;
public Player()
{
name = "";
scoreTotal = 0;
scoreToAdd = 0;
playerChatConnection = null;
indexesOfGuesses = new List<int>();
}
}
public enum PlayerType {twitchPlayer, guestPlayer};
Commenter is just a string string and a number I use to also hook this up to a twitch chat (this part actually works and was surprisingly easy lol)
I am declaring the networked variable like this:
public NetworkVariable<Player> quizPlayer = new NetworkVariable<Player>();
and then assigning it like this:
[ServerRpc]
public void AssignInitialValuesServerRpc(byte[] playerByte)
{
string playerString = Encoding.ASCII.GetString(playerByte);
var player = JsonUtility.FromJson<Player>(playerString);
quizPlayer.Value = player;
}
However, The error message didn’t stop when I stopped calling the server Rpc and just had a network variable all on it’s own and only stopped when even the declaration of the networked variable was removed. What am I doing wrong and can you even network custom classes?
I’m very sorry, I can’t remember the specific message I was getting but this mostly worked, I also had to change a few other things in the class, like I to change the list indexesOfGuesses, to an array. Commenter had to be converted to a string and I’m going to use a dictionary of key: string, value: commenter or find something less spegatti. Thank you for the quick response though
For the unlucky student that finds this a year down the line here’s what I ended up doing:
I made this new class which consolidates my other classes together and has not failed me yet in what I’m trying to do:
[System.Serializable]
public class NetPlayer : INetworkSerializable
{
public string name;
public int scoreToAdd;
public int scoreTotal;
public int[] indexesOfGuesses;
public string playerChatConnectionTwitchName;
public int[] ghostPartsIndexs;
public PlayerType playerType;
public NetPlayer()
{
name = "";
scoreTotal = 0;
scoreToAdd = 0;
playerChatConnectionTwitchName = null;
indexesOfGuesses = new int[8];
ghostPartsIndexs = new int[4];
playerType = PlayerType.guestPlayer;
}
public void NetworkSerialize(NetworkSerializer serializer)
{
serializer.Serialize(ref name);
serializer.Serialize(ref scoreToAdd);
serializer.Serialize(ref scoreTotal);
serializer.Serialize(ref indexesOfGuesses);
serializer.Serialize(ref playerChatConnectionTwitchName);
serializer.Serialize(ref playerType);
serializer.Serialize(ref ghostPartsIndexs);
}
}
I make an instance of this class on my networked player script:
public NetworkVariable<NetPlayer> quizPlayer = new NetworkVariable<NetPlayer>(new NetworkVariableSettings
{
WritePermission=NetworkVariablePermission.ServerOnly,ReadPermission=NetworkVariablePermission.Everyone
});
I assign the values of the NetPlayer via ServerRpc
I have them generated on a Manager script called NetworkMailRoom.cs which handles most network management
[ServerRpc]
public void AssignInitialValuesServerRpc(string np)
{
NetPlayer player = JsonUtility.FromJson<NetPlayer>(np);
quizPlayer.Value = player;
// from here, add this net player and client Id to the list and dictionary on the manager object
NetworkMailRoom.instance.AddToNetPlayersDictionaryServerRpc(NetworkManager.Singleton.LocalClientId, quizPlayer.Value);
NetworkMailRoom.instance.AddToNetPlayerListServerRpc(quizPlayer.Value);
}
I make absolutely no claim that this is the most efficient way to do this. To me this code just makes sense but if anyone wants to give critique or other suggestions, I’d greatly appreciate it.
It’s not working for Netcode. You have to implement that method in your NetPlayer:
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
then you’ll get an error: The type ‘NetworkData’ must be valid unmanaged type (simple numeric, ‘bool’, ‘char’, ‘void’, enumeration type or struct type with all fields of unmanaged types at any level of nesting) in order to use it as a type argument for ‘T’ parameter
I think you’ll find you are more likely to get good answers if you ask good questions. A reference to a different post that doesn’t ask a question either is not that.
Managed types are not supported in NetworkVariables. You’d either have to use NetworkList to sync the arrays of the player data or replace the arrays with fixed size unmanaged types such as FixedList128 from the Unity.Collections package.
It would be extremely useful with an example of this working on either the docs or if somebody could make a working example of getting this method to work after the new updates, there is barely any information available for newcomers for this kind of stuff, does anybody know where the golden information for getting this kind of thing to work is ? Having player data in a struct or class, and have it all sync instead of having 50 different networkvariables, thanks
Following this solution, you’ll have to change all classes to a struct, then it should work because struct is unmanaged type.
I didn’t figured out, though, how to store a list of that struct using ‘NetworkList’. The way I solved the problem turned out to be a much simpler one. I just converted the List to a JSON string (using Newtonsoft), then assigned that string to a NetworkVariable. Other players will be able to access that data unserializing it back to the same class.
I’m not sure if this will work with MonoBehaviour exclusive properties, such as Vector2D. In that case, you’ll probably have to store such information in simpler variables like a float array.