Skip to content

Resources

Resources group server Lua scripts, shared code, client scripts, and package metadata. Current GMPC resource loading is declarative: config.toml chooses resources and their order, while each resource.toml chooses server scripts and their order.

resources/
  economy/
    resource.toml
    shared/
      constants.lua
    server/
      database.lua
      main.lua
    client/
      main.lua
      ui.lua

A directory without resource.toml is skipped during discovery. A resource with invalid metadata is discovered as inactive and cannot be selected in the server configuration.

Selecting Resources

The resources array in the server's config.toml is the authoritative load order:

resources = [
  "database",
  "economy",
  "gameplay"
]

Only listed resources are packaged and loaded. Directory names do not determine startup order, and an active but unlisted resource does nothing. If a listed resource is missing, inactive, or invalid, server startup fails rather than silently continuing with a partial game mode.

resource.toml

Field Required Meaning
version yes Non-empty package version. Change it when players must receive a changed client package.
active yes Whether the resource may be selected. Selecting a resource with active = false prevents server startup.
scripts yes Ordered list of server-side .lua files to execute. An empty array is valid.
author no Author shown in client-resource metadata.
description no Short description shown in client-resource metadata.
version = "1.2.0"
active = true
author = "GMPC Team"
description = "Economy and trading"

scripts = [
  "shared/constants.lua",
  "server/database.lua",
  "server/main.lua"
]

Every script path must be relative, end in .lua, stay below shared/ or server/, and contain no .. segment. Files may be nested. They run exactly in array order; GMPC no longer scans either directory for server entry points.

The distinction between the two directories remains important:

Directory Server execution Client packaging
server/ Only when listed in scripts Never packaged. Put secrets and authoritative-only code here.
shared/ Only when listed in scripts Every .lua file is recursively included in the client package.
client/ Never executed by the server Every .lua file is recursively included in the client package.

The scripts array controls only server execution. It does not restrict what the packager sends from shared/, so a shared file must not contain credentials or other server-only data.

Client Packages

For each configured resource containing Lua files under client/ or shared/, the server compiles those files to stripped Lua bytecode, creates a ZIP-based .pak, and writes a manifest under public/. The manifest records archive and per-file SHA-256 hashes. The client verifies those hashes before executing code; a corrupt or mismatched package stops the connection flow.

client/main.lua is the only automatic client entry point. Other packaged files must be loaded from it with require. A package without client/main.lua can still be downloaded, but it executes no client entry point.

Configured resource order is preserved when packages are announced and loaded by the client. This makes dependencies predictable, but a resource should still fail clearly when a required earlier resource is unavailable.

Client require

Each client resource has an isolated module cache. require("ui.scoreboard") normalizes the name to ui/scoreboard and searches in this order:

Order Path
1 client/<module>.luac
2 client/<module>.lua
3 shared/<module>.luac
4 shared/<module>.lua
5 <module>.luac
6 <module>.lua

A missing module, syntax error, or runtime error fails resource startup and disconnects the client. Keep client/main.lua focused on assembling modules so the log identifies failures close to their source.

Lifecycle

Server scripts may each define onResourceStart and onResourceStop. Start hooks run in declared scripts order after every script has loaded. Stop hooks run in reverse order. Resource-owned timers and event handlers are removed during unload.

Client entry points and required modules can also define resource lifecycle hooks. After every configured client resource has started, GMPC emits onInit once. During unload it emits onExit first, then stops resources in reverse resource order and runs each resource's stop hooks in reverse capture order.

Timers created through setTimer are associated with the current server resource and are cleaned up when that resource unloads.

Exports

A server resource exposes functions by assigning an exports table:

exports = {
  giveCoins = function(playerId, amount)
    -- authoritative implementation
  end
}

The Lua state also provides a global resource-export proxy. Defining the local resource's exports table shadows that proxy, so retain it first when the same resource also consumes another resource:

local resourceExports = exports

exports = {
  rewardPlayer = function(playerId)
    local economy = resourceExports.economy
    if economy and economy.giveCoins then
      economy.giveCoins(playerId, 10)
    end
  end
}

A missing resource, export table, or exported member evaluates to nil. Check it before calling unless the dependency is guaranteed by your configured resource order.