2
\$\begingroup\$

What I want to achieve is synchronize the state of a list of objects between two applications using sockets. All my attempts, but failed.

One of my methods was to send each object each update to the client, which is clearly a bandwidth problem and I'm very limited to the amount of objects I can send since I send all the objects in one UDP packet.

It's clear to me that I need to send all the game objects to the client and then only update the fields as they change on the server side. The reason why I didn't try this approach from the beginning is because I identified a few barriers. My objects gets serialized and would like to synchronize every property.

  1. How do I detect the change of a property without implementing a change event externally and for all the objects that inherited my main entity class.

  2. Alot of the object's properties gets changed every frame so when I apply the changes to the clients representative object it requires alot of processing since I need to find each property which I need to change from the object and assign it the new value.

  3. Each object has components which also needs synchronization. These components are within a list contained in each game object. So I must not only simple synchronize the object's properties, but the properties of each component as well.

  4. A property can change multiple times each frame and I only want to synchronize the last value the property was set to at the end of the frame.

I currently I have no clue on how I can implement this method. My first method works, but it's not the optimal approach according to my understanding. Please any small hint or opinion can contribute to the formulation of the answer.

Thanks in advance.

\$\endgroup\$
1
\$\begingroup\$

For what i can understand, i think you might could consider making a singelton factory that keeps your frame updates and the sends them over networking.

so in theory what you do is that you have a gameobject, lets call it GMOBJ. so when you change your property somewhere in the code, you register this to the frameUpdater.

frameUpdater.RegisterChange( GMOBJ, "scaling", value );

the string would be the identifier for the property, if you put this into a dictionary you could easily do that call several times and it would only store the lasted edited value. The string could also be a hashcode.

on every end of frame then you would do something like.

frameUpdater.SendChangedData();

and that function would then build a byte array of the data changed and send it to the other application.

that application would recive it and then deserialize it back to values and change the corresponding gameobject with propertys.

Something like this is what i think you want.

\$\endgroup\$
  • \$\begingroup\$ How do I update the gameobject's property on the client side? Meaning how do I reference that specific object that needs to be updated in the list of object. \$\endgroup\$ – Rudi Jansen van Vuuren Mar 8 '17 at 20:32
  • \$\begingroup\$ How do I implement the registration dynamically - not having the add RegisterChange to every property I create. This is important since fields and sub lists contains values that also needs to be synchronised. \$\endgroup\$ – Rudi Jansen van Vuuren Mar 8 '17 at 20:38
  • \$\begingroup\$ For referencing the gameobject, i would use an ID to ID the object. thats the simplest and most convinient way in my mind. well, i would make a template class that has a thing called changeValue, wich in terms invokes a funktion calling the register thing and then changes the value. etc: RegValue<int> myValue; myValue.changeValue(10); <--- invokes register \$\endgroup\$ – Tordin Mar 9 '17 at 10:24
1
\$\begingroup\$

You almost certainly do not want to update everything every single frame.

Usually you would split data into Atomic events and Continuous events.

So things like a position change would be a Continuous event and do not need to be handled immediately. For example you could send the new position every X milliseconds and the client could interpolate between the old value and this new one in between.

Other events things will be atomic for example player death as this needs to happen immediately but these events will usually be more sparse and also hopefully lightweight than the continuous ones like movement animation etc.

You basically want the client to guess everything until it gets a server response, at which point it will 'fix' itself to the real values if it got the guessing wrong - this is the cause of 'glitching' and jumping about in multiplayer games, the client guessed and was wrong so the player is 'teleported' to match the real server value. If the latency is low and your prediction is good, you hope this doesn't happen (or little enough it is not noticable). But you usually don't need everything to be completely in sync at all times between client and server, just marry them up every so often and you save the majority of your bandwidth/performance.

\$\endgroup\$
  • \$\begingroup\$ You also say 'A property can change multiple times each frame'.... this doesn't make much sense because if it changes multiple times... you only need to send the last one \$\endgroup\$ – Milney Mar 8 '17 at 14:10
1
\$\begingroup\$

I wrote an answer to a previous question about networking a multiplayer game here: How can I minimise data sent through a network in a modern FPS?.

To summarize - we started with a system that read every single replicated field on every object and sent it to the client. This was slow, but once we had that working we knew we had a solid baseline for optimizations.

Our next step was to keep track of every object that appeared to change - we essentially put a notification in each field's setter that marks the entire game object as dirty, and puts it in the head of a list of 'dirty objects this frame'. Only those objects would then have their replicated fields sent. This was a significant improvement.

Next we actually stored, on the server, a 'shadow copy' of the object's replicated fields. Every time the object was seen as dirty, we would compare each field with the previous shadowed value. If it differed, we would send it and copy the new value into the shadow copy. If it didn't differ we would skip it.

Finally, we compressed some of the data down so that we wouldn't send the fields as a UInt32, say, if the value could only ever be between 0 and 7.

I hope that gives you some ideas.

\$\endgroup\$
  • \$\begingroup\$ How do you compare objects to see if they're dirty? I mean, you still need to send the data to be able to test whether or not the they're differentiating. Or do you test certain properties such as location, and if they don't match - update..? \$\endgroup\$ – Rudi Jansen van Vuuren Jul 12 '17 at 10:39
  • \$\begingroup\$ @RudiJansenvanVuuren I test on the server before sending it, not on the client. \$\endgroup\$ – Steven Jul 12 '17 at 14:26
  • \$\begingroup\$ I've currently put this project aside, but I've took a similar approach. I was able to update about 150 active/dirty entities before bandwidth became a problem. I've also implimited ghosting/prediction to remove any stuttering effects that may occur. Can you maybe tell me how many entities you can synchronize at once and what's your average data usage? \$\endgroup\$ – Rudi Jansen van Vuuren Jul 12 '17 at 16:19
  • \$\begingroup\$ We did 8KB/S for 512+ entities. \$\endgroup\$ – Steven Jul 12 '17 at 23:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.