Objetivo: tener un ciclo de trabajo rápido (editar → ver el resultado en segundos) y saber dónde mirar cuando algo pasa. Todo lo demás del curso se apoya en esto.
1. Las tres carpetas que importan (Mac)
| Carpeta | Qué hay | Para qué la usas |
|---|---|---|
~/Library/Application Support/Steam/steamapps/common/ProjectZomboid/Project Zomboid.app/Contents/Java/ | El juego: projectzomboid.jar (el motor en Java) y media/ (scripts, Lua, texturas, modelos) | Solo lectura. Es la "documentación" real del juego |
~/Zomboid/ | Todo lo del usuario: console.txt, Logs/, Saves/, Workshop/, mods/, Lua/ | Logs, partidas de prueba, archivos que escriben los mods |
~/Zomboid/Workshop/<Mod>/ | Cada mod, con la forma que espera Steam | Donde trabajas |
La forma de un mod en Build 42
~/Zomboid/Workshop/CursoLab/
├── preview.png ← imagen de Steam (256×256)
├── workshop.txt ← datos de la página de Steam (lo llena el uploader)
└── Contents/mods/CursoLab/
├── common/ ← (opcional) assets que sirven para cualquier versión
└── 42/ ← lo que carga Build 42
├── mod.info
├── poster.png
└── media/
├── lua/{shared,client,server}/
├── scripts/
└── textures/mod.info mínimo (copiado de Emote Bubbles, uno de nuestros mods):
name=Curso Lab
id=CursoLab
description=Mod de práctica del curso.
poster=poster.png
versionMin=42.0.0
author=elp4nsho
modversion=0.1.0id tiene que ser igual al nombre de la carpeta dentro de Contents/mods/. Es el error número uno cuando un mod "no aparece".
2. Modo debug
En Steam: clic derecho en Project Zomboid → Propiedades → Opciones de lanzamiento → -debug.
Qué te da (sacado de media/lua/shared/keyBinding.lua, sección [Debug]):
| Tecla | Qué hace |
|---|---|
F11 | Lua debugger: lista de archivos Lua cargados, botón Reload, breakpoints, inspector de objetos |
` `` (tecla a la izquierda del 1) | Consola Lua: ejecuta Lua en vivo dentro del juego |
| Íconos a la izquierda de la pantalla | Menú debug: teletransporte, spawnear ítems y vehículos, horda, clima, ver loot |
Los errores de Lua aparecen en pantalla (contador rojo abajo a la derecha) apenas ocurren. En el modo normal pasan en silencio y solo quedan en el log.
3. Logs
~/Zomboid/console.txt: el log de la sesión actual. Se reescribe cada vez que abres el juego.~/Zomboid/Logs/: una carpeta por sesión con logs más completos (*_DebugLog.txt). Si el juego se cae cargando, el error de verdad suele estar aquí.
Ten console.txt siempre abierto en una terminal:
tail -f ~/Zomboid/console.txt | grep --line-buffered -E "CursoLab|ERROR|Exception|STACK"4. VS Code que entienda el juego
- Instala la extensión Lua (sumneko / LuaLS).
- En la configuración del workspace donde trabajas (
.vscode/settings.json):
{
"Lua.runtime.version": "Lua 5.1",
"Lua.workspace.library": ["~/Zomboid/Workshop/_juego/lua"],
"Lua.diagnostics.globals": ["Events", "getPlayer", "getText", "ISContextMenu", "ISBaseTimedAction"]
}Con _juego/lua como librería, Ir a la definición (F12) sobre ISBaseTimedAction te lleva al código del juego. Las funciones que vienen de Java (como getPlayer()) no tienen código Lua: esas se ven en el módulo 07.
5. El ciclo rápido
| Cambiaste… | Para verlo |
|---|---|
Un .lua de client/ o shared/ | F11 → busca el archivo → Reload. Ojo: vuelve a correr el archivo completo, así que los Events.X.Add(...) se registran dos veces (lo arreglamos en el ejercicio 3) |
Un .lua de server/ en una partida local | Igual que arriba |
Un script .txt (ítems, recetas, modelos) | Salir al menú y volver a cargar la partida. Si no basta, reiniciar el juego |
| Una textura o un modelo | Reiniciar el juego (las texturas quedan en caché) |
mod.info | Reiniciar el juego |
Ten una partida de pruebas dedicada: modo sandbox, sin zombis, con el mod activado. Así cargas en segundos.
Ejercicios
Ejercicio 0.1 · CursoLab existe
Crea el mod CursoLab con la estructura de arriba y este archivo:
42/media/lua/shared/CursoLab_Core.lua
CursoLab = CursoLab or {}
CursoLab.VERSION = "0.1.0"
function CursoLab.log(...)
local parts = {}
for i = 1, select("#", ...) do
parts[#parts + 1] = tostring(select(i, ...))
end
print("[CursoLab] " .. table.concat(parts, " "))
end
CursoLab.log("archivo cargado")
Events.OnGameStart.Add(function() CursoLab.log("OnGameStart") end)Listo cuando: el mod aparece en la lista de mods, y en console.txt ves [CursoLab] archivo cargado y, al entrar a la partida, [CursoLab] OnGameStart.
Pregunta: ¿el primer mensaje sale antes o después del menú principal? ¿Por qué? (Pista: ¿cuándo se cargan los archivos de shared/?)
Ejercicio 0.2 · La consola Lua
En una partida con -debug, abre la consola (` ``) y ejecuta:
CursoLab.log("hola desde la consola")
print(getPlayer():getFullName())
print(getPlayer():getX(), getPlayer():getY(), getPlayer():getZ())Listo cuando: ves tu nombre y tus coordenadas. Acabas de llamar a métodos Java de un objeto IsoPlayer desde Lua. En el módulo 07 vemos cómo funciona eso por dentro.
Ejercicio 0.3 · Recargar sin duplicar
- Cambia el mensaje de
OnGameStarty recarga el archivo con F11 → Reload. - Agrega un
Events.EveryOneMinute.Add(...)que escriba un mensaje. Recarga dos veces. ¿Cuántas veces sale el mensaje por minuto? - Arréglalo para que recargar no duplique el handler.
Listo cuando: puedes recargar el archivo diez veces y el mensaje sale una vez por minuto.
Una solución
if CursoLab.onMinute then
Events.EveryOneMinute.Remove(CursoLab.onMinute)
end
function CursoLab.onMinute()
CursoLab.log("pasó un minuto")
end
Events.EveryOneMinute.Add(CursoLab.onMinute)Events.X.Remove necesita la misma función que pasaste a Add. Por eso guardamos la referencia en la tabla del mod, que sobrevive a la recarga. Con una función anónima no hay cómo sacarla.
Desafío 0
Haz un script de shell lab.sh que:
- copie un
.luaque editaste a la carpeta del mod (si trabajas en otra carpeta), y - muestre solo las líneas nuevas de
console.txtque contenganCursoLabo un error, con color.
No hay solución: es tu herramienta, hazla a tu gusto.
Siguiente: 01 · Anatomía del juego y de un mod