ET
ETc|Custom Lua Mod for N!tmod
v1.4
Wolfenstein: Enemy Territory
1. Overview

ETc|Custom is a modular Lua framework for Wolfenstein: Enemy Territory running on N!tmod. It extends the stock gameplay and administration with quality-of-life features and guard rails for public clan servers. You are allowed to remove the etc from all files. You can modify what you want. You even can tell others its yours.

Main Feature Blocks

  • Custom health, regeneration and ammo for human players.
  • Time-based bot control with persistent on/off state.
  • Public rules + internal member rules with persistent acceptance tracking.
  • XP control tools: /addxp and /setxp for allowed admins.
  • Configurable ClanTag protection (rename or kick tag stealers).
  • Admin password / login layer on top of dangerous shrubbot commands.
  • Ingame donation list via /donate.
  • Modular help system: /cmds + /h <command>.
  • Central debug and command logging, viewable ingame by /logs.

Goals

  • Keep Lua code modular and easy to extend.
  • Make rule enforcement automatic and persistent via flat-files.
  • Improve security for critical admin commands via /etclogin.
  • Remain compatible with typical N!tmod ET public servers.
Scope: The mod does not replace N!tmod shrubbot or anti-cheat functionality. It builds on top of it, focusing on rules, convenience and additional protections.
2. Requirements
  • Wolfenstein: Enemy Territory (ET 2.60b or ETLegacy recommended).
  • N!tmod with Lua support enabled.
  • File system write access to:
    • nitmod/luas/etc_custom/
    • nitmod/luas/etc_custom/logs/
    • nitmod/luas/etc_custom/db/
Note: If your host mounts the game directory as read-only, the mod cannot write DB or log files and most persistent features will not work.
3. File & Folder Structure

3.1 Directory layout

<fs_homepath>/
  nitmod/
    luas/
      etc_custom/
        mod_main.lua        (entry point)
        config.lua          (central configuration)
        core.lua            (core hooks and shared state)
        regen.lua           (health regeneration)
        commands.lua        (toggle commands & public commands)
        rules.lua           (rules & acceptance system)
        botcontrol.lua      (time-based bot control)
        xp.lua              (XP tools /addxp /setxp)
        help.lua            (help system /cmds /h)
        tag.lua             (ClanTag protection)
        rconpm.lua          (RCON private messages: m <slot|name> <msg>)
        logs.lua            (/logs viewer for debug.log & commands.log)
        donate.lua          (/donate โ€“ ingame donation list)
        adminpassword.lua   (/etclogin, /etclogout & command protection)

        db/
          etcrules.db       (rule acceptance tracking)
          botcontrol.db     (timed botcontrol on/off state)
          adminlogin.db     (persistent AdminPassword login state)

        logs/
          debug.log         (debug messages)
          commands.log      (command usage + important actions)

        donation_list.txt   (data source for /donate)

3.2 Loading via N!tmod

Add the Lua entry point to your N!tmod configuration, for example in nitmod.cfg or your main server.cfg:

// Load ETc|Custom Lua
set lua_modules "luas/etc_custom/mod_main.lua"

On server start you should see a console line similar to:

[ETc|Custom] Version: 1.4 Loaded
4. Configuration (config.lua)

config.lua is where you configure nearly everything: logging behaviour, health & ammo values, rule levels, bot schedule, ClanTag protection and admin passwords.

4.1 Logging configuration

Modname = "ETc|Custom"
Version = "1.4"

ENABLE_DEBUG_LOG    = false   -- set to false in production
ENABLE_COMMANDS_LOG = true
LOG_DIR_MODE        = "keep"  -- reserved for log maintenance strategies
  • debug.log receives internal messages via logDebug().
  • commands.log receives structured admin actions via logCommand().

4.2 Health, regen & ammo

et.MAX_HEALTH      = 175      -- custom max health on spawn
et.REGEN_AMOUNT    = 2        -- HP per regen tick
et.REGEN_INTERVAL  = 1000     -- milliseconds between ticks
et.REGEN_START     = 156      -- minimum health where regen starts
et.COMBAT_COOLDOWN = 5000     -- ms without combat before regen

et.MAX_AMMO_MP40     = 500
et.MAX_AMMO_THOMPSON = 500

These values are only active if the corresponding CVars are enabled: etc_customhealth and etc_regen for health-related features, etc_customammo for ammo.

