3
\$\begingroup\$

I've created a voxel game in C++, OpenGL and SFML, and I want to make it multiplayer.

I'd like to make it similar to Minecraft's client-server model: The single-player is just a client to the hidden server underneath; but can be configured to connect to multiplayer as well so that the single player and multiplayer code are one and the same.

Spitball-ideas:

  • Use a separate thread for the server logic and then share the data between a synchronized point in the code for the client.
  • Just send packets to local host from the server thread and collect them from the client thread.

How should I do this?

\$\endgroup\$
  • \$\begingroup\$ You basically need to embed a server inside the single player mode. Write the server module in a way that it can be embedded easily. \$\endgroup\$ – Vaughan Hilts Apr 16 '15 at 17:43
  • \$\begingroup\$ @VaughanHilts hmm but exactly how would I go about embedding it while allowing it to be networked? Create a class for basic things like. Block broken and then wrap that with a network layer? \$\endgroup\$ – John Apr 16 '15 at 17:45
5
\$\begingroup\$

General concept

Create a server class (to handle connections and messaging) and a client class (to handle connecting to server by IP and port).

Then ask the player whether they want to create or join a server.

  • If create, start a server and join it with the client.
  • If join, join the existing server.

Minecraft singleplayer can be opened to the LAN, by just clicking that option. So it is already running singleplayer with server client setup. It works, because latency is basically 0. It adds a bit overhead, but nothing noticeable if done decently.

Coding it

You should definitely run the server in its own thread.

Handle all actions as network messages. Instead of directly calling WalkForward() (for example), you would do:

client.SendInput(inputSnapshot);

and in the server

while(server.ReadMessages())
   Handle(server.messages.next())

////
void Handle(MessageBase message)
{
   if(message.readByte() == InputMessageType
      HandleInputSnapshot(message);
}
void HandInputSnapshot(..)
{
   world.Update(message.getConnection(), message)
   server.CreateAndSendWorldStateUpdateMessageForPlayer(message.getConnection());
}

The server would store the world state with all objects in the world, their locations, rotations etc. It would calculate each client's local area for objects that they should know, and send each a personal worldStateMessage (or similar).

Each client would also have world state, but from its own view. It would not know about all the objects around it, only those that server has sent it. Clients constantly receive worldStateMessages, maybe something like 20 times per second?

Why this works

With this kind of system, you would not send "DestroyBlockXY", but "Client X targeted xyz and clicked mouse 1". When the server receives such a message, it would execute that action in its own world model and notify other clients, that "Client X just targeted xyz and clicked mouse 1". Other clients would pick up this message (if it's in their local area) and update their view of the world, to mirror the server's.

As you see, you can't just plug a client-server model in. You have to code your game around it. But when done like this, you can play on a local server or internet server, using exactly the same code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.