SimEthereal example with ES - blog

The grid cells are 2048… the grid is endless.

1 Like

Perfect, thanks for letting me know.

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.)

…I just haven’t written the ShipLabelState yet.

3 Likes

Just a quick two questions: You mentioned that I have to gradle install the jar myself. I may just be missing a reference somewhere but:

  1. Can I download the dependency jars you are referencing in the build.gradle file somewhere online?
  2. How do I install them to the mavenLocal repository?

Which jar?

Sure… since they are in the JCenter public maven repo you can just get them there like any other mavena-accessible jar.

gradle install

I have a feeling these questions are not really compatible, though. I seem to have missed some information on what you are actually trying to do.

Trying to get sim-eth-es to compile :slight_smile: 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 lemur…
cd Lemur
gradle install

Checkout SiO2
cd SiO2
gradle install

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.

1 Like

HUD labels are back:

Was pretty simple:

…and now they will work for any entity that has BodyPosition and Name… whereas before they were hard-coded for ships.

3 Likes

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

Thanks for reading,

~Nihil

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.

It’s possible that the examples depended on snapshot versions… I’ll have to take a look. But Lemur 1.9.1 should be up on jcenter and the builds should have no problem downloading that if that’s what it’s referring to.

I’m on my way out the door so I can’t look right now.

@Ali_RS
Sorry … I was wrong. Your gradle build file worked just fine. My problem was I needed to put it in the sim-eth-es folder.

The build gave me a zip file with the jars in it. The jars don’t all have the names I expected … such as lemur-master-SNAPSHOT.jar. But it gives me a starting point.

Thanks.

1 Like

It’s all kind of unnecessary anyway… you can pretty much build sim-eth-basic or sim-eth-es now just by removing the -SNAPSHOT from the versions of the simsilica dependencies. Those have all been officially released now. I just haven’t gotten around to updating these projects yet.

pspeed thanks for taking the time to respond. Sorry i haven’t replied in several days but…

I had no idea how to use gradle, after talking to wobblytrout , a twitch.tv streamer, he was able to walk me through what to do.

In order to get the gradle to build (building the sim-eth-es), I had to comment out a line from GameServer.java, :
Serializer.initialize();

Also had to comment out distributions line of the build.gradle:
//distributions {
// main {
// contents {
// from(serverStartScript) {
// into “bin”
// }
// }
// }
//}

After doing the above it did load up and run as a standalone, and I was able to get it loaded up in JMonkey to try and play with the code. Although, I think i have bitten off more than I can chew… As a no0b coder this may be a bit over whelming, lol, but I did get it to work!

Thanks for your time!

~Nihil

How were you trying to run it? You shouldn’t have had to do any of that.

@pspeed, I was trying to get the source code into a Jmonkey project so I could mess around with it. I guess in order for me to do that, I had to run the build.gradle?

Once I removed those couple of lines, (I commented them out) the gradle build succeeded and the application ran. I was then able to put it into a new project. I tried just copying and pasting before the gradle build, but I was getting a ton of errors. Most of which were like null pointer errors, since I didn’t change package names etc… so like some of the imports weren’t able to be found.

Yeah, then that’s a ton of work. a) you have to run with JME 3.1 beta. b) you have to manually hunt down the dependencies and the dependencies of those dependencies. (You can see these from the command line if you run gradle dependencies in the checked out sim-eth project.)

Dependency management is much simpler in modern build tools like gradle versus the ‘manual hunt’ that’s required for the default SDK stuff.