- Renamed code prefix LB_ -> YALB_ across all four script files - Renamed source files LootboxSpawner_*.c -> YALootBoxes_*.c - Deleted three empty 0-byte stub files (_BoxTypes/_LootLists/_SpawnLocations) - Fixed folder case scripts/4_world -> scripts/4_World to match config.cpp - Verified box_types.json className values match CfgVehicles class names Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
13 KiB
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
- Recursively list all files under
P:\YALootBoxes. - Read every
.c,.cpp, and.jsonfile you find. - 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 (suggestYLB_orYALB_) if these were meant to be renamed too CfgPatches/CfgModsclass name (LootboxSpawner) inconfig.cppCfgVehiclesclass names (LootboxSpawner_Crate_Military,_Medical,_Industrial) — these must exactly match theclassNamefields insidebox_types.json, so check both sides together$profile:LootboxSpawner\path constant — should become$profile:YALootBoxes\- Any
displayNamestrings, log prefixes (Print("[LootboxSpawner] ...")), or code comments referencing the old name Prefix.cppcontent 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,UAMaxDistancesare 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
RegisterNetSyncVariableBoolusage — confirm sync var registration pattern matches howContainerObject/ItemBasesubclasses 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 aContainerObject-derived class — this was a best-effort implementation and deserves scrutiny - Verify
eAgentsenum 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<T>.JsonLoadFile/JsonSaveFileusage matches real DayZ API (class name and static usage pattern) - Confirm the
map<string, ref array<ref LB_LootEntry>>(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 believeJsonFileLoadercannot deserialize amap<string, array<...>>directly. If so, propose a fix: e.g. restructureloot_lists.jsonas 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/MakeDirectorycalls match the real API (case, return type) - Confirm default-object construction (e.g.
LB_MainConfig()constructor) actually runs beforeJsonLoadFileoverwrites 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/HasExpiredAfterOpeningactually 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 whenSpawnOneAtRandomFreeLocationrecurses 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 callOnFinishProgressServerand 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_MESSAGEis 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 inInit.c/Missions, sinceRPC_USER_ACTION_MESSAGEmay not exist or may not behave as a generic toast).
Config/JSON schema consistency
- Confirm every field referenced in
.cfiles has a matching field (same name, same casing) in the example JSON files, and vice versa. - Confirm
failEffects[].chancesemantics 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:
-
In the main config class, replace
EnableDebugLogging(bool) withDebugLogLevel(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). -
Define the level ordering:
NONE(0) < ERROR(1) < WARN(2) < INFO(3) < DEBUG(4) < VERBOSE(5). A message at level X is printed only ifDebugLogLevel >= X. -
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 bothPrint()(.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.RPTfile) — verifyErrorExis real API before using it; if uncertain, just usePrint()consistently and note the limitation. -
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 →
ERRORorWARNdepending 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
- Config file missing / failed to parse / unknown class referenced →
-
Update the example
main_config.jsonto use the new field with a sensible default (INFOrecommended for normal server operation). -
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
- 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
.cfile 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)
- No file still calls the old single-arg
- 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.