Finally getting around to writing some documentation… because that’s how I roll on a Friday night.
Still some blanks in there but the meatier parts are filled in. I’m really looking forward to seeing what @zissis has to say because he struggled without any documentation at all. Would this have helped you before? Did it teach you anything new? Did I miss something important?
@pspeed good start to documentation! Yes this would have helped me get going quicker. But I do appreciate that you did not have documentation back them because it forced me to read all the code and understand the library inside out. What I suggest is people read the documentation then read the code. Once you know the code inside out you can start doing some more advanced stuff like I do … for example, multiple channels for priority messaging and different frame rates for different entities etc…
I forget the details but can you remind me how you dealt with the multiple grids? Did you simply register multiple EtherealHosts on different channels?
Also, because I’m messing with the update loop timings at the moment… can you remind me what physics update rates you are using and what your state collection interval is if you hacked that? (The state collection interval was previously not configurable but I though I remembered you hacking around that or something.)
I’m trying to expose all of the things you had to hack around (within reason) but I’m also trying to make sure my own test isn’t unrealistic if I decide to lower the physics update rate to make CPUs on windows happier (which is a much longer story).
I ended up with a solution that did not require a hack of the network layer for multi channel and difrent tick rates per channel. In my space game, I have seperate server instances each with it’s own EtherealHost that has unique object state protocols, zone grids and zone radiuses. They are the following:
Sector … zone grid of 10000,10000,10000… radius 1,1,1 … this is the sector view that encompasses one solar system … planet and astroid entities are transmitted an 10 tricks per second because they move very slowly anyways.
Ships … zone grid of 100,100,100 … radius 1,1,1 … encompasses all ship entities with a "fog of war stretching out 100 units in all directions. Largest ship entity is 10 units in side … allows for a decent amount of ships in a small area. Tick rate is at 20 ticks per second … based on ship velocity I found 20 ticks per second to be more than adequate.
Weapons/explosions … zone grid of 100,100,100 radius 1,1,1 encompasses all weapons and explosions with a fog of war stretching out 100 units in each direction. The tick rate is 60 ticks per second because weapons cam move very quickly and only last about a second or two anyways. This channel is on TCP/IP instead of UDP because I want to ensure that an explosion only gets transmitted ONCE and I need to ensure it always gets recieved. Interestingly, your network layer works just as fast on TCP/IP as well … go figure lol
Camera … This channel never sends anything … it’s sole purpose is to update the camera position be receiving messages from the client and updating all the other channels. I achieve this by registering a user GUID send by the client when it connects to each channel. This way the camera position is always synched on every channel.
Command processing … This channel reads all the client commands and processes them. Keeping commands on a separate channel ensures minimal latency.
Now for the update loop … Instead of hacking the state collection interval as I did originally, I wanted to hack as little as possible so instead, I have a counter for each channel that I check against a pre-configured tick rate. I can then keep track of which channels should be updated in the cycle. I then iterate over all the entities and send an updateEntity if that entity’s channel is ready for a broadcast. All channels run off of the same time value of course so that I can properly de-multiplex at the client.
So in essence, I am using channel multiplexing on different ports so that … for example, congestion on ship movement doesn’t effect weapon movement … etc … By using the same time value for all channels and the same listener on the client, I can properly de-multiplex at the client and everything is properly time synced.
I know this was a long answer to a straight forward question but I hope it helps.
P.S. all the other hacks where due to the buggy split code … there was one other hack which prevented a freeze on the processing of the incoming frame reference packets but I will have to look into that.
You may or may not be interested to note that in the latest SimEthereal code, you can set the state collection interval… and even the time it uses to sleep during its idle periods. Though that last one is only relevant to a very narrow set of use-cases. Anyway, whether you can get away with slower rates would still depend on how fast you are pumping the data so the fact that you are managing that carefully may make the other not matter.
What tick rate does your physics run at? Or is that what you were getting at with “ships at 20 FPS, weapons at 60 FPS, etc.” You have different physics rates or that’s just the rate you update the ZoneManager?
The reason I ask is that the SimEthereal example’s physics loop is running at 60 FPS. This is good for a test but kind of overkill for the kind of sim it is… I could probably get away with 30 FPS just fine. And it’s only significant because my server is running on a Windows machine where the Thread.sleep(1) versus Thread.sleep(0) is significant to the timing of the game loop. ie: Thread.sleep(1) and at 60 FPS, I drop a frame or two (~57 FPS achieved) but at Thread.sleep(0) there is a constant CPU usage which seems unnecessary for this game.
I may just turn it into a command line setting. I know a lot of games work fine with 30 FPS physics but 60 FPS definitely tests some stuff.
My physics engine is set up at 60 ticks. Planets / asteroids are kinetics on group 1 and collide with group 2 … ships are dynamic on group 2 and colide with group 1 and 2 … weapons are ghost controls on group 3 and only collide with group 2. I needed to keep it at 60 ticks because some weapons are very fast and I don’t want to miss the collisions. Because I basically have monster commercial servers it’s not an issue on the cpu usage.
If these servers are not Windows then it’s not an issue anyway… and you could get away with sleep(1) just fine. (which by the say is what the state collector has always defaulted to so no worries there)