1

It's probably o noob question, but important to me. Also I think it's an interesting topic.

I'm using C# with new Unity Multiplayer. You can find tutorial here: https://unity3d.com/learn/tutorials/topics/multiplayer-networking - I'm working on exactly that base. I've just succesfuly made my code so that when player joins or hosts, he adds his "players stats" to a static List as an instance of the "PlayerStats" class. It should work this way for every player - whenever someone joins, his instance of his statistics is added to the list.

Now, this list should be one, global, so I thought - it should be synchronized by server. Maybe as some kind of SyncVar, probably SyncList of some type. And here's the problem - is there any way to synchronize a list of class instances?

I've checked Unity Documentation and seems that's a bummer. Or maybe I understand it wrong. SyncList seems to have only basic types like integer, etc, there is also a struct, but... Do I really need to convert class with player stats into a struct for a server-wide synchronization?

Once again what I want to achieve: I need to have one, global list of players into which new joining players would be added and identified. I've already done identifying - while adding new instance, I'm giving that player an ID = PlayerList.Count - 1. ID which is static, but should be local. Probably best if elements of PlayerList could be PlayerStats class instances. So each player (at his own index) loads his data from disk into his instance in PlayerList. I thought it would be convenient that way (not sure how to do it otherwise, though). It works in singe player mode, but in Multiplayer I don't know how to design it properly. Because I need that static list to be server-wide, aware of other players.

And what if I had to synchronize equipment, which are made of classes in my project.

Can you help me somehow with designing that? I'm trying to create a simple multiplayer rpg based on our new Unity Multiplayer tutorial. Now there's a need to identify players and load their data in proper place, data which is already generated by character generator and saved, and which properly loads in single player already. I thought I should use a local singleton instance of a class PlayerStats for player data, and to keep those instances in global server-wide list. My PlayerStats are a component of PlayerStatsObject (empty gameobject in hierarchy that has DontDestroyOnLoad). PlayerStats class, made into singleton instance, contains whole generated character, with his vitals, class, race, equipment lists made of classes, etc.

So basically, I need every player to be added to the list, have his own PlayerStats, and make those PlayerStats easily interactable/modifiable by other players (and AI enemies / Environment, but that's easy, it's single player). Adding PlayerStats as a component to Player prefab seems overkill to me, as those stats will be called by almost everything in game all the time. So that's a ton of GameObject.Find("Player").GetComponent<PlayerStats>();. Seems that would be disastrous design.

trahane
  • 701
  • 6
  • 16
A guy
  • 71
  • 11
  • writing multiplayer is incredibly difficult. it's not something you can "just figure out". you're question is much like asking "so I want to fly a plane!" or "how can I play guitar like Prince?!" – Fattie Sep 20 '16 at 05:23
  • That's good to get clarified though! Thanks. I'm trying to learn and considering different approaches, but figured out I should put that into practice and just test by myself. Starting with probably the simplest ways, using Unity's HLAPI. Also, I've read your posts about singletons and seems I won't be using them just to make "shortcuts". It may mess up mulitplayer unexpecedly, among many other things, and using just one line of code with FindObjectOfType in many scripts shouldn't impact performance at all... After all, if we have only 1 object of some type, what is the problem finding it? – A guy Sep 20 '16 at 14:36

1 Answers1

4

How about generating UUIDs for the users on the server. These will provide a solid base to exchange information about the users between clients.

Next step would be the actually exchange of data. You'll need a way to extrapolate the data from the object. Sending complete instances of objects over the network would ask quite the bandwidth and is not necessary seeing the other clients know the structure of the class itself. So all you want is the information to construct an exact equal of an object on machine B as exists on machine A.

ToString is kind of a standard used for transforming complex data into a string. Most often used for displaying or storing such data. You can pick the objects fields to synchronize and combine them into a string. So by adding a ToString method to your PlayerStats class you would be able to:

  1. loop (more on this later) over your PlayerStats instances
  2. convert them to strings
  3. concatenate those strings into one single string, separated with a delimiter (e.g. ##)
  4. send it off to clients/server
  5. clients can split the string back to multiple strings
  6. by matching the UUIDs, the client can determine which players already exist and which need to be newly created.

About the looping, my suggestion would be to use the Observer Pattern. In short you'll have a single monitoring instance per type of object, PlayerStats in this case. Every instance of PlayerStats will register itself at the observer on instantiating OR you can create a Factory who does the instantiating and registering for you. On destruction of a PlayerStats instance you'll need to "unsubcribe" from the monitoring instance again (you don't want ghost references haunting your application).

Your idea about using the PlayerStats as component isn't that much of a strange idea. Yet you're right that finding the component over and over again is a waste of resources. Using the Observer Pattern you can keep track of all PlayerStats instances and easily loop over them.

Hopefully this will get you started in the right direction!

Maarten Bicknese
  • 1,498
  • 1
  • 14
  • 27
  • Great, thanks Marteen! That has shown me some flaws in my ideas. I've already used delimiters to slice text into parts for translation (localization) and back again, so I should be able to do that. I understand that it's just to make data shorter (less transfer). Creating UUID, no idea about how yet, but I'll search how to implement. Now I just need each player to have his own PlayerStats, and you say Observer Pattern might help. Factory is somewhat known to me already. I'm going to read about and practice Observer Pattern then, thanks again! – A guy Sep 19 '16 at 20:51
  • Another person showed me a really simple sollution in comparison, I guess, so maybe I should try his way first: http://forum.unity3d.com/threads/how-to-synchronize-a-list-of-player-stats-instances.431924/ I think it's hard to grasp Observer Pattern with my current level of knowledge, I would need to have an example on similar code to mine to grasp it. Now I just have to find out if I can make local static variables synchronized, while still refering to local player only. – A guy Sep 19 '16 at 21:45