Zay-ES-Net super-basic example

I was going to swing back and make a visual client at some point, too. Originally I was trying to get this done for the guy with the issue to show an example. So I went as simple as possible… and it still took me 2-3 hours to put together.

A simple visual client would draw a 10 x 10 grid somehow (I was going to use short flat boxes like a chess board where the edges of the cells don’t quite meet)… then little cones pointing down the Z-axes to represent the pieces. Floaty text above them to show the name and stuff.

That would be all that’s needed to make it more visual.

Any client interaction is going to require delving into networking topics that are not Zay-ES related… though I guess they are necessary for a Zay-ES networked game. Just nothing to do with those librariy.

I tried the gradelw way, to see if that is also possible and to find out if I’m able to get my head around that gradle stuff. The build.gradle looks readable and yeah maybe brings me back the Makefile feeling into the Java world, as ./configure && make && make install is something I normally can handle even if it fails…
I have this

cli@kaos:~/tmp/Examples-master/zay-es-net-basic$ chmod u+x gradlew

because it was not excecutable then I did what was written in the README.md

cli@kaos:~/tmp/Examples-master/zay-es-net-basic$ ./gradlew runServer
Downloading https://services.gradle.org/distributions/gradle-2.10-bin.zip

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)

So I googled around and end up here [stackoverflow article][1]. I did what was written there

sudo dpkg --purge --force-depends ca-certificates-java
sudo apt-get install ca-certificates-java

then I fired the gardelw runServer again and it happily started working and compiling and

cli@kaos:~/tmp/Examples-master/zay-es-net-basic$ ./gradlew runServer
:compileJava
Download https://jcenter.bintray.com/org/jmonkeyengine/jme3-core/3.1.0-alpha2/jme3-core-3.1.0-alpha2.pom
Download https://jcenter.bintray.com/com/simsilica/zay-es/1.2.1/zay-es-1.2.1.pom
Download https://jcenter.bintray.com/com/simsilica/zay-es-net/1.2.1/zay-es-net-1.2.1.pom
Download https://jcenter.bintray.com/org/slf4j/jul-to-slf4j/1.7.5/jul-to-slf4j-1.7.5.pom
Download https://jcenter.bintray.com/org/slf4j/slf4j-parent/1.7.5/slf4j-parent-1.7.5.pom
Download https://jcenter.bintray.com/com/google/guava/guava/19.0/guava-19.0.pom
Download https://jcenter.bintray.com/com/google/guava/guava-parent/19.0/guava-parent-19.0.pom
Download https://jcenter.bintray.com/org/sonatype/oss/oss-parent/7/oss-parent-7.pom
Download https://jcenter.bintray.com/org/slf4j/slf4j-api/1.7.13/slf4j-api-1.7.13.pom
Download https://jcenter.bintray.com/org/slf4j/slf4j-parent/1.7.13/slf4j-parent-1.7.13.pom
Download https://jcenter.bintray.com/org/jmonkeyengine/jme3-networking/3.1.0-alpha2/jme3-networking-3.1.0-alpha2.pom
Download https://jcenter.bintray.com/org/jmonkeyengine/jme3-core/3.1.0-alpha2/jme3-core-3.1.0-alpha2.jar
Download https://jcenter.bintray.com/com/simsilica/zay-es/1.2.1/zay-es-1.2.1.jar
Download https://jcenter.bintray.com/com/simsilica/zay-es-net/1.2.1/zay-es-net-1.2.1.jar
Download https://jcenter.bintray.com/org/slf4j/jul-to-slf4j/1.7.5/jul-to-slf4j-1.7.5.jar
Download https://jcenter.bintray.com/com/google/guava/guava/19.0/guava-19.0.jar
Download https://jcenter.bintray.com/org/slf4j/slf4j-api/1.7.13/slf4j-api-1.7.13.jar
Download https://jcenter.bintray.com/org/jmonkeyengine/jme3-networking/3.1.0-alpha2/jme3-networking-3.1.0-alpha2.jar
:compileJava FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Could not find tools.jar

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 23.461 secs

Ok more googeling says that my JAVA_HOME points to the SDK maybe instead of JRE or something like that.

cli@kaos:~/tmp/Examples-master/zay-es-net-basic$ java -version
openjdk version "1.8.0_01-internal"
OpenJDK Runtime Environment (build 1.8.0_01-internal-b15)
OpenJDK 64-Bit Server VM (build 25.01-b15, mixed mode)
cli@kaos:~/tmp/Examples-master/zay-es-net-basic$ echo $JAVA_HOME

On my machine that JAVA_HOME is empty.
But I guess you tell me know this is kind a setup issue and I better fix this somehow and ask in some Java forum. So the journey goes on :smile:
[1]: http://stackoverflow.com/questions/29584328/gradlew-bat-and-gradlew-sslhandshakeexception

You don’t have a JDK installed. When you use the SDK, I guess you are using the one built into it.

yeah exactly. I’ll do tonight. Seems worth the effort this gradle approach.

Actually, it’s strange… it seems you do have JDK installed but I guess JAVA_HOME is not set properly for some reason.

Edit: I guess that one shown in your screen shot is the SDK one? I guess that could be why JAVA_HOME isn’t exported properly or something. I’ve never run the SDK on Linux and always installed the JDK separately on my Mint boxes.

This looks really nice and seems usable now? seems that all you have to do is create a GameLoop that takes a GameSystemsManager which calls your version of “AppStates” or GameSystems, Im assuming it also calls the Systems in the order you add them?

Yep.

And yeah, it’s usable now. I haven’t pushed an official release because maybe I will still tweak some things… but in the games I’m using it in it has been stable for a while now.

I have some questions about that super basic example:

                // Note: normally the game logic would get updated more often than
                //       the entity data send updates.  For example, game logic updates
                //       at 60 FPS while updates are sent only 20 FPS or less depending
                //       on the type of game.

I do not understand why the game logic should have higher update rate thant the updates. Becaus as far I can see if you update the game logic 60 you nevertless see only every 3th such change on the client, so why not have them both at the same rate. What do I overlook here?

Next question about the Position.class there are setters, I thought it is better to have a component immutable, means new position and new facing just means a new Position.class object. In my invader I only have getters.

Then the last question so far:

Server server = Network.createServer(GameConstants.NAME, 
                                                     GameConstants.PROTOCOL_VERSION,
                                                     GameConstants.PORT, GameConstants.PORT);

Why do you need a name, version and two ports, why not just this constructor here

Server server = Network.createServer(GameConstants.PORT);

??

Because it if often not necessary for the client to be 100% responsive to entity updates. If you need ‘real time’ position updates then there are more efficient ways of doing that and they will look better.

Else sending updates all the time is wasteful to network bandwidth.

No there aren’t. Look again.

So that if an old client tries to connect or a client for a different game, they will get kicked right away with an appropriate message.

Ok that I understand, but why then update the game logic 60 times per second when you only send the update 20 times per second? I mean why not update the game logic as well 20 times per seconds? Is there a special reason? I would like to explain that as well, when I write the case study, but I only can write what I understand :smile:

Damn you are right. But why having those “clones” or how ever that kind of “factory” is called? Why not just new and set location/quterion all the time? Ah I think I understand now. You update that way only one of the both, so those “factory” methods are for convenience and lower the verbosity of the code. Got it I think.

And the last one is now clear as well. The version is my defined version, if I have a new game server I set a new version and scare away old clients. Ok this I got as well.

The Serializer I did not completely understand, I do not see the connection to the networking stuff, but I guess that is somehow hidden (or I do not see the link).

Your game logic may update often for whatever reason… physics, whatever. Usually quite often so that physics is accurate and AI is self-responsive and so on.

But it’s also quite often that network updates are only sent 5 times a second.

Note: not all updates are necessarily sent as entity updates. Physics updates are generally sent in a completely different way as ES updates are two slow and clumsy for that. I often only update the real Position component 1 time a second for physics based objects where as they stream constant 20 times per second packets of changes for the client to interpolate.

Out of curiosity did you ever used Zay ES outside of games? If yes what kind of app? because I think it is not strictly game related. But yeah the question is completely off topic.

No. But I did write a white paper on how the idea of entity style selection and duck typing go well with modern web ‘mashups’ and noSQL databases.

[OT]
In this blog, the author explain how and why it adapt ECS/CES to create LightTable (an editor/IDE) http://www.chris-granger.com/2013/01/24/the-ide-as-data/

1 Like

Ok I wrote part 1 in my blog as it is my playground and less formal or with the need of keep it up to date. Currently I do not exactly know where I will end with that. After I have a nice example I will port it to Zay ES case study section and polish it up. As well I try to keep my case studies up to date in the wiki.

I hope that’s fine with you, else yell “No good”.

EDIT: I took some of your explanations but did not give you credits, as I may have missunderstood something, so it’s me to blame if there are wrong statements in it.
EDIT2: Of course if you want credits I can add. I just was not sure. Only the link to the example do credit you.

Note:

The game loop is running as infinit loop in a try catch block to be able
to cleanly react on an abort of the program with ctrl-C.

Is unfortunately not true. Ctrl-c will halt the program without reaching my finally block. Normally in a loop like that you would have some exit condition and so I left the finally block as a ‘good practice’… also if the loop internals throw an exception for some reason then the code will at least try its best to clean up nicely and let the clients know the server is closing.

In a real game, letting the user know that the server shut down is the difference between one or two “Hey is the server up yet?” posts and 500 reviews about “My game crashed for no reason!!11!!!”

Also, just an aside, using a Vector3f for rotation is a little strange.

Hey thanks for the corrections! I will change it.

That’s me not know too much about 3D maths. It worked for my invaders, but I guess I would better use a magical Quaternion instead, like you did for your example. If I do, then I will change that in the invaders as well. With the vector I just store Euler angles and do the quaternion stuff “outside”. So your approach is a little more to the point I guess…

Sorry to pump this thread again, but I have my second part. If you absolute not like it then I leave it on my blog only, else I’ll start to move it to Zay ES wiki, like the other stuff. I will write a 3. part and maybe a 4th part to deal with interpolation (but there I would need some help).