Making singleplayer a special case of multiplayer

Florian

Active Member
Contributor
Architecture
Name: Making singleplayer a special case of multiplayer
Summary: Make singleplayer be in the background a headless server + client.
Scope: Engine
Current Goal: Making singleplayer a special case of multiplayer
Phase: Design
Curator: Florian
Related: -

The idea is to make singleplayer a special case of multiplayer by letting it be single player be
a client that connects to "headless server" started in the background.

Advantages:
  1. Reduces effort for manually testing it, as currently you have to test singleplayer, non headless server + client, headless server + client.
  2. It enforces code that seperates clearly between "client" and "server", which makes the code better understandable. There is just one possible setup (client+server) not multiple which have to consider while reading the code.
  3. It will promote the reduction of non server components from the headless server.
  4. It will promote the reduction of non client components from the client.
  5. It simplifies the introduction of client predictions that make games appear less laggy even if the network connection is bad.
    Since the client has it's own game state, it can be temporarly modified to show for example a block placement or inventory modfication before the server has confirmed it. Currently we have no block preview and the inventory prediction has some bugs.
  6. It is possible to debug both server and client in one VM. You can stop both at once for easier debugging.
  7. Future code developed for singleplayer will "auto magically" work on a headless server with one client - as there is no difference. Currently there are still a few things that don't work with a headless server.
  8. It has the potential of providing a huge framerate boost. Currently any code that works with entities can't run in parallel. If the server and client have each their seperate entity manager than for example the rendering of entities can run concurrent to some server only calculations like pathfinding or enemy spawn location searches.

Disadvantages:
  1. The game will need more memory. However the memory need will NOT be doubled!
    For example the periodic saving requires a lot of memory and is server only. Everything related to rendering isn't requried on the server. Assets can be shared between server and client if they are read only. Potentially we could even share chunk data.
  2. CPU usage in singleplayer will be higher, as some calculations are done redundantly. A higher CPU usage doesn't however mean a FPS drop.Also the amount of stuff both client and server calculate redundantly should be small.
Next planed steps:

Get rid of all static variables including the CoreRegistory by replacing it with dependency injection.

In rare cases we can expose a "Context" object that provides a method for registering objects that will then be injected via dependency injection. It may also offer a method injectAll that fills all annotated fields of the object that got passed as argument. Also we may want to have it have a get method to get objects in case they are only available after construction.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
I went against the blanket agree crowd with a "Useful" rating as this sounds like a great idea, I just don't feel like have the technical depth to really add my weight behind it :) I'm a glorified bureaucrat and/or cheerleader most the time!

Curiously, how would debugging in an IDE change? Currently I test via IntelliJ's run configs launching a headless server in one execution then one or more clients in another. I guess that would be unchanged as it is intentional headless. But if you launch a standard game instance how does it split off the server side, isn't it just yet another thread?
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
Single player is already a special case of multiplayer. I don't actually think code separation between server and client is a good idea, because you end up with the code dealing with a single concept split across files. Having the code together makes it easier to follow, not harder, in my opinion.

To be a bit more verbose... I'm happy with the idea of cleaning up the use of static state, and with having a debug option to run both a server and client internally to a single instance to aid debugging - this is a really neat idea. I disagree with making this the default and only behavior. I don't think it is reasonable to sacrifice single player performance in order to force developers to correctly test their code.
 
Last edited:

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
Well, at the moment developers have to test twice (or three times if you take into account headless), something I don't bother doing, because starting Terasology to test once is long enough already. So it's possible my mods might not be running in multi-player mode.
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
... though now with the bug where the instigator being received over network is EntityRef.NULL, it's impossible to test anyway. Bugs like that would not have been introduced with complete separation, as they would arise immediately.
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
Well, at the moment developers have to test twice (or three times if you take into account headless), something I don't bother doing, because starting Terasology to test once is long enough already. So it's possible my mods might not be running in multi-player mode.
That's an argument for having the internally multiplayer setup for ease of testing, not eliminating the existing singleplayer architecture.

Bugs like that would not have been introduced with complete separation, as they would arise immediately.
True, but they also would not be introduced if people always tested with a multiplayer setup. You can already test by running both a server and client - if you can be bothered anyway. I support making this simpler, but I don't think there is anything fundamentally wrong with the architecture as is. Complete separation has some big issues, including near-doubling of chunk data (since both ends would have independent chunk data) and doubling of of some work around chunk data (recalculation of lighting, which is done both server and client side).

The other thing to know about the network code is it is basically just proof of concept code. I'm honestly surprised it works as well as it does.

One other thing we should consider is adding the ability to flag single player modules as such, and preventing their use in multiplayer.
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
@Immortius you have missed that part: "Assets can be shared between server and client if they are read only. Potentially we could even share chunk data."

Also, having "internally multiplayer setup" for testing will not eliminate required double-testing (or triple), since then we might have bugs in single-player mode. Granted you might argue that sharing some of the data (like chunk/lighting data) - might introduce bugs that will be visible only in real multiplayer, but the range of bugs this might introduce is very narrow and probably only bugs in engine, not mods themselves.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Moving thread to Dev Portal after realizing it is in the Incubator. I'm trying to empty out and delete that one :)
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
@Immortius you have missed that part: "Assets can be shared between server and client if they are read only. Potentially we could even share chunk data."
I saw it. Assets aren't (much of) a problem, but I doubt you can share chunk data (and ultimately they should be entities like everything else).

Also, having "internally multiplayer setup" for testing will not eliminate required double-testing (or triple), since then we might have bugs in single-player mode.
That is very unlikely in my experience.

The entire network architecture is designed so that you develop for multiplayer and it collapses down nicely and efficiently for single player. The only two paths for network communication are events and replication - in a multiplayer situation the events get sent between the client/server, while in a single player situation they all run locally. And replication simply isn't needed.

There can be situations where you'll have issues in a listen server (when an event that should be sent to the client is also played on the server, resulting in the local client seeing or hearing things meant only for a remote player), I will grant you that. So maybe drop listen server support? But I vehemently disagree with the idea of removing the single player support.
 

Florian

Active Member
Contributor
Architecture
I guess it is to early to decide if we want to remove the old single player mode or not.

I suggest we add a client+server option without removing the old singleplayer for now. Then we can see how it goes if that is the only mode we use for testing.
 

Florian

Active Member
Contributor
Architecture
I started woring on it. You can view a work in progress version at:

https://github.com/MovingBlocks/Terasology/compare/develop...flo:no-static-access-part1

It introduces a new Context intreface, with a get, put and delete method and makes the CoreRegistry be based on that Context object. Thus for a transition phase objects will be obtainable via either, Context object, CoreRegistry or dependency injection.

Nice thing about it is that the permanentPut methods of CoreRegistry are no longer necessary as the engine simpliy works with a context that acts as parent context for everything else. If an object isn't found in a context it is looked up in the parent context.
 
Top