4.3 Rules & member levels

-- Level range that counts as "member"
et.minLvL = 7
et.maxLvL = 999

-- Admin levels allowed to use admin commands
allowedAdminLevels = {
  [10]  = true,
  [11]  = true,
  [999] = true
}

Members within [minLvL, maxLvL] are required to:

  • Read member rules via /etcrules.
  • Confirm them via /accept.
  • Only then they can join a team (otherwise forced to spectator).

All rule acceptance data is stored in:

rulesDBPath = "nitmod/luas/etc_custom/db/etcrules.db"

4.4 Bot schedule

BotSchedule = {
  { from = 0,  to = 2,  bots = 8  },
  { from = 2,  to = 4,  bots = 32 },
  { from = 4,  to = 8,  bots = 30 },
  { from = 8,  to = 10, bots = 20 },
  { from = 10, to = 18, bots = 14 },
  { from = 18, to = 24, bots = 8  }
}

DefaultBotCount = 8

botControlFile = "nitmod/luas/etc_custom/db/botcontrol.db"

The schedule uses the serverโ€™s local time (0โ€“23 hours). When BotControlEnabled is on, the script regularly sets: bot maxbots <bots> based on this table.

4.5 ClanTag protection

ClanTagProtection = {
  enabled        = true,
  tags           = { "ETc|", "ETo|", "ETe|" },
  minLevel       = 7,          -- exempt players with level >= minLevel
  maxWarnings    = 2,
  interval       = 120,        -- seconds between checks
  mode           = "rename",   -- or "kick"
  warningMessage = "^1Warning:^7 Please remove the protected clantag: %s",
  renameNotice   = "^3You have been renamed for using protected clantag. %s",
  kickMessage    = "Protected clantag %s used. You have been kicked."
}

See section 9 for detailed behaviour.

4.6 Admin password configuration

AdminPassword = {
  passwords = {
        [0]   = "password1",
        [1]   = "password2",
        [2]   = "password3",
        [3]   = "password4",
        [4]   = "password5",
        [5]   = "password6",
        [6]   = "password7",
        [7]   = "password8",
        [8]   = "password9",
        [9]   = "password10",
        [10]  = "password11",
        [11]  = "password12",
        [999] = "password13"
  },

  authTimeout = 0,   -- 0 = no timeout (active until disconnect or /etclogout)
  blockAfter  = 3,
  blockTime   = 300,
  kickAfter   = 10,

      protectedCmds = {
        ["setlevel"]   = true,
        ["setleve"]    = true,
        ["setlev"]     = true,
        ["setle"]      = true,
        ["setl"]       = true,
        ["ban"]        = true,
        ["unban"]      = true,
        ["unba"]       = true,
        ["resetxp"]    = true,
        ["resetx"]     = true,
        ["reset"]      = true,
        ["levlist"]    = true,
        ["levlis"]     = true,
        ["levli"]      = true,
        ["levl"]       = true,
        ["levinfo"]    = true,
        ["levinf"]     = true,
        ["levin"]      = true,
        ["levi"]       = true,
        ["levedit"]    = true,
        ["levedi"]     = true,
        ["leved"]      = true,
        ["leve"]       = true,
        ["banguid"]    = true,
        ["bangui"]     = true,
        ["bangu"]      = true,
        ["bang"]       = true,
        ["useredit"]   = true,
        ["useredi"]    = true,
        ["usered"]     = true,
        ["usere"]      = true,
        ["levadd"]     = true,
        ["levad"]      = true,
        ["leva"]       = true,
        ["levdelete"]  = true,
        ["levdelet"]   = true,
        ["levdele"]    = true,
        ["levdel"]     = true,
        ["levde"]      = true,
        ["levd"]       = true,
        ["userdelete"] = true,
        ["userdelet"]  = true,
        ["userdele"]   = true,
        ["userdel"]    = true,
        ["userde"]     = true,
        ["userd"]      = true,
        ["dbsave"]     = true,
        ["dbsav"]      = true,
        ["dbsa"]       = true,
        ["dbs"]        = true,
        ["db"]         = true,
        ["delrecords"] = true,
        ["delrecord"]  = true,
        ["delrecor"]   = true,
        ["delreco"]    = true,
        ["delrec"]     = true,
        ["delre"]      = true,
        ["delr"]       = true,
        ["del"]        = true,
        ["del_bot_xp"] = true,
        ["del_bot_x"]  = true,
        ["del_bot_"]   = true,
        ["del_bot"]    = true,
        ["del_bo"]     = true,
        ["del_b"]      = true,
        ["del_"]       = true,
        ["rcon"]       = true,
        ["rco"]        = true,
        ["rc"]         = true,
        ["devmap"]     = true,
        ["devma"]      = true,
        ["devm"]       = true,
        ["dev"]        = true,
        ["readconfig"] = true,
        ["readconfi"]  = true,
        ["readconf"]   = true,
        ["readcon"]    = true,
        ["readco"]     = true,
        ["readc"]      = true,
        ["read"]       = true,
        ["rea"]        = true
    },

    sayOnlyCmds = {
        ["levinfo"]    = true,
        ["levinf"]     = true,
        ["levin"]      = true,
        ["levi"]       = true,
        ["levlist"]    = true,
        ["levlis"]     = true,
        ["levli"]      = true,
        ["levl"]       = true
    }
}

Protected commands require a valid /etclogin <password> and the correct level password. Based on authTimeout, the login can persist until disconnect or expire automatically. Persistent login state is stored in adminlogin.db.

4.7 Persistent feature CVars (server.cfg)

To keep the feature toggles persistent across server restarts, set the following CVars in your main server.cfg (or any config that is executed on every boot):

// ETc|Custom persistent feature toggles
set etc_customhealth  "1"   // 1 = enable custom spawn health
set etc_customammo    "1"   // 1 = enable custom ammo
set etc_regen         "1"   // 1 = enable health regeneration
set etc_rules         "1"   // 1 = enable /rules
set etc_website       "1"   // 1 = enable /website
set etc_etcrules      "1"   // 1 = enable /etcrules (member rules)
set etc_notifyrules   "1"   // 1 = enable member rule reminder on join

The mod reads these CVars on start inside mod_main.lua, applies them to the internal flags (USE_CUSTOM_HEALTH, USE_CUSTOM_AMMO, etc.) and writes them back once to ensure they are defined.

5. Core Hooks & Game Flow

core.lua provides the central ET hook implementation and shared state. regen.lua attaches regeneration and combat delay logic on top.

5.1 Shared state

  • lastRegen[client] โ€“ last regen tick time (ms).
  • lastCombat[client] โ€“ last damage time (ms) as attacker.
  • clientIsBot[client] โ€“ flag to exclude bots from custom logic.
  • rulesNotified[client] โ€“ whether a member has seen the reminder.

5.2 Member rule notification

In Core_ClientBegin, for non-bots in the member level range:

  • Show center-print reminder to read /etcrules.
  • Show console text with the same information.
  • Only once per map per player (tracked via rulesNotified).

5.3 Custom spawn health and ammo

In Core_ClientSpawn (non-bots):

  • If USE_CUSTOM_HEALTH:
    • Health is set to et.MAX_HEALTH.
  • If USE_CUSTOM_AMMO:
    • Ammo for MP40/Thompson is set according to config values.
  • Some static ammo tweaks are applied (e.g. grenades / specific slots).

5.4 Regeneration logic (regen.lua)

Regen_RunFrame(levelTime):

  • Skips regeneration if ENABLE_REGEN is false.
  • For each non-bot, non-spectator:
    • If time since last regen โ‰ฅ REGEN_INTERVAL and
    • time since last combat โ‰ฅ COMBAT_COOLDOWN and
    • REGEN_START โ‰ค health < MAX_HEALTH โ†’ add REGEN_AMOUNT HP.

Regen_ClientDamage(taker, attacker):

  • Updates lastCombat[attacker] for valid player indices.
  • Used to block regen while the player is actively in combat.
6. Rules & Acceptance System

The rules system enforces a โ€œread and accept firstโ€ flow for members before they can join a team. It uses a persistent flat-file database: etcrules.db.

6.1 Database format

<NGUID>|<PlayerName>|<flag>

flag = 0  -> rules viewed, not accepted
flag = 1  -> rules fully accepted

On Rules_InitGame, all entries are loaded into:

  • acceptedRead[nguid] โ€“ player has viewed /etcrules at least once.
  • acceptedPlayers[nguid] โ€“ player has accepted the rules.

6.2 Blocking team join

Rules_ClientUserinfoChanged(clientNum):

  • Checks shrubbot level. If within [et.minLvL, et.maxLvL]:
  • If rules are not both read and accepted:
    • Force the client to spectator (team = 3).
    • Show center-print explaining they must run /etcrules and /accept.

6.3 Player commands

/etcrules Show member rules & mark as read
  • Only available to players in the member level range.
  • Prints all member rules from etcrules table.
  • Marks acceptedRead[nguid] = true and writes an entry to etcrules.db if none existed (flag 0).
/accept Confirm member rules
  • Only available to member level range.
  • Requires the player to have run /etcrules first.
  • Updates etcrules.db with flag 1 for their NGUID.
  • Sets acceptedPlayers[nguid] = true.
  • If already accepted, the player is informed.
/rules Public server rules
  • Available to everybody if USE_RULES is enabled.
  • Prints the general rule set from the rules table.

6.4 Admin rule tools

All restricted to allowedAdminLevels:

  • /addaccept <player> โ€“ mark player as accepted.
    • Target can be slot, name fragment or DB-backed name fragment.
    • No argument โ†’ applies to yourself.
    • If already accepted, the admin is informed and no duplicate entry is created.
  • /forgetaccept <player> โ€“ reset acceptance.
    • Clears flags and sets database entry to flag = 0 if present.
    • If there is no entry, or already reset, a message explains this.
  • /checkaccept <player> โ€“ status overview.
    • Works on online players and DB-only entries.
    • Shows Read: yes/no and Accepted: yes/no.
    • No argument โ†’ checks your own status.
7. Admin Commands & Features

7.1 Feature toggles (admin)

All restricted to allowedAdminLevels:

/customhealth Toggle custom spawn health
  • Toggles CVar etc_customhealth.
  • Controls whether et.MAX_HEALTH is applied to human players on spawn.
  • State persists via server CVars.
/customammo Toggle custom ammo
  • Toggles CVar etc_customammo.
  • Controls whether configured ammo values are applied on spawn.
/regen Toggle health regeneration
  • Toggles CVar etc_regen.
  • Enables/disables the regeneration logic in regen.lua.
/notifierules Toggle member rule reminders
  • Toggles CVar etc_notifyrules.
  • Controls whether members get a reminder to read /etcrules when joining.

7.2 XP Tools

  • /addxp <id|name> <amount>
    • Adds XP across all 7 skills.
    • Amount is distributed evenly, remainder spread over first skills.
    • Valid range: 1โ€“5,000,000.
  • /setxp <id|name> <amount>
    • Sets total XP across all 7 skills to the given amount.
    • Existing XP is overwritten (mode = โ€œsetโ€).
Protection: XP commands cannot target bots, and they cannot modify players with equal or higher admin level.

7.3 Log viewer

The /logs command (admin only) allows viewing the debug.log and commands.log from inside the game.

/logs [debug|commands] [1-30]
  • No first argument โ†’ show from both logs.
  • debug โ†’ only debug.log.
  • commands โ†’ only commands.log.
  • Line count defaults to 5, max 30.

Use /h logs ingame for an explanation targeted at players/admins.

8. Time-Based Bot Control

The bot control module dynamically adapts bot maxbots based on the time of day. This helps keep the server active when population is low, and less crowded when real players are online.

8.1 How it works

  • On et_InitGame:
    • Reads botcontrol.db to know if BotControl is enabled.
    • If disabled, applies DefaultBotCount once.
  • In BotControl_RunFrame:
    • Every 60 seconds:
      • Read current hour (os.date("%H")).
      • Find matching schedule entry.
      • Execute bot maxbots <bots>.

8.2 Admin toggle: /botcontrol

/botcontrol (admin only) toggles the entire system on/off and stores the setting in botcontrol.db (1/0).

Tip: Use a more conservative schedule during peak hours and more bots during night hours to keep the server attractive around the clock.
9. ClanTag Protection

The ClanTag protection module prevents non-members from using protected tags like ETc|, even when combined with color codes.

9.1 Detection

  • Runs every ClanTagProtection.interval seconds.
  • Skips players with shrubbot level โ‰ฅ minLevel.
  • For others:
    • Strips ET color codes and checks if the plain name contains one of the tags.

9.2 Warnings & actions

  • First maxWarnings detections:
    • Show a center warning using warningMessage.
    • Play a referee sound.
  • After that:
    • If mode = "rename":
      • Remove only the tag portion from the visible name (keeping colors).
      • Apply the new name and show the renameNotice.
    • If mode = "kick":
      • Kick the player with a message based on kickMessage.
10. Admin Password Layer

The AdminPassword module introduces an additional login layer above shrubbot, focusing on high-risk commands such as !setlevel, !ban, !unban, !rcon, and similar.

10.1 Login & logout

  • /etclogin <password>
    • Checks if the player has a valid NGUID and level.
    • Looks up the expected password for that level.
    • On match:
      • Marks the user as logged in (runtime + in adminlogin.db).
      • Resets failed attempt counters.
      • Informs the user that login was successful.
      • If already logged in, the user is informed instead of silently re-logging.
  • /etclogout
    • Clears login state for this player/NGUID (runtime and in adminlogin.db).
    • Protected commands will again be blocked until next login.

10.2 Protected shrubbot commands

When a player types a command like !setlevel in chat, adminpassword.lua:

  • Checks if the command name is listed in protectedCmds.
  • If not logged in:
    • Shows a warning that /etclogin is required.
    • Does not execute the command.
  • If logged in:
    • Rebuilds the full chat command including arguments.
    • Executes it server-side.
    • Confirms execution in a private chat to the admin.

10.3 Blocking & kicks on wrong passwords

  • After blockAfter failed attempts in a row:
    • Player is temporarily blocked for blockTime seconds.
  • After kickAfter total failed attempts:
    • Player is kicked from the server.
  • All attempts are logged with name, IP, MAC (if available) and NGUID.

10.4 Chat masking

To prevent accidental exposure of level passwords:

  • AdminPassword_ClientSay scans say messages for:
    • /etclogin <password> patterns.
    • Known password strings from AdminPassword.passwords.
  • Any such occurrence is replaced with ****** before storing/logging.

10.5 Why this protection really matters

The AdminPassword module adds a second factor: even if someone steals the n_key, they still need the level-specific password that only trusted admins know. Without this extra password, all protected commands are blocked.

10.6 adminlogin.db โ€“ persistent login state

To make sure that login state survives map changes, the module stores authenticated admins in adminlogin.db. This file links NGUID and level with a simple โ€œlogged inโ€ flag and optional timestamps. When the map restarts, the module reloads the file, so admins do not have to re-enter their password every round (unless they explicitly use /etclogout, or you change the configuration).

11. Ingame Help System

The help system exposes a simple, discoverable interface so players and admins can look up commands ingame without external documentation.

11.1 /cmds โ€“ list available commands

  • Lists only commands relevant to the current player:
    • Public Commands โ€“ everyone sees these.
    • Member Commands โ€“ only for et.minLvL..et.maxLvL.
    • Admin Commands โ€“ only for allowedAdminLevels.
  • Each entry shows a short description (e.g. /rules โ€“ Show general rules).

11.2 /h <command> โ€“ detailed help

  • Example: /h addxp, /h logs, /h etclogin.
  • Shows a longer usage block, including:
    • Parameters.
    • Examples.
    • Notes and access requirements.
  • Respects access:
    • If a player has no access to a command, help is also denied.
12. Ingame Donation List

/donate gives players a quick overview of recent donations as a text-only list, suitable for console output.

12.1 Data source

  • Reads donation_list.txt from the etc_custom directory.
  • Typical line format:
    15 EUR SomeNickname 11/24
    50 EUR AnotherDonor 12/03
  • The script:
    • Parses amount, name and date.
    • Prints them in responsive columns with ET color codes.

12.2 Output structure

  • ASCII ETc| logo header.
  • A progress bar based on fixed current / goal values (adjust in code).
  • Formatted donation rows per line.
Note: The donation system is intentionally simple (flat text file), because the ET engine has no direct MySQL integration. More advanced automation can update the text file from external scripts or your website backend.
13. Rcon Private Messages

rconpm.lua adds a tiny helper for server operators to send private messages to players via the console or RCON.

13.1 Usage

m <slot|name> <message>
  • slot โ€“ numeric client slot ID.
  • name โ€“ name fragment (color codes stripped for matching).

If a slot is valid and in use, the message is sent only to that player. If a name fragment is given:

  • All matching players are listed in the server console.
  • The message is sent to each of them.

Messages appear in the recipient chat as:

