Desarrollo de servidor para juegos multijugador con nodejs y magx

Muchos desarrolladores están comenzando a desarrollar un servidor en línea multiusuario basado en la biblioteca socket.io . Esta biblioteca hace que sea muy sencillo implementar el intercambio de datos entre el cliente y el servidor en tiempo real, pero aún hay que pensar e implementar toda la lógica y la interfaz de la interacción servidor-cliente, así como la arquitectura para escalar y optimizar el tráfico.







Quiero hablar sobre la biblioteca magx , con la cual no se puede pensar en el componente de red (comunicación entre el servidor y los clientes), sino que se concentra inmediatamente en desarrollar la lógica del juego y la interfaz de usuario del cliente.







A la hora de diseñar la arquitectura de un juego multijugador, se suelen considerar 2 enfoques: con un servidor autoritario y un no autoritario (cliente autoritario). Ambos enfoques son compatibles con la biblioteca magx. Comencemos con un enfoque más simple: no autoritario.







Servidor no autorizado



Su esencia es que el servidor no controla los resultados de entrada de cada jugador. Los clientes rastrean de forma independiente las acciones ingresadas por el jugador y la lógica del juego localmente, después de lo cual envían el resultado de una determinada acción al servidor. Después de eso, el servidor sincroniza todas las acciones realizadas con el estado del juego de otros clientes.







Es más fácil de implementar desde un punto de vista arquitectónico, ya que el servidor solo es responsable de la comunicación entre clientes, sin hacer ningún cálculo adicional que los clientes hagan.







Usando la biblioteca magx, dicho servidor se puede implementar en solo unas pocas líneas de código:







import * as http from "http"
import { Server, RelayRoom } from "magx"

const server = http.createServer()
const magx = new Server(server)

magx.define("relay", RelayRoom)

// start server
const port = process.env.PORT || 3001
server.listen(port, () => {
  console.info(`Server started on http://localhost:${port}`)
})
      
      





Ahora, para conectar clientes a este servidor e iniciar su interacción, simplemente instale la biblioteca js:







npm install --save magx-client









y conectarlo al proyecto:







import { Client } from "magx-client"
      
      





Alternativamente, puede utilizar un enlace directo para el uso de HTML:







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





Después de conectarse, solo unas pocas líneas le permitirán configurar la conexión y la interacción con el servidor:







// authenticate to server
await client.authenticate()

// create or join room
const 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 patches
room.onPatch((patch) => updateState(patch))

// handle state snapshot
room.onSnapshot((snapshot) => setState(snapshot))

// handle joined players
room.onMessage("player_join", (id) => console.log("player join", id))

// handle left players
room.onMessage("player_leave", (id) => console.log("player leave", id))
      
      





En el ejemplo correspondiente del proyecto magx-examples se describe un ejemplo detallado de cómo construir la interacción entre clientes y un servidor no autorizado .







Servidor autorizado



, , - .







- . , , , , .







, . , (cheating).







. magx , (worker). , .







/ . — . Mosx — , magx - , .









, . mosx — @mx.Object, , @mx. :







@mx.Object
export class Player {
  @mx public x = Math.floor(Math.random() * 400)
  @mx public y = Math.floor(Math.random() * 400)
}

@mx.Object
export 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 : 0
    player.y += movement.y ? movement.y * 10 : 0
  }
}
      
      





, — Map() . (Array) (number, string, boolean) .









. :







export class MosxStateRoom extends Room<State> {

  public createState(): any {
    // create state
    return new State()
  }

  public createPatchTracker(state: State) {
    // create state change tracker
    return 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!")
  }
}
      
      







— .







const magx = new Server(server, params)

magx.define("mosx-state", MosxStateRoom)
      
      





magx-examples.







?



:







Mosx



  1. @mx
  2. @mx .
  3. @mx.Object.private @mx.private, .
  4. .
  5. Typescript
  6. ( MobX patchpack — )


Magx



  1. API.
  2. :

    • ( webockets)
    • ( )
    • ( )
    • ( )
  3. Salas integradas: vestíbulo y relé (para servidor no autorizado)
  4. Biblioteca JS Magx-client para trabajar con el servidor
  5. Consola de monitoreo magx-monitor para administrar salas de servidores, sus clientes y estado de visualización
  6. Soporte completo de TypeScript
  7. Dependencias mínimas (para la biblioteca notepack.io - para reducir el tráfico de red)


Este proyecto es bastante joven y espero que la atención de la comunidad lo ayude a desarrollarse mucho más rápido.








All Articles