M MY Multiplayer: Wiki

Modules and import

How to split a resource's Lua code into modules under modules/ and reuse them across MY Multiplayer (MYMP) resources using import.

In MY Multiplayer (MYMP), a module is a .lua file inside a resource's modules/ folder. It does not need to be listed in meta.xml: the server discovers every module automatically, compiles each one whenever the resource starts and sends shared and client modules to players along with the resource.

cart.luaclient only · name ui/cart
main.luaserver only · name main
counter.luashared · name counter
money.luashared · name money

Where each module runs

  • modules/server/: runs on the server only and is never sent to players.
  • modules/client/: runs on the client only.
  • Anywhere else inside modules/: shared (available on both sides).

Module naming and resolution

A module's name is its relative path inside modules/, without .lua and without a leading server/ or client/.

File Module name Side
modules/money.lua money Shared
modules/server/main.lua main Server
modules/client/ui/cart.lua ui/cart Client
  • Side precedence: if a side has its own module with the same name as a shared one, that side's module wins.
  • Default main module: import "@shop" is shorthand for import "@shop/main".

Sharing code by returning a table

The clearest pattern is to gather exported functions and values into a local table and return it. The caller receives that table from import.

modules/money.lua:

local money = {}

function money.format(value)
    return "$" .. value
end

return money

Importing script:

local money = import "@shop/money"

print(money.format(25))

Anything declared local inside the module stays private to it. A module with no return makes import return true.

Sharing code through globals

Globals defined by a module are copied into the importing resource's environment without leaking anywhere else: import hands over only the globals the module defined.

modules/money.lua:

function formatMoney(value)
    return "$" .. value
end

TAX = 0.1

Importing script:

import "@shop/money"

print(formatMoney(25), TAX)

Selecting specific globals

Passing a table of names before the module path imports only those listed globals. If the module does not define one of them, import raises an error.

import { "formatMoney" } "@shop/money"

print(formatMoney(25))
print(TAX)

Here formatMoney is imported while TAX is not: the second print outputs nil.

Single execution per importing resource

A module runs only once inside each resource that imports it. Importing it again within the same resource returns the cached result, so state kept inside the module is shared across that resource's scripts.

modules/counter.lua:

local count = 0
local counter = {}

function counter.add()
    count = count + 1
    return count
end

return counter

Within the same resource:

local a = import "@shop/counter"
local b = import "@shop/counter"

print(a == b)
print(a.add())
print(b.add())

This prints true, 1 and 2 because a and b reference the same table. Another resource that imports @shop/counter runs the module in its own Lua state and keeps an independent count.

Because a module runs inside the importer's state, global variables such as resourceRoot, as well as any events and timers the module creates, belong to that importing resource. When imported by shop, this module attaches the handler to shop's resourceRoot:

addEvent("onShopBuy", true)

addEventHandler("onShopBuy", resourceRoot, function(item)
    print(getPlayerName(client) .. " bought " .. item)
end)

Importing from another resource

local accounts = import "@accounts/api"

addEventHandler("onPlayerJoin", root, function()
    accounts.load(source)
end)
  • On the server: if the accounts resource is not running, import starts it first.
  • On the client: the target resource must already be loaded on that client.

Errors raised by import

Message Cause
import: "shop/money" is not a module name such as "@resource" or "@resource/module" The module specifier does not start with @.
import: there is no resource called shop On the server, no resource exists with that name.
import: shop is not loaded on this client On a client, the target resource has not been loaded yet.
import: shop has no module "money" The resource has no module with that name.
import: @shop/main is client-only The module only exists on the other side (here, client-only).
import: @shop/money does not compile: … The module file has a Lua syntax error.
import: @shop/money is imported again while it runs (an import cycle) Circular import: two modules import each other during startup.
import: @shop/money defines no "TAXES" A name in the { … } list is not a global defined by the file.