Skip to content

A 2D MMO Game Engine built using the Bun runtime from the ground up

License

Notifications You must be signed in to change notification settings

Lillious-Networks/Mystika

Repository files navigation

Mystika - Game Engine

github

Note

This project is currently a work in progress

Core Development Team: Lillious, Deph0, Elyriand

Discord

Getting Started

Important

Requirements:


Database Creation:

bun setup

Running the server

- Production (MySQL)

bun production

- Development (Sqlite)

bun development
Database Setup

- Production (MySQL)

bun setup

- Development (Sqlite)

bun setup-sqlite
Unit Tests (Production Build Only)
bun test
Create Config
bun create-config
Run Docker
bun docker
Stop Docker
bun stop-docker

Production Environment Variables

Important

The below environment variables are required

Location: /.env.production

DATABASE_HOST
DATABASE_USER
DATABASE_PASSWORD
DATABASE_NAME
EMAIL_USER
EMAIL_PASSWORD
EMAIL_SERVICE
EMAIL_TEST
SQL_SSL_MODE DISABLED | ENABLED
DATABASE_ENGINE sqlite | mysql
WEBSRV_PORT
WEBSRV_PORTSSL
WEBSRV_USESSL
WEBSRV_USECERT
GOOGLE_TRANSLATE_API_KEY
WEB_SOCKET_URL
ASSET_PATH
DOMAIN
GAME_NAME
DATABASE_PORT

Client Identity

Structure
declare interface Identity {
  id: string;
  useragent: string;
}

Packets

Types
const PacketTypes: PacketType = {
  0: "PING",
  1: "PONG",
  2: "CONNECTION_COUNT",
  3: "RATE_LIMITED",
  4: "LOGIN",
  5: "LOGIN_SUCCESS",
  6: "LOGIN_FAILED",
  7: "LOAD_MAP",
  8: "TIME_SYNC",
  9: "MOVEXY",
  10: "AUTH",
  11: "LOGOUT",
  12: "DISCONNECT",
  13: "SPAWN_PLAYER",
  14: "LOAD_PLAYERS",
  15: "DISCONNECT_PLAYER",
  16: "INVENTORY",
  17: "CHAT",
  18: "STATS",
  19: "CLIENTCONFIG",
  20: "REGISTER",
  21: "TELEPORTXY",
  22: "SELECTPLAYER",
  23: "BENCHMARK",
  24: "STEALTH",
  25: "ATTACK",
  26: "PROJECTILEXY",
  27: "REVIVE",
  28: "UPDATESTATS",
  29: "TARGETCLOSEST",
  30: "AUDIO",
};
Structure
declare interface Packet {
  type: PacketType;
  data: PacketData;
  id: string | null;
  useragent: string | null;
}

Rate Limiting

Options
const RateLimitOptions: RateLimitOptions = {
  maxRequests: 2000,
  time: 2000,
  maxWindowTime: 1000,
};
Structure
declare interface RateLimitOptions {
  maxRequests: number;
  time: number;
  maxWindowTime: number;
}

Caching

import cache from '../services/cache'; // Main player cache
import assetCache from '../services/assetCache'; // Asset caching
cache.add(key: string, value: any);
assetCache.add(key: string, value: any);

Adds an item to the cache

cache.addNested(key: string, nestedKey: string, value: any);
assetCache.addNested(key: string, nestedKey: string, value: any);

Adds a nested item to the cache

cache.get(key: string)
assetCache.get(key: string)

Fetches an item from the cache

cache.remove(key: string)
assetCache.remove(key: string)

Removes an item from the cache

cache.clear();
assetCache.clear();

Clears the cache

cache.list();
assetCache.list();

Fetches all items from the cache

cache.set();
assetCache.set();

Updates an item in cache

cache.setNested();
assetCache.setNested();

Updates a nested item in cache


Events

import { Events } from "../socket/server";
events.GetOnlineCount();

Returns the amount of clients that are currently connected

events.GetOnlineData();

Returns a list that contains client connection data

events.Broadcast(packet: string);

Broadcasts a message to all connected clients

events.GetClientRequests();

Returns a list that contains client request data

events.GetRateLimitedClients();

Returns a list of rate limited clients


Listener Events

onAwake

Fires immediately after the server starts

Listener.on("onAwake", (data) => {
  console.log("Awake event emitted");
});
onStart

Fires immediately after onAwake

Listener.on("onStart", (data) => {
  console.log("Start event emitted");
});
onUpdate

Fires immediately after onStart every 60 frames

Listener.on("onUpdate", (data) => {
  console.log("Update event emitted");
});
onFixedUpdate

Fires immediately after onStart every 100ms

Listener.on("onFixedUpdate", (data) => {
  console.log("Fixed update event emitted");
});
onSave

