Sim-eth-es Troubleshootings

Thanks for asking, @Ali_RS because that would’ve been my next task/problem :smiley:

I’ve seen that the Zone updates are happening, but for the client I only saw:
AddObject (ModelContainer) and then UpdateObject (MobContainer) ONCE.

I don’t know why because technically I should see an AddObject ModelContainer until something is setting a BodyPosition on it when it becomes a MobContainer, so I should see another AddObject.

Could this already be the problem? Because this class is mainly about the server, but without it (that’s the note), the Client does not have a BodyPosition Entity and thus fails early.

Edit: Yep, solved, and thanks to the interpolation it’s now really fluent and smooth.

What would happen if I’d need another Transitionally Buffered Object, say a player has a cloaking device, I cannot use Entities because that could be like anywhere between 100-2000ms delay, but that would mean I’d need to edit the zone logic?

The cloaking device makes the ship invisible?

(Too bad SimEthereal doesn’t expose its own visibility flag in this case.)

SimEthereal is not designed to piggy-back other state (and man what a pain that would have been). So you are left with cloaking through other means (and maybe including the timestamp to correctly integrate)… or doing something with fake invisible objects or something.

For the first approach the ‘lag’ could just be part of the cloaking power-up process.

The problem in either case is that the other clients are still getting position updates for the cloaked ship. A hacked client could essentially see right through the cloak. The only way around that is to remove the object from the sim-ethereal space when cloaked. Then you are left with how to sync the player.

Selective visibility is not something that SimEthereal supports. I think it’s possible in theory to have support for where an object is only visible to a particular player. I haven’t looked at what it would take to make that happen, though. 99% sure that state updates are already client-specific.

For other things not having to do with visibility, the answer is similar. Handle it yourself and give an in-game explanation for the delay, have the effect be client-reactive to some perceived state (like how I handle walk animation), or have some extra invisible objects in the scene that indicate some state.

Let me know if you find a way around the cloaking issue. I have the same element on my backlog

Well just to be clear this was a hyptothetical question and not all so related to the visibility itself (though I might’ve gotten that idea from SimEtheral). But if one does not think about visibility / hacking, it’s still the synchronization which might be of interest, I mean this even accounts for spells being casted in some games where lag makes a difference.

This is not all so easy…

The casting of a spell happens on the server not the client. The client is just the view.

That sort of issue is not different than the ones in those original Valve articles. The spell in this case would be a new object anyway… so that one’s pretty easy.

@asser_fahrenholz Now I remember something: In World of Warcraft a spell lasted shorter than it actually lasted to account for latency:
Imagine Firebolt takes 2 seconds, then the game had a configurable(!) setting, say default is 100ms, then you could re-cast another spell after 1900ms or start walking again after 1900ms (but the spell bar still moved until 2 seconds).

There were two possible outcomes of that: It worked or the spell failed/recasting didn’t work. So I guess the setting is set so that you can cast again and the packet just appears in time after said 2 seconds.

Now I still have a few more questions for Mr. Speed though:

A) I’ve reworked the way movement/sprinting is handled and while it technically works, it exposes a bug which to me feels like a memory corruption / multithreading issue / strange thing. Now since we’re using Java this is more than unlikely, so I don’t know what’s wrong there. One fact is that changing the value of an unrelated variable and even changing something in other places of code changes the bug. My best guess would be that in the Physics Character the Controller Approach you use doesn’t work, but that doesn’t fit to the symptoms. Now onto the facts:

What I did was to make the client only send the walk direction together with a sprinting flag because of 3 facts:

  1. That way you always walk 3 units / second and not sqrt(2) * 3 [when you’d press W and D, you’d walk 3 units/s in both directions).
  2. Prevent cheating by simply modifying the speed value, that way the client only ever sends the direction
  3. Make room for further boolean state movement types (isDucked, …)

The code is here:
https://github.com/MeFisto94/Monake/commit/8bdcde3b71b6cfea482d972f3cf47ce9646454b8

The Problem is the CharInputDriver: vTemp is always wrong and most of the time showing 1.5f in the direction I wanted to walk (though the Debug State shows that the Spatial moves at 0.5 at most). When I stop walking, vTemp still lags behind quite a few frames even though the visual representation again does not:

Now here’s the catch: when I change the code, that means the constant runSpeed without EVER sprinting, I can walk faster (when decreasing runSpeed, with runSpeed 4 you can barely walk). Due to the values, I’d suspect the applied force overcompensating the speed so that in the next frame it’s braking again. But if that was the issue, I’d see the sign always changing, I more suspect that when I change the code, the execution time is influenced, because I also saw that: As I was only moving the world spatial, the behavior changed, which shouldn’t be at all, because that was view-only. And I’ve discovered it makes a difference between launching the project in IntelliJ and with gradlew, with gradlew you can walk faster…

B) We still have the lemur problem with Jaime as posted above unfortunately.

C) This little side project really increased my interest in the whole networking stack but I have to say that I didn’t feel that comfortable in the code base, it felt foreign and strange to me, probably because it’s far away from jme’s “rootNode.attachChild(assetManager.loadModel())” and instead is adding a value to two enums, adding code to a huge switch statement, having lots of code spread across many parts, so many considerations to do.

I fear that when I’d port my game, I wouldn’t have the same behavior any more in single player (this starts with the 100ms delay thing). I’m not at all afraid of the coding undertaking but that it ends bad and I throw away either 3/4 of my game or the networking branch.

Simple Issues I have so far is that I’d prefer to have a headless jmeApplication at least for the AssetManager and using AppStates broadly instead of GameSystems (again not an issue, whether I’d use one or the other doesn’t matter, I could probably even write a wrapper class).

Another thing is that the code isn’t split into client, server and shared and so I jump through the code like a headless monkey. I guess this is also only an issue of Gradle Magic.

I know that I may be asking the wrong question on purpose: Can I adopt/modify the SimEth ecosystem so that it feels natural to my code base? Because currently it doesn’t feel like being bolt on but instead being the mortar between the whole game bricks. If I only think about the AI Systems and synchronizing them to still keep the client completely up to date so that it does predictions right, I get an anxiety disease :smiley:
And the second question would be: I’m like 80% through my game code-wise. Finish the game and bolt on networking or do it now? I mean it’s too late in both cases, but I’m leaning towards finishing first to at least have something. For Motivation and to not have to worry about how the systems should work when doing the networking code.

Are you using native bullet?

If so, applied forces are all wonky because of the variable time step. I tried a hundred different ways to fix this but was only able to fix it locally by using a fixed time step.

It was really frustrating because even adding logging would change the behavior. I tried moving driver execution into the pre tick, post tick, nothing worked. I actually think there is a bug in native bullet somewhere but I wasn’t able to find it.

Basically, for some reason, forces are applied differently somehow when the step time naturally closely matches the actual time.

This is actually why none of this was officially released and I have a bunch of char animation changes left uncommitted.

Regarding the UI issue with Jaime, I missed that before. I will need more information.

1 Like

I mean, how else will you do it? It has to sit between the thing moving the objects and the client’s view of those objects. It can’t be otherwise.

SimEthereal is probably the most complicated bit of code I’ve ever written. I think the fact that you can say “Hey this object moved” on the server and that all of the clients just get an event about that… is about as simply as I could think to make it.

I think the issues you are fighting are fundamental and not related to the design. You simply want things you can’t have.

Treat single player as a local multiplayer if this is really a concern. Just use the loopback address. That’s what I do.

90% of apps states is for visuals. You drag along a ton of stupid shit just to execute something once a frame. Moreover, that code will never be usable anywhere else outside of a JME application.

It makes more sense to go the other way, adapt systems to states. AppStates are kind of a broken design. They are supposed to let you ‘extend through composition’ a JME application but then they don’t even fully support that. (Just like Controls are only a partial solution for Spatials.) GameSystems are way simpler because their only job is to execute game code and hook you up with other systems. No weird update delay, no preRender, postNosePick, postRender, preUpdate, postUpdate, stateAttached, stateDetached garbage.

So I guess it’s the examples you are criticizing? They may have lost something in trying to be simple. As I develop the moss stuff I’m trying to be more modular and clearly spell out client, server, and common… but in the end I think that only makes your problem worse maybe.

This code will always be far and away from a giant Main.java class. We can probably argue over the decomposition but there will always be some kind of decomposition.

1 Like

Yes, I didn’t test jBullet yet because I think it’s easier for us to switch to impulses / setting the linear Velocity directly.

Sure, so:

The problem is that Jaime isn’t in-line (vertically speaking) with the numbers, even though it should be due to the layout (I tried multiple). For some reason the offset / translation I set, is ignored by lemur.

Not really criticizing, rather posting them as a list to myself and maybe to see/discuss whether this is possible/reasonable. And I’m not a fan of a giant Main class, it’s rather that I don’t know sometimes if I’m on the client or the server.

I don’t have too much time at the moment… but something to remember is that Jaime is 0,0,0 at his feet and Lemur GUI elements grow down.

1 Like

Another way I am using (which is common for most RPGs) is that I send the target point to server (when player clicks on a walkable object) and in server I find a path for player to follow using a server side NavigationSystem and using a PathFollowSteerBehavior I fed the calculated force into bullet physic.
So player movement is treated like a npc.

1 Like

So, the Lemur Problem is fixed, it was just moving the “Jaime” Node instead of the container out of it’s parent, but the bullet issue still baffles me, especially because I didn’t notice it until changing a line, I really feel like reverting the commit…

I’ve tried impulses, forces and setting the velocity directly this time, nothing works. The only thing which worked half way was applying the desiredVelocity as force, that way the character bugged a bit and was able to accelerate (however the velocity wasn’t capped there).

After some fiddling (I now set the desiredVelocity as LinearVelocity), I had this beautiful thing in my log which correlated to my impression:

SET: (0.0, -0.6666667, -5.0)
vTemp: (0.0, -0.6666667, -2500.0)

I can’t tell why and what is wrong there, but I’ve also found that the Z value was always half the desired value (even when applying a force), this time it’s not half the value, but 50 times the value, that’s probably due to the mass of the character being 50. Not sure why it multiplies the setLocalVelocity with the mass though, or reports it like this…
Everyone is appreciated to check out Monake and edit the CharInputDriver :slightly_smiling_face:

I’m telling you… you should really try to build SiO2’s bullet form source and just pass a fixed timestep to bullet. For native bullet this will clear up 1000 weird things.

Like, change this line:
pSpace.update(t);

to:
pSpace.update(1/60f);

…and see if your weird problems magically go away.

1 Like

For me when setting body.setPhysicsRotation directly cause the body to have a buggy rotation. It is very noticeable when he is not moving and standing in place.

In following code

 // Kill any non-yaw orientation
        qTemp.toAngles(angles);
        if( angles[0] != 0 || angles[2] != 0 ) {
            angles[0] = 0;
            angles[2] = 0;
            body.setPhysicsRotation(qTemp.fromAngles(angles));
        }

I also see this behavior in SiO2’s bullet example but it is hard to notice it.

I am going to replace it with torque based rotation to see if it fix. I need to find a way to calculate torque force from desired rotation. You know I suck at Math ! :blush:

btw I am going to test idea of fixed timestep, Paul thanks for the idea :+1:

This is probably the source of your other problem, too.

Essentially, I’ve found that setting anything on the rigid body in the drivers has inconsistent results if you don’t use a fixed time step… for native bullet. I’ve tried moving the running of drivers to the prephysics tick, the post-physics tick, etc… as I recall the only thing I accomplished was more consistent failure. It doesn’t make sense to me and I lost the will to live while trying to track the issue down in the C code.

