Much of this was already discussed in this other thread but now that the release is “official”, I thought it deserved its own topic for further evolution.
The full version release can be found here:
Along with this comes new releases of Lemur, SiO2, and SimEthereal and all of those have been pushed to jcenter. So it’s now possible to build the source for the example with building other dependencies first.
Reminder screen shots…
Four clients logged in:
For those who want to see just the changes that were necessary to integrate SimEthereal on top of the basic networking example:
I kept detailed notes as I did those changes so I can factor those into proper documentation… hopefully sooner rather than later.
Next steps for this app might be to add a chat bar. But I really want to fork it into a “basic + ES” version so I can start adding other objects than the spaceships, properly support colored ships, etc… These things are too hard to add to this non-ES version.
Also, I want to add some stats collection inside of SimEthereal and add debug displays of this information on the “game host”. Chat and stats I may add to this basic example (though it starts to become less basic then… so I may still fork an interim version.)
Pasting this from another thread because it’s probably even more relevant here:
I use UDP to send the deltas from a known good baseline that the client and server have agreed upon. The client acknowledges the messages that it gets (and keeps acknowledging). When the server receives one of these ack messages, it moves the baseline up to where the client’s messages say it should be and then starts sending a double-ack for those messages. That way the client knows that the message receive is based on a new baseline.
This is different than a true reliable protocol because stale data is still discarded and overwritten. A reliable protocol (like TCP) will deliver everything even when it’s crusty and old and no longer relevant.
The protocol also means that for objects not moving, that object’s individual state update is only 28 bits or something. (zone ID + network ID plus a few bits indicating that the data has not changed.)
Rotation and position are packed into bit streams…with the resolution of position greatly reduced since all positions are relative to the zone. For example, my SimEtheral example packs a Vector3f
position into three 16 bit values. Quaternions are packed into 4 12 bit values. So 48 bits each for position and rotation plus another bit each for ‘no change’ or not. So even a normal object update takes only about 124 bits… ie: 16 bytes with four bits to spare. Since everything is packed into a bit stream (which by the way are completely usable outside of SimEthereal) those four bits add up also. After 31 objects, I can fit a 32nd one in for free, basically.
But that’s why I can fit so many object updates in a small UDP packet. I think by default I clamp it at ~1400 to try and stay under a typical MTU size (so the UDP packets are less likely to be split in the network stack). In theory that lets me send 90 object updates in a 1500 byte message… there may be some additional frame protocol stuff that I’m forgetting.
If they can fit in the message, then I try to pack three frames at a time (this actually depends on how you call the network code but that’s the default). But I will defer a frame’s state to a new message or even split a frame to try to keep it under the current estimated MTU.
Edit: bitstream classes if anyone is curious:
Ability to pack Vector3f/Quaternions/etc. easily into bitstreams is part of my SimMath package:
Create a simple an generic Chat service that can be plugged into any SpiderMonkey-based application. It provides basic chat services but could easily be expanded with different methods or whatever since it used the RMI services.
Here is the commit that added just the service so you can see the classes. I put them in their own package to make it easier to extract them later if we want:
To be able to intercept the text the user enters on the new command console, I modified the CommandConsoleState to take a pluggable CommandEntry object:
And finally, this is hooking up the chat service. Plugging it into the networking was pretty much one line each on client and server. The rest of the changes are just hooking up the chat listener to the message display and the console entry to the chat sending.
I want to tweak what the messages look like and do a bit more testing then maybe I’ll setup a public server.
In your textfield - how’d you get the position for the cursor?
I’m currently struggeling with BitmapText having everything declared private - so I can’t access the individual glyphs. I thought maybe observe the quads from the vertex buffer - but that may be missleading since some quads have smaller xadvance than their width. But if everything else fails I will try to read that vertex buffer and use that as a hint to where individual letters are.
// We add an extra space to properly advance (since often
// the space character only has a width of 1 but will advance
// far) then we subtract that space width back.
float x = font.getLineWidth(row + " ");
x -= font.getLineWidth(" ");
Ah, I completely forgot that you could do that with BitmapFont.
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Could not find tools.jar