Home Java Server development for multiplayer game using nodejs and magx

Server development for multiplayer game using nodejs and magx

by admin

Many developers are starting to develop a multiplayer online server based on the library socket.io This library makes it very easy to implement data exchange between the client and the server in real time, but you still need to think through and implement all the logic and interface of the server’s interaction with clients, as well as the scaling architecture and traffic optimization.

I want to tell you about the library magx which allows you to forget about the networking (server and client communication) and concentrate on the development of the game logic and the client UI.

When designing a multiplayer game architecture, 2 approaches are usually considered: authoritarian server and non-authoritarian (authoritarian client).Both of these approaches are supported by the magx library. We will start with the simpler approach, the non-authoritarian one.

Non-authoritarian server

The essence of it is that the server does not control the results of each player’s input. Clients independently track the player’s input actions and game logic locally, and then send the result of a certain action to the server. After that, the server synchronizes all the actions performed with the game state of other clients.

This is easier to implement from an architectural point of view, because the server is only responsible for communicating between clients, without doing any of the extra calculations that clients do.

With the magx library such a server can be implemented in just a few lines of code :

import * as http from "http"import { Server, RelayRoom }from "magx"const server = http.createServer()const magx = new Server(server)magx.define("relay", RelayRoom)// start serverconst port = process.env.PORT || 3001server.listen(port, () => {console.info(`Server started on http://localhost:${port}`)})

Now in order to connect clients to this server and start their communication, you just need to install the js library :

npm install --save magx-client

and connect it to the project :

import { Client }from "magx-client"

You can also use a direct link to use in HTML:

<script src="https://cdn.jsdelivr.net/npm/magx-client@0.7.1/dist/magx.js"> </script>

Once connected, just a few lines will allow you to configure the connection and communication with the server :

// authenticate to serverawait client.authenticate()// create or join roomconst rooms = await client.getRooms("relay")room = rooms.length? await client.joinRoom(rooms[0].id): await client.createRoom("relay")console.log("you joined room", name)// handle state patchesroom.onPatch((patch) => updateState(patch))// handle state snapshotroom.onSnapshot((snapshot) => setState(snapshot))// handle joined playersroom.onMessage("player_join", (id) => console.log("player join", id))// handle left playersroom.onMessage("player_leave", (id) => console.log("player leave", id))

A detailed example of how to build an interaction between clients and a non-authoritative server is described in the example project magx-examples

Authoritarian server

In an authoritarian server, the processing and execution of all actions affecting gameplay, applying game rules, and handling input from player-clients is done on the server side.

The client cannot make any changes to the game state himself. Instead, he sends the server exactly what he wants to do, the server processes this request, makes changes to the game state and sends the updated state to the clients.

With this approach, logic on the client is reduced to a minimum, the client becomes responsible only for rendering game state and handling player actions. The advantage of this approach is that it makes it much harder for clients to use cheating.

Designing an authoritarian server requires a description of the game state and the rules of how the player interacts with that state on the server side. In the magx server architecture, it is assumed that all logic is implemented by a room (worker). Each room is actually a separate server to which the clients connect.

Each room’s data/state is isolated and synchronized only with the room’s clients. One of the most important elements of an authoritative server is the state management system. Mosx – recommended state management system, but the magx architecture is not dependent on any system, so the choice is always up to you.

Game state description

Since all game logic must be based on state, the first thing to do is to describe it. With mosx it’s pretty easy to do this – you need to create classes for each state object type and wrap it with @mx.Object decorator, and put @mx decorator before each property you want to track state changes for synchronization with clients. Let’s look at an example of a state with a collection of players :

@mx.Objectexport class Player {@mx public x = Math.floor(Math.random() * 400)@mx public y = Math.floor(Math.random() * 400)}@mx.Objectexport class State {@mx public players = new Map<string, Player> ()public createPlayer(id: string) {this.players.set(id, new Player())}public removePlayer(id: string) {this.players.delete(id)}public movePlayer(id: string, movement: any) {const player = this.players.get(id)if (!player) { return }player.x += movement.x ? movement.x * 10 : 0player.y += movement.y ? movement.y * 10 : 0}}

The only limitation to consider when designing a state is the need to use Map() instead of nested objects. Arrays and all primitive types (number, string, boolean) can be used without restrictions.

Game room description

After describing the state and the logic of its change, it is necessary to describe the logic of interaction with clients. To do this, you need to create a room class and describe the necessary event handlers :

export class MosxStateRoom extends Room<State> {public createState(): any {// create statereturn new State()}public createPatchTracker(state: State) {// create state change trackerreturn Mosx.createTracker(state)}public onCreate(params: any) {console.log("MosxStateRoom created!", params)}public onMessage(client: Client, type: string, data: any) {if (type === "move") {console.log(`MosxStateRoom received message from ${client.id}`, data)this.state.movePlayer(client.id, data)}}public onJoin(client: Client, params: any) {console.log(`Player ${client.id} joined MosxStateRoom`, params)client.send("hello", "world")this.state.createPlayer(client.id)}public onLeave(client: Client) {this.state.removePlayer(client.id)}public onClose() {console.log("MosxStateRoom closed!")}}

Room registration on the server

The last step is to register the room and the server is ready.

const magx = new Server(server, params)magx.define("mosx-state", MosxStateRoom)

The complete source code of the example above is available in the repository magx-examples

Why pay attention to this project?

In conclusion, I would like to mention the advantages of the libraries used :

Mosx

  1. A simple and convenient way to describe state via @mx decorators
  2. Ability to apply @mx decorator to computable properties.
  3. Ability to create @mx.Object.private and @mx.private properties, with different access levels for different players.
  4. Dynamically change player access to private objects.
  5. Built-in mechanism for grouping objects for easy management of access rights to private data
  6. Ability to make a copy of a state for each player
  7. Full Typescript support
  8. Minimum dependencies (for libraries MobX and patchpack – for packet compression)

Magx

  1. Simple and clear API.
  2. Extensive customization options for server components :
    • Client-server communication mechanism (webockets is used by default)
    • Database for storing data of rooms and user sessions (local storage by default)
    • Server communication mechanism for scaling (the cluster communication mechanism is implemented out of the box)
    • User authentication and verification method (local sessions are used by default)
    • Ability to work in a cluster out of the box
    • Built-in rooms : lobby and relay (for non-authoritative server)
    • JS Library Magx-client to work with the server
    • Monitoring console magx-monitor for managing server rooms, their clients and viewing the status
    • Full Typescript support
    • Minimal dependencies (on notepack.io library – to reduce network traffic)

    This project is quite young and hopefully the attention of the community will help him evolve much faster.

    You may also like