MAEngine

Getting Started

Multiplayer game server toolkit with Rust core and Lua scripting

Getting Started

MAEngine is a multiplayer game server toolkit featuring:

  • Rust core for networking, ECS, and replication
  • Lua scripting for game logic (LuaJIT on server, Lua 5.4 on client)
  • QUIC transport with TLS 1.3
  • SurrealDB for persistent storage
  • Unreal Engine 5 client with WebUI support

Quick Start

Create a Server Script

-- games/my_game/Server/init.lua

Server.Subscribe("Start", function()
    Log("Server started!")
end)

Player.Subscribe("Spawn", function(player)
    local character = Character.Spawn(Vec3(0, 0, 100))
    player:Possess(character)
    player:SetValue("score", 0)
end)

Events.SubscribeRemote("PlayerAction", function(player, data)
    Log("Received action from player " .. player:GetId())
end)

Create a Client Script

-- games/my_game/Client/init.lua

-- Create HUD after brief delay
Timer.Delay(0.5, function()
    local hud = WebUI.CreateAtScale("HUD", "hud/index.html")
    hud:SetFullscreen(true)
    WebUI.ShowViewport(false)
end)

-- Bind to player value changes
local player = Client.GetLocalPlayer()
if player then
    player:BindValue("score", function(p, key, new, old)
        -- Update HUD when score changes
        Log("Score: " .. tostring(new))
    end)
end

Input.Register("Fire", "LeftMouseButton")
Input.Bind("Fire", Input.Pressed, function()
    Events.CallServer("PlayerAction", { action = "fire" })
end)

Run the Server

.\build.bat run -p core-server -- --game my_game

API Reference

Server

Client


Key Concepts

Server vs Client

MAEngine is server-authoritative. The server controls all game logic while clients handle rendering and input.

FeatureServerClient
RuntimeRust + LuaJITUE5 + Lua 5.4
AuthorityAuthoritativePredictive
DatabaseFull accessNone
EntitiesCreate/Modify/DeleteRead-only
WebUINoneFull access
InputNoneFull access
TraceNoneFull access

Event-Driven Architecture

-- Class-level events
Character.Subscribe("Spawn", function(character) end)
Player.Subscribe("Destroy", function(player) end)

-- Instance events
entity:Subscribe("OnHit", function(ent, damage) end)
entity:Fire("OnHit", 25)

Value Replication

-- Synced to all clients
entity:SetValue("health", 100)
player:SetValue("score", 50)
-- Synced only to the owning player
player:SetPrivateValue("inventory", { items = {} })
player:SetPrivateValue("secret_mission", "Find the key")
-- React to value changes
Character.BindValue("health", function(char, key, newVal, oldVal)
    if newVal <= 0 then
        char:Destroy()
    end
end)

Remote Events

-- Receive from client
Events.SubscribeRemote("PlayerAction", function(player, data)
    -- Validate and process
end)

-- Send to client
Events.CallRemote("UpdateUI", player, { score = 100 })
Events.BroadcastRemote("GameEvent", { message = "Round started!" })
-- Send to server
Events.CallServer("PlayerAction", { action = "fire" })

-- Receive from server
Events.SubscribeRemote("UpdateUI", function(data)
    hud:CallEvent("SetScore", data.score)
end)

IDE Support

Download the EmmyLua type definitions for autocomplete in VS Code or IntelliJ.


Project Structure

games/my_game/
├── Server/
│   └── init.lua      # Server-side script (authoritative)
├── Client/
│   ├── init.lua      # Client-side script (UE5)
│   └── UI/           # WebUI HTML/CSS/JS files
│       └── hud/
│           ├── index.html
│           ├── style.css
│           └── script.js
├── Shared/
│   └── constants.lua # Shared constants
└── config.toml       # Game configuration

On this page