2 Likes

Unfortunately the fixed time step didn’t fix it for me, note that pSpace.update() is still called at variable times but made to believe it’s 1/60 (so I want to say I did it as you suggested but that doesn’t change when/how often update is called).

What I got when doing this is quicksand, the character slowly bugs through the floor, falling down. What I don’t get is why it used to work in the SiO2 Example Code like just without adding this line calculating run/walk, must’ve been a very lucky circumstance.

Regarding the questions of code organization, I thought I would mention something about this now that I understand it’s the sim-eth examples you are talking about.

I fully expect that a real game would split its own code up in a more development-friendly way. The sim-eth examples are monolithic examples and so keep code together in one project. I do that in other simple cases also mostly because I don’t use an IDE and it’s easier for my to navigate around.

However, for SpaceBugs I developed it as a “real game” and so the code is separated into three projects:

  • server
  • common
  • client

The “server” project contains all of the GameServer code, the sim package, all of the game systems, etc… Anything “game logic” lives here.

The “common” project contains the shared stuff that both client and server need to communicate. So this would be the game constants and the RMI interfaces that the client and server classes implement. For example, in the sim-eth examples this would be where things like AccountSession and AccountSessionListener lived. GameSession, GameSessionListener, etc… net.server impls live in the ‘server’ project and net.client impls live in the client project.

For an ES based app, this is also where the components live.

With just those two projects, I could create a command-line server only application… with no visuals. Aside from jme-math and probably a few utility classes, it wouldn’t even really need anything from JME-core. That’s the ideal server, really.

The ‘client’ project is where the JME UI lives along with the client impls of common’s interfaces. No ‘sim’ code lives here.

For my single player games, I autowire a server and client together an auto-login, too… it may not be the most efficient way but with a loopback connector it’s going to behave exactly like the networked version. (At some future time, maybe it’s possible to wire the client interfaces directly to server implementations… but that’s a project for a future date when the game is done and you’re bored.)

…it also makes it super easy to text the network code because I don’t have to do 20 steps every time. Just launch and click “single player”. :slight_smile:

1 Like

It’s not about how often update is called. I experimented with a lot of things.

The issue was that when the tpf passed to update was VERY CLOSE to the actual time elapsed… but not exactly like it. (Or maybe it was when it was exactly like it.) Things like applied torques/impulses would not show up or be so small as to be irrelevant. Jaime would move like in quick sand if he moved at all. Or like 1/100th speed.

I don’t have time to resurrect which version worked and I have a lot of commented out attempts so I’m not sure what state I left my local code before rolling it back to push releases in November.

Here is the code verbatim in case it matters:

        float t = 1 / 60f;
        //float t = 0.99f / 60f;
        //float t = 2f / 60f;
        //float t = 0.016666781f; //(float)(time.getTpf() * speed);
        //float t = (float)(time.getTpf() * speed);
System.out.println("-----t:" + t + "  ------------- " + time.getTime() );
        if( t != 0 ) {

//            for( EntityRigidBody b : driverBodies.getArray() ) {
//                b.getControlDriver().update(time, b);
//            }

            //pSpace.update(t);//, 2);
            //pSpace.update(t, 0);
            //pSpace.update(t, 1);
            pSpace.update(t, 2);
System.out.println(" distribute events");
            pSpace.distributeEvents();

I think the update(t, 0) one is the right one, thinking back.

1 Like

OH! did not know it can take a second argument called maxSubSteps.
Searched the web for it … and …

old doc says :

maxSubSteps: Should generally stay at one so Bullet interpolates current values on its own. A value of zero implies a variable tick rate, meaning Bullet advances the simulation exactly timeStep seconds instead of interpolating.


new doc says:

It is perfectly fine to stepSimulation(1/120 , 0) to get a fixed timestep of 120 Hertz for example.


It mentions you can safely use maxSubSteps = 0 with a fixed timeStep. In our case t=1/60.

1 Like