M MY Multiplayer: Wiki

Módulos e import

Cómo dividir el código Lua de un recurso en módulos dentro de modules/ y reutilizarlos en MY Multiplayer (MYMP) con import.

En MY Multiplayer (MYMP), un módulo es un archivo .lua dentro de la carpeta modules/ de un recurso. No necesita declararse en meta.xml: el servidor los descubre automáticamente, compila cada uno cada vez que inicia el recurso y envía los módulos compartidos y de cliente junto con él.

cart.luasolo en el cliente · nombre ui/cart
main.luasolo en el servidor · nombre main
counter.luacompartido · nombre counter
money.luacompartido · nombre money

Dónde se ejecuta cada módulo

  • modules/server/: se ejecuta solo en el servidor y nunca se envía a los jugadores.
  • modules/client/: se ejecuta solo en el cliente.
  • Cualquier otra ruta dentro de modules/: compartido (disponible en ambos lados).

Nombre y resolución de módulos

El nombre de un módulo es su ruta relativa dentro de modules/, sin .lua y sin el prefijo server/ o client/.

Archivo Nombre del módulo Lado
modules/money.lua money Compartido
modules/server/main.lua main Servidor
modules/client/ui/cart.lua ui/cart Cliente
  • Prioridad por lado: si un lado tiene un módulo propio con el mismo nombre que uno compartido, gana el módulo específico de ese lado.
  • Módulo predeterminado (main): import "@shop" equivale a import "@shop/main".

Compartir código devolviendo una tabla

La forma más clara de exponer código consiste en reunir lo que ofrece el módulo en una tabla local y devolverla con return. Quien llama a import recibe esa tabla.

modules/money.lua:

local money = {}

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

return money

En el script que importa:

local money = import "@shop/money"

print(money.format(25))

Todo lo declarado como local en el módulo permanece privado dentro de él. Un módulo sin return hace que import devuelva true.

Compartir código mediante globales

Las globales creadas por el módulo pasan a quien lo importó sin filtrarse a otros recursos: import entrega únicamente las globales que el módulo definió.

modules/money.lua:

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

TAX = 0.1

En el script que importa:

import "@shop/money"

print(formatMoney(25), TAX)

Elegir qué globales importar

Con una lista de nombres antes del identificador, solo llegan las globales indicadas. Si el módulo no define alguna de ellas, import lanza un error.

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

print(formatMoney(25))
print(TAX)

Aquí formatMoney existe, pero TAX no: el segundo print muestra nil.

Ejecución única y estado por recurso

Un módulo se ejecuta una sola vez en cada recurso que lo importa. Importarlo de nuevo dentro del mismo recurso devuelve el mismo resultado almacenado, por lo que el estado del módulo se comparte dentro de ese recurso.

modules/counter.lua:

local count = 0
local counter = {}

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

return counter

En el mismo recurso:

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

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

Esto imprime true, 1 y 2, ya que a y b son la misma tabla. Otro recurso que importe @shop/counter vuelve a ejecutar el módulo en su propio estado y mantiene su propia cuenta.

Como el módulo se ejecuta dentro del estado de quien lo importó, variables globales como resourceRoot, además de los eventos y timers que cree, pertenecen al recurso importador. Este módulo, importado por shop, asocia el handler al resourceRoot de shop:

addEvent("onShopBuy", true)

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

Importar desde otro recurso

local accounts = import "@accounts/api"

addEventHandler("onPlayerJoin", root, function()
    accounts.load(source)
end)
  • En el servidor: si el recurso accounts no está en ejecución, import lo inicia antes automáticamente.
  • En el cliente: el recurso de destino ya tiene que estar cargado en ese cliente.

Mensajes de error de import

Mensaje Causa
import: "shop/money" is not a module name such as "@resource" or "@resource/module" El nombre del módulo no empieza con @.
import: there is no resource called shop En el servidor, no existe un recurso con ese nombre.
import: shop is not loaded on this client En el cliente, el recurso todavía no se cargó.
import: shop has no module "money" El recurso no tiene ningún módulo con ese nombre.
import: @shop/main is client-only El módulo solo existe en el otro lado (aquí, solo en el cliente).
import: @shop/money does not compile: … El módulo contiene un error de sintaxis Lua.
import: @shop/money is imported again while it runs (an import cycle) Ciclo de importación: dos módulos se importan entre sí al iniciarse.
import: @shop/money defines no "TAXES" Un nombre de la lista { … } no corresponde a una global del módulo.