Integrated/listen servers for singleplayer

Started by
13 comments, last by hplus0603 4 years, 8 months ago

It sounds like you are trying to write one piece of common code, and either hiding the differences behind a layer of abstraction (e.g. your broadcast method, or the 'permissioned variable' system), or trying to use a bunch of if-checks to get it to do different things depending on whether it's a client or server. To me, both of these seem like code smells.

Given your example of setting a variable - that's already the wrong level of abstraction for the problem. If I'm running code that expects to be able to set a value and then it fails due to lack of permissions then I shouldn't have been running that code in the first place. Some systems will only run server-side. Some will only run client-side. And some will run on both sides, on common code and data. Rarely will any need to care 'where' they are.

 

Advertisement
21 hours ago, Kylotan said:

It sounds like you are trying to write one piece of common code, and either hiding the differences behind a layer of abstraction (e.g. your broadcast method, or the 'permissioned variable' system), or trying to use a bunch of if-checks to get it to do different things depending on whether it's a client or server. To me, both of these seem like code smells.

Given your example of setting a variable - that's already the wrong level of abstraction for the problem. If I'm running code that expects to be able to set a value and then it fails due to lack of permissions then I shouldn't have been running that code in the first place. Some systems will only run server-side. Some will only run client-side. And some will run on both sides, on common code and data. Rarely will any need to care 'where' they are.

 

Thank you very much. I now realise what mistakes I've been making.

In the Console class (which is common code) I've replaced variable.setValue(value) with user.setVariable(variable, value). user is an argument that is passed to the Console.run(...) method. LocalUser will send a packet to the server if connected. ServerUser will set the variable. Same thing for commands - if the command is a server only command, LocalUser will send a packet and ServerUser will execute the command.

I've got a minor problem with weapons (as that is common code). On the client side, should I decrease the ammo count when firing? I'm thinking that I shouldn't as it is logic and so it should be server-side, right?

Firing is sent as part of the PlayerMovementPacket.

Once again, thank you for your help.

I would say always send the "I want to fire my weapon" command to the server, even if the client thinks it can't fire right now, and do predict using up ammunition on the client. If something happens to desynchronise the client and server so much that your shot didn't actually happen, it's probably going to distract you from the fact that your ammo counter was momentarily wrong. You just need to make sure you can correct the client's view of the world later if the server disagrees with you.

I think you need two counters for ammo -- one for "ammo count displayed to user" and one for "ammo count received by server."

The user would be quite surprised if they fired a bullet and didn't see a lower ammo count right away. Similarly, you shouldn't let the user fire too many shots just because the server is slow to respond, so when the user-display variable goes to 0, stop allowing fire.

You will likely also want a time-step-when-changed for each of them, and if you get a server update for ammo count at a time step higher than the last time you changed the display-value, then update the display value to the server value if they are different -- this will make sure that your display is "eventually consistent."

 

enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement