fix: Multiplayer nil-reference error, global variable leak, network serialization safety, and XMLFile handle leak#2
Open
XelaNull wants to merge 1 commit intoBigFood2307:mainfrom
Conversation
…erialization safety, and XMLFile handle leak 4 targeted bug fixes identified through code review: 1. Move calcPrice() inside g_server guard in ChangeDFPDecimalSettingsEvent:run() - g_server is nil on clients, causing nil-reference error - Clients receive prices via DFPPricesChangedEvent anyway 2. Add missing 'local' keyword to fls variable in onWriteStream/onReadStream - Prevents global variable leak 3. Tag network stream prices with farmland IDs - Makes serialization order-independent - Fixes potential desync on custom maps with non-contiguous farmland IDs - Replace undefined # operator with explicit count 4. Add xmlFile:delete() after xmlFile:save() in saveSettingsXML - Prevents XMLFile handle leak on every game save Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Companion PR to our translations contribution. While working through your code for that, we spotted a few bugs — mostly multiplayer-related — and wanted to help fix them.
Full disclosure: These fixes were developed with AI assistance (Claude Code by Anthropic). A human developer reviewed and verified each change. Every fix was identified through line-by-line code review against the source. Singleplayer loading was verified (no Lua errors), but multiplayer-specific behavior was not runtime-tested.
4 targeted fixes, each with detailed inline comments explaining the why behind the change. No functionality changes, no refactoring, no style opinions — just bug fixes.
onWriteStream/onReadStreamFix 1: Multiplayer Client Error (changeDFPDecimalSettingsEvent.lua)
The bug: When any player changes a decimal setting (e.g., MinGreed slider) in multiplayer, all OTHER clients hit a nil-reference error. We identified this through code review — we haven't tested the actual multiplayer behavior, so we can't say for certain whether this causes a client disconnect, a logged error, or a crash. But the code path is clear:
The error path (from code review):
Why it's wrong regardless of severity: Even if the GIANTS engine catches this error gracefully,
calcPrice()on clients is redundant work — clients already receive updated prices viaDFPPricesChangedEvent(whichcalcPrice()broadcasts from the server). The call shouldn't be there.The fix: Move
calcPrice()inside theg_server ~= nilguard. This also matches the pattern already used inChangeDFPCheckSettingsEvent:run(), which correctly does NOT callcalcPrice().Note: Your mod already has the perfect solution —
DynamicFieldPrices:onSettingsChanged()(line 110) wrapscalcPrice()in anisServerguard. It's just never called!Fix 2: Global Variable Leak (DynamicFieldPrices.lua)
The bug: Lines 28 and 35 assign
fls = self.farmlandManager.farmlandswithout thelocalkeyword, creating a global variable. Lines 43 and 52 in the same file correctly uselocal fls— so this is clearly an oversight, not a style choice.The risk: Any other mod using a global named
flswould collide. In singleplayer this is harmless in practice, but it's a one-word fix.Fix 3: Network Serialization Safety (DynamicFieldPrices.lua + DFPPricesChangedEvent.lua)
The issue: The network code writes and reads farmland prices using
pairs()iteration, which does not guarantee order in Lua. Additionally,DFPPricesChangedEventuses the#(length) operator on the prices table, which returns undefined results for tables with non-sequential keys.When it matters: On vanilla FS25 maps, farmland IDs are contiguous (1, 2, 3, ..., N), so
pairs()happens to iterate in order and#returns the correct count. But on custom maps where farmland IDs might have gaps (e.g., {1, 2, 5, 10}), prices could be assigned to wrong fields or the stream could desync.The fix: Tag each price with its farmland ID in the stream. Instead of writing prices in whatever order
pairs()gives us and hoping the reader iterates in the same order, we write(farmlandId, price)pairs. The reader maps each price back to the correct farmland by ID. This is order-independent and works regardless of farmland ID layout.Bandwidth impact: Adds one
int32per farmland per sync (about 320 extra bytes on an 80-field map). Negligible — this only fires once on player join and once per in-game day.Fix 4: XMLFile Handle Leak (DFPSettings.lua)
The bug:
saveSettingsXML()creates an XMLFile handle withXMLFile.create()and callsxmlFile:save(), but never callsxmlFile:delete()to release the handle. TheloadSettingsXML()function at line 193 correctly callsxmlFile:delete()— the save function just missed it.The risk: Each game save (manual or auto) leaks one XML handle. Over a long play session this accumulates. One-line fix.
What We Didn't Change
We intentionally left these alone — they're code style choices, not bugs:
print("Day passed!")debug statements (your call whether to gate these behindDFPSettings.debug)updateSettingglobal function in DFPSettings.lua (it works correctly despite missinglocal— each closure captures the right values at assignment time)We've also submitted a separate translations PR adding all 21 missing languages (bringing you to 26/26 complete coverage).
— Claude & Samantha
🤖 Generated with Claude Code (Claude is the AI, Samantha is our AI project-manager persona) — reviewed and verified by a human developer