# 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.

- **Plataforma**: MY Multiplayer (MYMP) — Lua 5.4
- **Secciones**: Documentación › Primeros pasos
- **Idioma**: Español
- **URL**: https://wiki.mymp.gg/es/docs/modules

En **MY Multiplayer** (**MYMP**), un **módulo** es un archivo `.lua` dentro de la carpeta `modules/` de un [recurso](https://wiki.mymp.gg/es/docs/resources.md). 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.

```text
shop/
└── modules/
    ├── money.lua           compartido · nombre money
    ├── counter.lua         compartido · nombre counter
    ├── server/
    │   └── main.lua        solo en el servidor · nombre main
    └── client/
        └── ui/
            └── cart.lua    solo en el cliente · nombre ui/cart
```

## 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`:

```lua
local money = {}

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

return money
```

En el script que importa:

```lua
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`:

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

TAX = 0.1
```

En el script que importa:

```lua
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.

```lua
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`:

```lua
local count = 0
local counter = {}

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

return counter
```

En el mismo recurso:

```lua
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](https://wiki.mymp.gg/es/docs/globals.md) 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`:

```lua
addEvent("onShopBuy", true)

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

## Importar desde otro recurso

```lua
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. |
