Thought maybe folks would be interested in the steps I’m going to have to do to convert the sim-eth-basic SimEthereal example over to use an EntitySystem to manage the game objects. It probably goes without saying that I’ll be using Zay-ES for this. (Though I guess I just said it.)
So far, I’ve forked the sim-eth-basic example into a sim-eth-es example and change the title screen, default ports, etc… The project can be watched here:
…right now (as of this writing) it’s pretty much identical to the regular example except the changes already mentioned.
I’ve also added Zay-ES, the server-side EntityData object, and the networking support. To see how simple that was, you can look at this commit:
With that commit, the example has a fully networked EntitySystem. It’s just up to me to actually do something with it now and start managing the objects. That was pretty simple, right? It’s supposed to be.
Next will be to have the server create the player and ship entities and make sure we can see them on the client. Then I’ll have to start modifying the ModelState to start rendering Entities with the appropriate components. That’s where the real fun begins because then I can finally start adding static objects like planets.
Following that, I’ll convert the ship positioning over to being ES based… then I can add additional moving objects like asteroids or missiles or whatever, really… just in the simulation layer. The sky is the limit at that point.
I added the basic code to create the player entity and to verify that it was working, I quickly implemented a client-side player list pop-up:
Right now it’s not formatting the list box values or anything.
Here is the commit that made these changes:
90% of the code is UI related stuff and the app state.
The most important bits are here in AccountHostedService:
+ // Create the player entity
+ player = ed.createEntity();
+ conn.setAttribute(ATTRIBUTE_PLAYER_ENTITY, player);
+ ed.setComponents(player, new Name(playerName));
+ log.info("Created player entity:" + player + " for:" + playerName);
And where we actually create and update the view of the entities on the client in the PlayerListState:
+ // Grab the latest player entity set
+ this.players = ed.getEntities(Name.class);
That’s it. The rest of the code is just exposing services already available through getters… and as said, the bulk of the lines-of-code added are that PlayerListState setting up the UI, binding to F2, etc…
Adding a CellRenderer to the ListBox to display things more nicely will be pretty trivial but I kind of like seeing the full .toString() for the moment so I will leave it.
The next dev step will have to wait until tomorrow, I think. I believe the next immediate step will be swapping out the manufactured shipId for the player EntityId and the necessary changes from the physics engine on up to facilitate that. Then I believe I get to remove a bunch of ugly code.
You are definitely not spitting in the wind, I am closely following everything related to SimEthereal. You have been a tremendous help to me over the short time I’ve been working with JME. Your forum posts have been extremely helpful. I am just naturally a forum lurker.
Same here. Thanks to the documentation of SimEthereal and the example project, I was successfully able to include it in my own project. Although I do have one quick question if you don’t mind: how does the zone grid work exactly? Let’s say I have a grid size of 2048, does that mean it creates a grid that is 2048 in its max size? Or does it mean that each grid section is of size 2048? If it’s not the latter, how would I go ahead and specify how big sections of the grid are?
Thanks, it really means a lot to know that. Helps with motivation to know that I’m not just spitting in the wind.
I was 10 seconds away from posting and asking for a guide on how to use sim ethereal with zay-es, and then you went and do this the same day, 30 minutes earlier. pure win! :chimpanzee_surprised:
And so, as mentioned offhand in the screen shots thread, I have converted the physics, networking, model view to use Zay-ES instead of the odd combination of spaghetti code that the non-ES version was.
You can see the full diff here:
The update is pretty sizable but here is kind of a highlight overview:
-client and host services modified to deal with EntityId instead of the ‘int’ ID
-SimplePhysics/Body/etc. modified to have an EntityId reference
-server-side BodyPositionPublisher listens to the physics system and adds changes to a BodyPosition component.
-client-side watches for BodyPosition containing entities and uses them to update spatials.
-client-side SharedObjectUpdater makes sure that the BodyPosition components are updated from the SimEthereal messages.
-ModelViewState was gutted to have way simpler code that just creates an EntityContainer and manages Mob objects that keep track of the state of the loaded ship. It’s worth a skim through that part of the diff to see how much it got simplified.
BodyPosition component
This is kind of the heart and soul of how I’ve tricked Zay-ES into working with SimEthereal.
It does no good to have a high-performance networking layer if you are still pushing slow(er) Entity Component updates for position.
BodyPosition is a component with all transient fields. On the server, the BodyPositionPublisher listens to the SimplePhysics engine (just like SimEthereal does) and uses those same object updates to update the BodyPosition component’s internal transition buffer. (If you recall, the transition buffer is what keeps a brief history of the object position.)
On the server, we do this for two reasons. 1) any system on the server that needs the entity position can now get it by looking at this BodyPosition object. 2) by adding the component, even though all of the fields are transient and won’t get sent over the wire, the client will see the BodyPosition component.
So on the client, the ModelViewState can watch for entities with a BodyPosition component. If it sees one then it’s just as likely to be empty… but there’s a trick. All users of BodyPosition will initialize it with the EntityId. This lets it look up the shared transition buffer from a static cache. Normally, each ‘user’ of an entity will get different instances of the component… which is usually good. In this case, we’re being tricky.
Meanwhile, the SharedObjectUpdter is listening for SimEthereal object events. When it receives one, it looks up the BodyPosition for that entity, initializes it if it isn’t already, and applies the SimEthereal update. Because ModelViewState and SharedObjectState both initialized BodyPosition from the internal static cache, the TransitionBuffer is shared… and so ModelViewState will see these updates.
TransifionBuffer is a thread-safe data structure that keeps a time based history of recent object positions so that clients can interpolate based on the current frame time. Since it’s already thread safe (for one writer and many readers) it’s fine to share it between BodyPosition components.
So, really that’s the magic:
BodyPositionPublisher → BodyPosition on the server
SharedObjectUpdater → BodyPosition → ModelViewState on the client.
And now that the infrastructure is setup, any other system that wants the position of mobile objects can simply look at BodyPosition and not worry about how it got populated.
Screenshot Tax
Here is the bonus picture of the ship with partially updated skin running in the new ES-based client:
Notice that the ship labels are missing now. Because we are using an ES, I can now easily split this into a separate system and no longer have to dirty up the ModelViewState with stuff it doesn’t need. Moreover, a separate system can also be easily toggled on/off by the user or expanded with additional HUD elements. (An ES is just so freeing.)
Trying to get sim-eth-es to compile But you haven’t published the jars you are referencing there yet. They are old at least. Am I missing something?
I can download the jars there (older versions), but then how do I gradle install the jar - yes, I’ve scoured how to get jars into local maven repository, but can’t seem to find the answer.
Checkout SimEthereal
cd SimEthereal
gradle install
Checkout sim-eth-es…
cd sim-eth-es
gradle run
The whole point of depending on the newer versions is that it won’t work with the older versions. So grabbing those jars won’t work… or I’d have continued depending on the older versions.
Turns out that I hadn’t completely converted the SimplePhysics over to the ES last time. The physics Bodies were still being created as a side-effect of something the connection setup was doing and weren’t accurately reflecting the current entity set.
The updates are in this commit:
It was in starting to create different object types that I discovered this so there is also a little bit of code in this commit that separates the “player entity” from the “ship entity”. Most of mentioned fixes are in SimplyPhysics.
You can also build them from github master by changing your build.gradle like this
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'eclipse'
apply plugin: 'idea'
mainClassName='example.Main'
repositories {
mavenLocal()
jcenter()
maven { url "https://jitpack.io" }
}
ext.jmeVersion = "[3.1,)"
project(":assets") {
apply plugin: "java"
buildDir = rootProject.file("build/assets")
sourceSets {
main {
resources {
srcDir '.'
}
}
}
}
dependencies {
// Need at least basic JME
compile "org.jmonkeyengine:jme3-core:$jmeVersion"
compile "org.jmonkeyengine:jme3-desktop:$jmeVersion"
compile "org.jmonkeyengine:jme3-lwjgl:$jmeVersion"
// We definitely want a UI
//compile "com.simsilica:lemur:[1.8,)"
//compile "com.simsilica:lemur:1.9.1-SNAPSHOT"
compile "com.github.jMonkeyEngine-Contributions:Lemur:master-SNAPSHOT"
//compile "com.simsilica:lemur-proto:[1.6,)"
//compile "com.simsilica:lemur-proto:1.7.2-SNAPSHOT"
// And our base code for sim-etheral, SiO2, etc.
// (many of these need to be built locally and 'gradle install'ed as of this writing)
//compile "com.simsilica:sio2:1.0.3-SNAPSHOT"
compile "com.github.Simsilica:SiO2:master-SNAPSHOT"
//compile "com.simsilica:sim-math:1.0.2-SNAPSHOT"
//compile "com.simsilica:sim-ethereal:[1.1,)"
//compile "com.simsilica:sim-ethereal:1.2.1-SNAPSHOT"
compile "com.github.Simsilica:SimEthereal:master-SNAPSHOT"
// Standard utility stuff
compile 'com.google.guava:guava:19.0'
compile 'org.slf4j:slf4j-api:1.7.13'
runtime 'org.apache.logging.log4j:log4j-slf4j-impl:2.5'
runtime project(':assets')
}
task wrapper(type: Wrapper) {
}
/*
This actually exits immediately since there is no standard input stream
task runServer(type: JavaExec) {
classpath sourceSets.main.runtimeClasspath
main = "example.net.server.GameServer"
jvmArgs '-Dlog4j.configurationFile=server-log4j2.xml'
}
*/
// Create a custom server start script in the distribution
task serverStartScript(type: CreateStartScripts) {
mainClassName = "example.net.server.GameServer"
applicationName = "server"
outputDir = new File(project.buildDir, 'scripts')
classpath = jar.outputs.files + project.configurations.runtime
defaultJvmOpts = ['-Dlog4j.configurationFile=server-log4j2.xml']
}
/*applicationDistribution.into("bin") {
from(serverStartScript)
fileMode = 0755
}*/
// I think this is ultimately clearer than the above
distributions {
main {
contents {
from(serverStartScript) {
into "bin"
}
}
}
}
// Either way we end up with dupes if we don't do this
distZip {
duplicatesStrategy = 'exclude'
}
I have been teaching myself java for a few months now. I still have a lot to learn, with out a doubt. I have been using Eclipse as my IDE, but recently have been looking for networking info. Like how to make a simple game over local network or similar.
While looking for a tutorial or sample code I could follow to get me started I stumbled upon J Monkey and specifically the Sim Ethereal example. I have downloaded the Sim-Ethereal basic example from GIT. This looks like to be exactly what I have been looking for.
But being such a no0b still as a java coder, and and new to J Monkey, I cant seem to figure out how to load the source code up in a new project. So I may poke around and see how it all works.
I mean, I can copy and paste the source into a new project, but then there is a lot of errors. What I do…
Create a new project, a JME3, BasicGame. I then copy and past the sim-eth-basic-sources folder into the mygame package that was created when the projected created itself. It has a main.java class in it.
Now inside of all the sim-eth-basic files there are errors. like:
import com.jme3.network.service.rmi.RmiHostedService; (doesn’t exist)
Is this a library or am I missing a class?
I think I followed the instructions correctlly from the “How Would I Use It” from this link:
But more than likely I didn’t, since I can’t seem to get this to work.
Might anyone be willing to point me to a place that could help me figure this out, or is there an easier way that I can add this to a new project? Or maybe I’m just to green yet to figure this out. lol
SimEthereal (and many other dependencies in that example) requires JME 3.1. You must be using JME 3.0.
Edit: but for example, if you’d used gradle and run the sim-eth example projects with gradle then it would have worked fine because it would have downloaded JME 3.1 and any other relevant dependencies. If you are setting up the project in the SDK then you will have to make sure it’s a 3.1 SDK and that you also include all of the relevant dependencies.
I put this gradle build file in a directory by itself and it didn’t run too well. Freaked out when it got to finding ASSETS. I had already run gradle build scripts for jmonkeyengine-master, SiO2-master, SimMath-master, SimEtherial-master, and lemur-master. So I thought it would have cached whatever it needed. So I don’t know what ASSETS refers to. Gradle and I would seem to be in the same boat. Haha.
EDIT: See comment below …
pretty easy to do … I downloaded the repo as a ZIP. However, the build gives me a “reported version” in the build directory of Lemur 1.10.1-SNAPSHOT.
I see that the build script says:
version=‘1.10.1-SNAPSHOT’ … on line 16
This is not a big deal to me in practical terms, because I can get Lemur-1.9.1 from the releases page … along with the latest Lemur Proto.
But the Sim-Etherial-ES build script can’t find the required lemur jars (1.9.1 etc). And that’s my problem.
Plus … the jmonkeyengine jars don’t come thru prolly because of a naming mismatch. I think they have a b001 or something in the name now.