MAEngine

Events

Server-side event system for local and remote communication

Events (Server)

The server-side Events system handles local script communication and receiving/sending messages to clients.

Security

Always validate data received from clients. Never trust client data for prices, damage values, or any game logic.


Local Events

Local events allow different scripts or parts of your code to communicate within the server.

-- Subscribe to local event
Events.Subscribe("GameStarted", function()
    Log("Game has started!")
end)

Events.Subscribe("PlayerScored", function(player_id, points)
    Log("Player " .. player_id .. " scored " .. points .. " points")
end)

-- Fire local event
Events.Call("GameStarted")
Events.Call("PlayerScored", 123, 10)

-- Unsubscribe
Events.Unsubscribe("GameStarted")
MethodDescription
Events.Subscribe(name, callback)Subscribe to local event
Events.Call(name, ...)Fire local event with arguments
Events.Unsubscribe(name)Remove all subscriptions

Remote Events (Server → Client)

Receiving from Clients

Events.SubscribeRemote("ClientAction", function(player, data)
    Log("Player " .. player:GetId() .. " sent: " .. tostring(data.action))

    -- Validate and handle
    if data.action == "buy_item" then
        -- Server validates price, inventory, etc.
    end
end)

Prop

Type

Sending to Clients

-- Send to specific player
Events.CallRemote("UpdateScore", player, { score = 100 })

-- Broadcast to all players
Events.BroadcastRemote("GameAnnouncement", {
    message = "Round starting!",
    countdown = 10
})

Prop

Type


API Summary

MethodDescription
Events.Subscribe(name, callback)Subscribe to local event
Events.Call(name, ...)Fire local event
Events.Unsubscribe(name)Remove subscriptions
Events.SubscribeRemote(name, callback)Receive from clients
Events.CallRemote(name, player, data)Send to specific player
Events.BroadcastRemote(name, data)Send to all players

Examples

Game State Broadcast

local game_state = {
    phase = "lobby",
    time_remaining = 0,
    scores = {}
}

function broadcast_state()
    Events.BroadcastRemote("GameStateUpdate", game_state)
end

Events.SubscribeRemote("ReadyUp", function(player, data)
    Log("Player " .. player:GetId() .. " is ready")
end)

Events.Subscribe("PhaseChange", function(new_phase)
    game_state.phase = new_phase
    broadcast_state()
end)

-- Start game
Events.Call("PhaseChange", "playing")

Purchase Validation

Events.SubscribeRemote("PurchaseRequest", function(player, data)
    local item_id = data.item_id
    local price = get_item_price(item_id)  -- Server-side price lookup

    local gold = player:GetPrivateValue("gold") or 0
    if gold >= price then
        player:SetPrivateValue("gold", gold - price)
        give_item_to_player(player, item_id)

        Events.CallRemote("PurchaseSuccess", player, {
            item_id = item_id,
            new_gold = gold - price
        })
    else
        Events.CallRemote("PurchaseFailed", player, {
            reason = "Insufficient gold"
        })
    end
end)

Damage System

Events.SubscribeRemote("PlayerAttack", function(player, data)
    local target = Entity.GetByID(data.target_id)
    if not target or not target:IsValid() then return end

    -- Validate attack (range, cooldown, etc.)
    local attacker = player:GetControlledCharacter()
    if not attacker then return end

    local distance = attacker:GetPosition():Distance(target:GetPosition())
    if distance > 500 then return end  -- Too far

    -- Apply damage (server authoritative)
    local health = target:GetValue("health") or 100
    health = health - 25  -- Server decides damage, not client
    target:SetValue("health", health)

    -- Notify attacker
    Events.CallRemote("DamageDealt", player, {
        target_id = data.target_id,
        damage = 25
    })
end)

On this page