Runs every 1 minute

Listener.on("onSave", (data) => {
  console.log("Save event emitted");
});
onConnection

Fires when a new connection is established

Listener.on("onConnection", (data) => {
  console.log(`New connection: ${data}`);
});
onDisconnect

Fires when a connection is dropped

Listener.on("onDisconnect", (data) => {
  console.log(`Disconnected: ${data}`);
});

Inventory Management

import inventory from "../systems/inventory";
Structure
declare interface InventoryItem {
  name: string;
  quantity: number;
}
inventory.add();

Add an item to player inventory

await inventory.add(username, { name: "item_name", quantity: number });
inventory.remove();

Remove an item from player inventory

await inventory.remove(username, { name: "item_name", quantity: number });
inventory.find();

Find an item from player inventory

await inventory.find(username, { name: "item_name" });
inventory.delete();

Delete an item from player inventory

await inventory.delete(username, { name: "item_name" });
inventory.get();

Fetches a player's inventory

await inventory.get(username);

Weapon Management

import weapons from "../systems/weapon";
Structure
declare interface WeaponData {
  name: string;
  damage: number;
  mana: number;
  range: number;
  quality: string;
  type: string;
  description: string;
}
weapons.add();

Adds a weapon to the weapon database

await weapons.add(weapon);
weapons.remove();

Removes a weapon to the weapon database

await weapons.remove(weapon);
weapons.find();

Fetches a weapon from the weapon database

await weapons.find(weapon);
weapons.update();

Updates a weapon in the weapon database

await weapons.update(weapon);
weapons.list();

Lists all weapons in the weapon database

await weapons.list();

Item Management

import items from "../systems/items";
Structure
declare interface Item {
  name: string;
  quality: string;
  description: string;
}
items.add();

Add an item to the item database

await items.add({ name: "item_name", quality: "item_quality", description: "item_description" });
items.remove();

Remove an item from the item database

await items.remove({ name: "item_name" });
items.list();

List all items from the item database

await items.list();
items.find();

Find an item from the item database

await items.find({ name: "item_name" });
items.update();

Updates an item in the database

await items.update(item);

Player Management

import player from "../systems/player";
Structure
declare interface Player {
  id?: string;
  name?: string;
  position?: PositionData;
  map?: string;
}
player.getLocation();

Get a player's location data

await player.getLocation({ name: username }) as LocationData | null;
player.setSessionId();

Sets a player's sessionId

await player.setSessionId(token, sessionId);
player.getSessionId();

Get a player's sessionId

await player.getSessionId(token);
player.login();

Logs a player in

await player.login("user_name, password);
player.logout();

Logs the player out by clearing the auth token

await player.logout(sessionId);
player.clearSessionId();

Clears the players session by clearing the session id

await player.clearSessionId(sessionId);
player.getUsernameBySession();

Gets a player's username by sessionId

await player.getUsernameBySession(sessionId);
player.getUsernameByToken();

Gets a player's username by authentication token

await player.getUsernameByToken(sessionId);
player.register();

Registers a new player account

await player.register(username, password, email, request);
player.findByUsername();

Finds a player by username

await player.findByUsername(username);
player.findByEmail();

Finds a player by email

await player.findByEmail(email);
player.setToken();

Assigns a player an authentication token

await player.setToken(username);
player.getEmail();

Gets a players email

await player.getEmail(sessionId);
player.returnHome();

Sets the players location to the main map at 0, 0

await player.returnHome(sessionId);
player.isOnline();

Checks if the player is currently online

await player.isOnline(username);
player.isBanned();

Checks if the player is currently banned

await player.isBanned(username);
player.getStats();

Fetches a player's stats

await player.getStats(username);
player.setStats();

Sets a player's stats

await player.setStats(username, stats);
player.getConfig();

Fetches a player's client configuration

await player.getConfig(username);
player.setConfig();

Sets a player's client configuration

await player.getConfig(session_id, stats);
player.checkIfWouldCollide();

Checks if a player would collide with a future position

await player.checkIfWouldCollide(map, position);
player.kick();

Kicks a player from the server

await player.kick(username, websocket);
player.ban();

Bans a player from the server

await player.ban(username, websocket);
player.canAttack();

Returns true if a self can attack another player

await player.canAttack(self, target, range);
player.findClosestPlayer();

Returns the closest player or null


Audio Management

import audio from "../systems/audio";
Structure
declare interface AudioData {
  name: string;
  data: Buffer;
  pitch?: number;
}
audio.list();

List all audio files in cache

audio.list() as AudioData[];
audio.get();

Fetches an audio file from cache

audio.get(name) as AudioData[];

About

A 2D MMO Game Engine built using the Bun runtime from the ground up

Resources

License

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •