New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

astra-engine

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

astra-engine

game web-engine

latest
Source
npmnpm
Version
0.1.59
Version published
Weekly downloads
36
3500%
Maintainers
1
Weekly downloads
 
Created
Source

astra-engine

Что это?

astra-engine - игровой веб-движок, написанный на NodeJS и использующий модуль socket.io

Установка

npm install astra-engine

Как использовать

Запуск сервера на TypeScript:

import SocketIO from "socket.io";
import { AstraEngine, Lobby, Player } from "astra-engine";

// Наследуемся от базового класса лобби
class GameLobby extends Lobby {
  // Метод вызывается когда команда прилетает от игрока в данном лобби
  onCommand(player: Player, action: string, payload: any) {
    // Если экшен команды "ping"
    if(action === "ping") {
      // Определяем задержку между игроком и сервером, которая является разницей во времени между ними
      const ping = Date.now() - payload;
      // И посылаем игроку задержку (пинг)
      this.command(player, "pong", ping);
    }
  }
}

// Создаём сервер (может быть любым фреймворком, поддерживающим socket.io)
const io = SocketIO(3000);
// И экземпляр движка, передавая созданный socket.io сервер и класс лобби, используемый по умолчанию
const engine = new AstraEngine(io, GameLobby);

Подключение клиента на JavaScript:

// EventEmitter не обязателен, но очень полезен для упрощения обработки команд
const { EventEmitter } = require("events");
const SocketIO = require("socket.io-client");

// Создаём экземпляр EventEmitter'а
const server = new EventEmitter();

// Привязываем к нему все обрабатываемые команды
server
     // Когда игрок подключился (после аунтентификации)
    .on("player.connected", ({ playerId }) => {
      // Берём playerId из данных, пришедших от сервера (пейлода)
      console.log(`player with id ${playerId} connected!`);
      // И отправляем команду подсоединения к лобби, т.к. после подключения мы можем это сделать
      io.emit("command", "lobby.join");
     })
     // Когда мы подключились к лобби - мы можем отправлять команды непосредственно в него
    .on("lobby.joined", ({ playerId, lobbyId }) => {
      // Выводим, что мы подключились в лобби
      console.log(`player with id ${playerId} connected to lobby with id ${lobbyId}`);
      // И, с интервалом в 500 мс, посылаем текущие время серверу
      setInterval(() => io.emit("command", "ping", Date.now()), 500);
    })
    // Когда же сервер отвечает нам командой "pong"
    .on("pong", ping => {
      // Мы выводим пинг, полученный из аргумента, являющимся пришедшими данными от движка
      console.log("pong!", `ping: ${ping} ms`)
    })

// Создаём соединение, передавая в query строку username, являющейся ключём аутентификации в данный момент
// (поддержка токенов пока не реализована)
const io = SocketIO("http://localhost:3000", { query: { username: "1337player" } });
// И враппим данные о команде в наш эмиттер
io.on("command", (action, payload) => server.emit(action, payload));

Классные фичи

Состояние лобби

У каждого лобби существует два типа объекта состояния:

  • lobbyState, глобальное, единое для всех игроков
  • playerState, уникальное для каждого игрока

Оба состояния можно менять и изменения отправлять клиентам, обмениваясь данными и синхронизируя их. Например, существует игра, цель которой нажмать на кнопку и получать очки, тогда лобби будет создано следующим образом:

class GameLobby extends Lobby {
  createPlayerState = () => ({ score: 0 })
  onCommand(player: Player, action: string) {
    if(action !== "player.score") return;
    const ps = this.getPlayerState(player);
    const changes = ps.modify(s => ({ score: s.score + 1 })).apply();
    this.command(player, "player.score", changes);
  }
}

Суть проста - функция createPlayerState возвращает объект, определяющий начальное состояние каждого подключенного в лобби игрока. Если она не объявлена, то состоянию присваивается пустой объект {}.

Метод onCommand вызывается при команде, не имеющей отношения к отношения к системному взаимодействию с лобби, посылаемой игроком находящимся в данный момент в лобби. Например, игрок, посылая команду game.ping, отправит её именно в то лобби, в котором он находится в данный момент и метод onCommand вызовется, передав игрока первым аргументом player. Вторым и третьим аргументами выступают наименование команды action и дополнительные данные payload, которые игрок мог передать. Если их нет - обработчику прилетает пустой объект {}.

В методе проверяется, является ли обрабатываемая команда player.score:

if(action !== "player.score") return;

В ином случае, обработка команды завершается. Метод базового класса Lobby именуемый getPlayerState позволяет получить состояние любого игрока, находящегося (или находившегося когда-либо) в этом лобби. Для этого первым аргументом передаётся ссылка на экземпляр игрока player, в ответ возвращается экземпляр класса SyncState, позволяющий манипулировать данными состояния.

const ps = this.getPlayerState(player);

Следующим шагом необходимо изменить состояние игрока, добавив ему очки. Данная операция осуществляется методом modify в объекте состояния. В его аргумент передаётся функция, в аргументах которой находятся:

  • state, текущее состояние;
  • changes, все совершённые изменения над этим состоянием после использования modify;

Методом modify возвращается экземпляр объекта изменений, которые можно сохранить и получить, выполнив метод apply, возвращающий объект изменений, совершённых над состоянием.

const changes = ps.modify(s => ({ score: s.score + 1 })).apply();

Изменения необходимо отправить клиенту и для этой цели используется метод базового класса Lobby именуемый command, имеющий следующие аргументы:

  • player, игрок, который должен получить данные;
  • action, команда, которая придёт игроку с этими данными;
  • payload, Сам объект данных, отправляемый игроку;

Прописав метод:

this.command(player, "player.score", changes);

После вышеперечисленных операций игрок получит ответ с изменившимся состоянием, новым количеством очков, что и требовалось сделать.

Тесты

yarn test

Лицензия

MIT

FAQs

Package last updated on 09 Nov 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts