Cross → Server Registry

Server Registry

A live list of every server running your game. Call RegisterServer once at startup — the module maintains a heartbeat and removes the entry automatically when the server closes or crashes.

Cross.RegisterServer()

Cross.RegisterServer(meta?)

Register this server in the shared registry. Optionally attach any metadata table — player count, game mode, map, etc. — which is visible to GetServers() on other servers.

Starts a 30-second heartbeat to keep the entry alive (entries expire after 90 seconds). Also updates the player count automatically on PlayerAdded / PlayerRemoving. Registers a game:BindToClose handler to remove the entry on graceful shutdown.

local Cross = RoExpress.Cross

-- call once at the top of a server Script
Cross.RegisterServer({
    mode   = "pvp",
    map    = "Forest",
    ranked = true,
})

Cross.GetServers()

Cross.GetServers() → {ServerEntry}

Returns all currently registered servers as a table of ServerEntry objects. Entries that have not been refreshed within 90 seconds are expired automatically by MemoryStore.

ServerEntry

FieldTypeDescription
idstringServer's JobId (unique per server instance)
placenumberPlaceId the server is running
playersnumberCurrent player count, refreshed on join/leave
metatableMetadata passed to RegisterServer
tsnumberos.time() of the last heartbeat
local servers = Cross.GetServers()
print(#servers, "servers online")

for _, s in servers do
    print(s.id, "| players:", s.players, "| map:", s.meta.map)
end

Cross.UnregisterServer()

Cross.UnregisterServer()

Immediately remove this server from the registry and stop the heartbeat. Useful for maintenance mode or before a forced restart. The entry also removes itself automatically on server close.

-- put the server into maintenance mode
Cross.UnregisterServer()
Cross.Publish("server.maintenance", { id = Cross.ServerId() })
-- kick all players after a delay...

Cross.ServerId()

Cross.ServerId() → string

Returns this server's unique identifier — game.JobId in a live server, a generated GUID in Studio. Stable for the lifetime of the server process.

print("This server:", Cross.ServerId())

-- exclude self when routing messages to other servers
local others = {}
for _, s in Cross.GetServers() do
    if s.id ~= Cross.ServerId() then
        table.insert(others, s)
    end
end

Pattern: matchmaking server selection

local TeleportService = game:GetService("TeleportService")
local Cross           = RoExpress.Cross

local function FindBestServer(mode: string)
    local servers = Cross.GetServers()
    local best
    for _, s in servers do
        if s.meta.mode == mode and s.players < 20 then
            if not best or s.players > best.players then
                best = s   -- pick least-empty server with room
            end
        end
    end
    return best
end

local function JoinOrCreate(player: Player, mode: string)
    local server = FindBestServer(mode)
    if server then
        TeleportService:TeleportToPlaceInstance(game.PlaceId, server.id, player)
    else
        TeleportService:TeleportAsync(game.PlaceId, { player })
    end
end
Crash resilience — if a server crashes without calling UnregisterServer, its registry entry expires after 90 seconds. GetServers() called after that will not include the crashed server.

See also

← Cross  ·  Messaging | real-time events across servers  ·  Shared Memory | persistent key-value state