# YALootBoxes — Polish, Verify, and Extend Logging **Project root:** `P:\YALootBoxes` **Context:** This is a DayZ server mod (Enforce Script). It was originally scaffolded under the name `LootboxSpawner` and has since been renamed to `YALootBoxes`. The mod spawns lockable lootboxes at config-defined locations; players need a specific held item to attempt opening one via a hold-to-open action; success unlocks+fills the box, failure rolls one random negative effect. All settings live in four JSON files under `$profile:YALootBoxes\`. This is a **source-level review and polish pass**. There is no DayZ Server/Tools setup available yet, so do not attempt to pack a PBO or boot a server — focus on static correctness, consistency, and completeness of the Enforce Script source and JSON schemas. Work through the phases below **in order**. Do not skip ahead. At the end of each phase, summarize what you found/changed before moving to the next. --- ## Phase 0 — Orientation 1. Recursively list all files under `P:\YALootBoxes`. 2. Read every `.c`, `.cpp`, and `.json` file you find. 3. Build a mental (or written, in scratch notes) map of: mod folder structure vs. the expected layout below, and flag any structural differences immediately. **Expected layout:** ``` YALootBoxes/ ├── config.cpp ├── Prefix.cpp └── scripts/ └── 4_World/ ├── YALootBoxes_Config.c ├── YALootBoxes_Lootbox.c ├── YALootBoxes_ActionOpen.c └── YALootBoxes_Manager.c ``` (File names above assume the rename also touched filenames — verify and report actual names found, don't assume.) --- ## Phase 1 — Rename Audit (the user says rename "should" be complete — verify, don't trust) Search the **entire** project for every leftover instance of the old naming scheme. Check ALL of: - [ ] String `LootboxSpawner` (any casing) — in `.c`, `.cpp`, `.json`, comments, file names, folder names - [ ] String `LB_` prefix on classes/functions/constants (e.g. `LB_Log`, `LB_MainConfig`, `LB_ConfigLoader`, `LB_BoxTypeDef`, `LB_FailEffect`, `LB_ActionOpenLootbox`, `LB_ApplyRandomFailEffect`, etc.) — decide on and apply a **consistent new prefix** (suggest `YLB_` or `YALB_`) if these were meant to be renamed too - [ ] `CfgPatches` / `CfgMods` class name (`LootboxSpawner`) in `config.cpp` - [ ] `CfgVehicles` class names (`LootboxSpawner_Crate_Military`, `_Medical`, `_Industrial`) — these **must** exactly match the `className` fields inside `box_types.json`, so check both sides together - [ ] `$profile:LootboxSpawner\` path constant — should become `$profile:YALootBoxes\` - [ ] Any `displayName` strings, log prefixes (`Print("[LootboxSpawner] ...")`), or code comments referencing the old name - [ ] `Prefix.cpp` content itself **Action:** Fix every occurrence found. Keep a running checklist in your response of exactly what was renamed, file by file, so the user can review the diff. Do not silently rename things — call out each change. **Cross-check after renaming:** confirm `box_types.json`'s `className` values still exactly match the `CfgVehicles` class names in `config.cpp` post-rename (this is the #1 way these mods silently fail to spawn anything — a one-character mismatch and the server just won't spawn the object, often without an obvious error). --- ## Phase 2 — Structural / Completeness Review Go file by file and check for the following. This codebase was written without ever being compiled against the real DayZ SDK headers, so treat it as a first draft that needs adversarial review, not a finished product. ### General Enforce Script correctness - [ ] Confirm every class that's referenced is actually defined somewhere (no dangling references to types that don't exist, e.g. double check `ContinuousInteractActionInput`, `ActionContinuousBase`, `CCINone`, `CCTObject`, `UAMaxDistances` are real DayZ API symbols available in the modding SDK — if you have access to DayZ SDK docs/headers via web search, verify; otherwise flag as "needs verification against SDK" rather than assuming correctness) - [ ] Check `RegisterNetSyncVariableBool` usage — confirm sync var registration pattern matches how `ContainerObject`/`ItemBase` subclasses normally do it in DayZ mods - [ ] Check for null-safety: every place a JSON-loaded reference (`m_TypeDef`, `LB_ConfigLoader.MainConfig`, etc.) is used, confirm there's a null check or a guaranteed-non-null path - [ ] Check `GetActions()` override signature/pattern is correct for hooking custom actions onto a `ContainerObject`-derived class — this was a best-effort implementation and deserves scrutiny - [ ] Verify `eAgents` enum members used (`SALMONELLA`, `INFLUENZA`, `CHOLERA`, `BRAIN`, `WOUND_AGENT`) are the real DayZ agent enum names - [ ] Verify `GetBleedingManagerServer()`, `GetHealthDamageManager()`, `SetFracture()`, `InsertAgent()` are real PlayerBase/HealthDamageManager API calls and used with correct signatures ### Config loading - [ ] Confirm `JsonFileLoader.JsonLoadFile` / `JsonSaveFile` usage matches real DayZ API (class name and static usage pattern) - [ ] Confirm the `map>` (or renamed equivalent) is a supported Enforce Script generic — DayZ's Enforce Script has known limitations with nested generic containers in JSON deserialization. **This is a likely problem area** — flag clearly if you believe `JsonFileLoader` cannot deserialize a `map>` directly. If so, propose a fix: e.g. restructure `loot_lists.json` as an array of `{type, entries}` objects instead of a map, since flat arrays deserialize far more reliably in Enforce Script's JSON layer. - [ ] Check that `EnsureDirectoryExists` / `MakeDirectory` calls match the real API (case, return type) - [ ] Confirm default-object construction (e.g. `LB_MainConfig()` constructor) actually runs before `JsonLoadFile` overwrites fields, so a partially-specified JSON file doesn't leave other fields zero/null ### Lifecycle & manager logic - [ ] Re-derive the despawn timer logic by hand against the user's original spec: locked boxes despawn/respawn after N minutes (config-driven per box type) **even if never opened**; opened boxes despawn N minutes after becoming unlocked. Confirm `HasExpiredUnopened` / `HasExpiredAfterOpening` actually implement this without overlap or gaps. - [ ] Check for a race/edge case: what happens if a box is mid-open-action (channeling) at the exact moment the lifecycle tick deletes it for expiring? Flag this as a known edge case if not already handled, and propose a minimal guard (e.g. skip despawn-delete if an action is actively targeting it, or just accept and document the rare edge case). - [ ] Check `CallLater(..., true)` repeating-timer usage is correct DayZ API usage (3rd param = repeat flag, confirm order of args). - [ ] Verify location pool logic (`m_FreeLocationNames`, `m_LocationInUse`) doesn't have an off-by-one or duplicate-assignment bug when `SpawnOneAtRandomFreeLocation` recurses on failure. ### Action / interaction logic - [ ] Confirm the "fixed channel time, instant roll, but failure can interrupt early" requirement is actually satisfiable with `ActionContinuousBase` + `OnFinishProgressServer` — i.e. confirm that bailing out early (releasing the button) does NOT call `OnFinishProgressServer` and does NOT roll anything. Flag if the current code doesn't clearly guarantee this. - [ ] Confirm the proximity message system (manager's `TickProximityMessages`) and the action's "show prompt when holding right item" are not redundant/conflicting — i.e. one always shows "Requires: X", the other only enables the action — and that nothing in the action class duplicates the proximity broadcast. - [ ] Verify `RPCSingleParam` / `ERPCs.RPC_USER_ACTION_MESSAGE` is a real, appropriate way to send a HUD text message to a single client in DayZ's API. If this is not correct, propose the standard pattern used by DayZ mods for "send toast/notification to one player" (often a custom RPC type registered in `Init.c`/`Missions`, since `RPC_USER_ACTION_MESSAGE` may not exist or may not behave as a generic toast). ### Config/JSON schema consistency - [ ] Confirm every field referenced in `.c` files has a matching field (same name, same casing) in the example JSON files, and vice versa. - [ ] Confirm `failEffects[].chance` semantics are documented clearly as "weight" not "independent probability" (since the code does a weighted pick among effects, not N independent rolls) — fix any comment/naming that implies otherwise. Produce a written list of every issue found in this phase, categorized as: - 🔴 **Will likely fail to compile or run** (must fix) - 🟡 **Will likely behave incorrectly at runtime** (should fix) - 🟢 **Style/maintainability nit** (optional) Fix all 🔴 and 🟡 items. For 🟢 items, list them but ask before changing anything purely stylistic. --- ## Phase 3 — Add Debug Logging Levels Extend the logging system to support **NONE / ERROR / WARN / INFO / DEBUG / VERBOSE** levels, replacing the current single `EnableDebugLogging: bool`. ### Requirements: 1. In the main config class, replace `EnableDebugLogging` (bool) with `DebugLogLevel` (string or int — your call, but document which and why; string is more admin-friendly for hand-editing JSON, int is cheaper to compare at runtime — consider storing as string in JSON but parsing to an int enum at load time for fast comparisons). 2. Define the level ordering: `NONE(0) < ERROR(1) < WARN(2) < INFO(3) < DEBUG(4) < VERBOSE(5)`. A message at level X is printed only if `DebugLogLevel >= X`. 3. Replace the single `LB_Log(string msg)` (or renamed equivalent) helper with level-specific variants, e.g.: - `Log_Error(string msg)` - `Log_Warn(string msg)` - `Log_Info(string msg)` - `Log_Debug(string msg)` - `Log_Verbose(string msg)` Each should prefix output appropriately, e.g. `[YALootBoxes][ERROR] ...`, and route to both `Print()` (.log/.rpt via engine default) and, if straightforward, `ErrorEx()` for ERROR-level messages specifically (DayZ's standard pattern for messages that should be prominent in the `.RPT` file) — verify `ErrorEx` is real API before using it; if uncertain, just use `Print()` consistently and note the limitation. 4. Go through **every existing log call in the codebase** and reclassify it to the correct level based on its actual content: - Config file missing / failed to parse / unknown class referenced → `ERROR` or `WARN` depending on whether it's recoverable - "Spawned box at location X", "Manager initialized" → `INFO` - Per-tick lifecycle summaries ("removed N, active now M") → `DEBUG` - Per-player proximity message sends, per-effect-roll details → `VERBOSE` 5. Update the example `main_config.json` to use the new field with a sensible default (`INFO` recommended for normal server operation). 6. Update the default-constructor fallback value to match. Add a short section to the project's README (create one at `P:\YALootBoxes\README.md` if it doesn't exist) documenting: - What each log level is meant to be used for - The config field name and JSON example - A reminder that VERBOSE will be noisy and is meant for active debugging sessions only, not production --- ## Phase 4 — Final Consistency Pass 1. Re-read every file once more, top to bottom, now that renaming and logging changes have landed, specifically checking that: - No file still calls the old single-arg `LB_Log(...)` (or its renamed equivalent) — every call site should now use a leveled function - No JSON file and `.c` file have drifted out of sync on field names again as a side effect of your edits - All four JSON example files are valid JSON (mentally parse them, or note if you want to validate via a tool) 2. Produce a final summary report with these sections: - **Renames applied** (file-by-file list) - **Bugs fixed** (🔴 and 🟡 items from Phase 2, with before/after description) - **Known limitations / things that need real DayZ SDK to verify** (be explicit — this matters since nothing has been compiled yet) - **Logging system** (what changed, default level, example config) - **Suggested next steps** for the user once they have DayZ Tools available (e.g. "pack PBO, boot test server, spawn near a military crate empty-handed, confirm proximity message text, pick up a crowbar, confirm action prompt appears, hold to open, confirm one of the two outcomes fires correctly") --- ## Ground rules throughout - **Do not invent DayZ API behavior you're not confident about.** If you can't verify something against real SDK docs/headers, say so explicitly in the summary rather than presenting a guess as fact. This is real game-server code the user intends to run. - **Do not silently delete functionality.** If you think something should be removed (e.g. a redundant message path), propose it and explain why before removing it, in your phase summary. - **Keep commit-sized changes traceable** — if this is a git repo, make small logical commits per phase rather than one giant diff; if it's not a git repo, mention that initializing one would make this kind of iterative work much easier to review going forward. - This is **review + polish + logging**, not a redesign. Don't change the core mechanics (proximity message always shown, fixed-channel hold-to-open, weighted single fail-effect roll, post-open despawn timer) unless you find them to be actually broken as currently spec'd — flag concerns rather than unilaterally redesigning.