Desenvolvimento de servidor para jogo multiplayer com nodejs e magx

Muitos desenvolvedores estão começando a desenvolver um servidor online multiusuário baseado na biblioteca socket.io . Esta biblioteca torna muito simples implementar a troca de dados entre o cliente e o servidor em tempo real, mas você ainda precisa pensar e implementar toda a lógica e interface da interação servidor-cliente, bem como a arquitetura para escalonamento e otimização de tráfego.







Eu quero falar sobre a biblioteca magx , usando a qual você não pode pensar sobre o componente de rede (comunicação entre o servidor e os clientes), mas imediatamente se concentrar no desenvolvimento da lógica do jogo e da IU do cliente.







Ao projetar a arquitetura de um jogo multiplayer, geralmente são consideradas 2 abordagens: com um servidor autoritário e um não autoritário (cliente autoritário). Ambas as abordagens são suportadas pela biblioteca magx. Vamos começar com uma abordagem mais simples - não autoritária.







Servidor não autorizado



Sua essência é que o servidor não controla os resultados de entrada de cada jogador. Os clientes rastreiam de forma independente as ações inseridas pelo jogador e a lógica do jogo localmente, após o que eles enviam o resultado de uma determinada ação para o servidor. Depois disso, o servidor sincroniza todas as ações realizadas com o estado do jogo de outros clientes.







É mais fácil de implementar do ponto de vista arquitetônico, pois o servidor é responsável apenas pela comunicação entre os clientes, sem fazer nenhum cálculo adicional que os clientes façam.







Usando a biblioteca magx, tal servidor pode ser implementado em apenas algumas linhas 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}`)
})
      
      





Agora, para conectar os clientes a este servidor e iniciar sua interação, basta instalar a biblioteca js:







npm install --save magx-client









e conecte-o ao projeto:







import { Client } from "magx-client"
      
      





Como alternativa, você pode usar um link direto para HTML:







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





Após a conexão, apenas algumas linhas permitirão que você configure a conexão e interação com o 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))
      
      





Um exemplo detalhado de como construir interação entre clientes e um servidor não autorizado é descrito no exemplo correspondente no projeto magx-examples .







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: saguão e retransmissão (para servidor não autorizado)
  4. Biblioteca cliente JS Magx para trabalhar com o servidor
  5. Monitor de console magx-monitor para gerenciamento de salas de servidores, seus clientes e visualização de status
  6. Suporte completo de texto digitado
  7. Dependências mínimas (para a biblioteca notepack.io - para reduzir o tráfego de rede)


Este projeto é muito jovem e espero que a atenção da comunidade o ajude a se desenvolver muito mais rápido.








All Articles