^1[^7Rcon PM^1]^7:^O <message>
14. Best Practices & Tips
  • Disable debug logging on live servers
    • Set ENABLE_DEBUG_LOG = false to reduce disk I/O.
    • Enable it temporarily when debugging specific issues.
  • Use /logs wisely
    • Check debug.log during development or when something behaves oddly.
    • Inspect commands.log to review admin activity and security-related events.
  • Keep ClanTagProtection in rename mode first
    • Start with mode = "rename" to avoid aggressive kicks.
    • Switch to "kick" only if you really need that behaviour.
  • Maintain strong admin passwords
    • Use unique, non-trivial passwords per level.
    • Only share them via secure, private channels (e.g. Discord DMs).
  • Backup your flat-file DBs regularly
    • etcrules.db โ€“ member rule acceptance history.
    • botcontrol.db โ€“ state of the timed bot system.
    • adminlogin.db โ€“ persistent login states.
    • donation_list.txt โ€“ donors and amounts.
  • Combine with your website / Discord
    • Link /website and /donate text to your existing web pages.
    • Use external scripts (PHP/Python) to update donation_list.txt.
Summary: ETc|Custom is designed to be a โ€œdrop-inโ€ enhancement layer for N!tmod servers: you keep your existing N!tmod configuration, and use this mod on top for rules, automation and additional protections. All behaviour is driven by config.lua and flat-files, so you always know exactly what the server is doing.
15. Command Reference

Quick overview of all commands provided or modified by the mod. Access is still restricted by shrubbot levels and configuration (see sections above).

Commands
Command Type Access Description
/rules Public All players Show general server rules.
/website Public All players Show server website / Discord info.
/donate Public All players Show ingame donation list from donation_list.txt.
/etcrules Member Level 7โ€“999 Display internal member rules and mark them as โ€œreadโ€.
/accept Member Level 7โ€“999 Confirm member rules; required before joining a team as member.
/cmds Helper All players List commands available to your level (public/member/admin separated).
/h <command> Helper All players Show detailed help for a command (usage, examples, notes).
/customhealth Admin toggle Allowed levels Toggle custom spawn health (CVar etc_customhealth).
/customammo Admin toggle Allowed levels Toggle custom ammo on spawn (CVar etc_customammo).
/regen Admin toggle Allowed levels Toggle health regeneration (CVar etc_regen).
/notifierules Admin toggle Allowed levels Toggle member rule reminder messages (CVar etc_notifyrules).
/botcontrol Admin toggle Allowed levels Enable/disable time-based bot system (stored in botcontrol.db).
/addaccept [<player>] Admin Allowed levels Mark a player (or yourself) as rules-accepted in etcrules.db.
/forgetaccept [<player>] Admin Allowed levels Reset rule acceptance state for a player.
/checkaccept [<player>] Admin Allowed levels Show read/accept status for a player (online or DB-only).
/addxp <id|name> <amount> Admin Allowed levels Add XP across all 7 skills (1โ€“5,000,000, no bots, no higher/equal level).
/setxp <id|name> <amount> Admin Allowed levels Set total XP across all 7 skills to amount (1โ€“5,000,000).
/logs [debug|commands] [1โ€“30] Admin Allowed levels Show last lines from debug.log and/or commands.log.
/etclogin <password> Security Valid level + NGUID Authenticate for protected !-commands (second factor on top of n_key).
/etclogout Security Logged-in admins Clear login state and remove access to protected commands.
m <slot|name> <message> RCON Server console / RCON Send a private message to one or multiple players (via rconpm.lua).
!setlevel, !ban, !unban, ... Protected Admins with /etclogin High-risk shrubbot commands like !setlevel, !ban, !unban, !resetxp, !levlist, !levinfo, !levedit, !banguid, !useredit, !levadd, !levdelete, !userdelete, !dbsave, !delrecords, !del_bot_xp, !rcon, !devmap, !readconfig. All of them require a successful /etclogin when listed in AdminPassword.protectedCmds.
16. Mod File Preview

This section lets you preview the Lua scripts and flat-file databases directly from the web server. For this to work, upload the etc_custom directory from your mod package next to this PHP file, like:

Files
Lua scripts
DB & data files
Logs (optional)
Currently viewing: โ€“ no file selected โ€“
Preview of mod-files
// Select a file above to preview its contents here.

// Hint: make sure the etc_custom folder is deployed next to this PHP.