State
On Nasdara servers, the attachment list of ONE lock slot on a rebuildable house
(Land_House_*) doubles on every world load. The slot name string is written to
storage_N/data/building_001.bin once per entry, so the file reaches gigabyte size
within hours.
The entities are not in the world. With 67 million lock entries declared in the
file, the server process used 1.2 GB of RAM and reported 3200 server FPS. Millions
of live lock entities would not run at that cost. The duplication therefore happens
during serialization, not in the live world.
There is no script side to it at all. Verified against scripts.pbo:
- BaseBuildingBase.OnStoreSave writes four values: m_SyncParts01, m_SyncParts02,
m_SyncParts03, m_HasBase
- Fence.OnStoreSave writes m_GateState and m_IsOpened
- The rebuildable houses (Land_House_1M1 .. Land_House_3S2) have NO OnStoreSave
and NO OnStoreLoad at all. Their class bodies are empty stubs:
class Land_House_1M1 : BuildingSuper {
override void OnDebugSpawn() { //TODO: spawn house rebuilded }
};
Across the whole rebuildable area there are zero OnStoreSave and zero OnStoreLoad
overrides, and no ctx.Write anywhere in the game writes a slot name into
persistence. The duplication is entirely inside the engine's attachment
serialization.
MEASURED ON TWO INDEPENDENT SERVERS
Server A:
- affected slot: Att_CombinationLock3_Metal
- entries per run: 2^24 = 16,777,216
- runs in file: 4
- peak building_001.bin: 1,815 MB
- affected object: x=7435.6 y=262.8 z=8582.2
- material slots present in the record: RB_LvL1_Brick
- lock on the object: Att_CodeLock2_Metal plus a battery
Server B:
- affected slot: Att_CombinationLock1_Wood
- entries per run: 2^18 growing to 2^24
- runs in file: 4
- peak building_001.bin: 3,457 MB
- affected object: x=9495.2 y=218.8 z=9775.7
- material slots present in the record: RB_LvL1_Nail
- lock on the object: Att_CodeLock1_Metal plus a battery
The run length is always an exact power of two. Note that the slot which bloats is
a COMBINATION lock slot, while the lock actually attached to the object is a CODE
lock - two different slot families.
GROWTH RATE
From the rotating snapshots in storage_3/backup on server B:
434.82 MB (14:38) -> 1730.84 MB (16:36) = x3.98
1730.84 MB (19:52) -> 3456.91 MB (20:42) = x2.00
From 29.8 MB to failure took about four hours.
THE FILE IS IRREVERSIBLY CORRUPTED AT 2 GiB
This is visible in the snapshots, not inferred:
snapshots 005-007 434.82 MB _EOF present
snapshots 008-011, 000-002 1730.84 MB _EOF present
snapshots 003, 004 3456.91 MB _EOF MISSING
All three working copies (.bin, .001, .002) stopped at the very same byte count,
3,624,836,792, and none of them has an _EOF marker. Past 2 GiB the write hits a
ceiling, the end marker is never written, and every object that would have been
written after the damaged one is missing from the file. On server A this cost
players their built structures.
SEPARATE HAZARD: THE SHUTDOWN SAVE
The save the server writes when shutting down stops INSIDE the oversized list,
with no _EOF marker, and everything that would follow the damaged object is
absent. The file looks small and healthy - 51.67 MB instead of 1815 MB on server A.
An admin who "restores from backup" using it loses almost the whole map.
THE PROBLEM SPREADS
After a manual repair, server A was left with one slot holding 8 legitimate
entries. After 15 hours and roughly 7 world loads, six slots on NEW objects were
affected, with 247,796 / 68,612 / 24,576 / 4,100 / 3,072 / 68 entries.
A CONTRAST IN THE CODE ITSELF
ConstructionBase declares MAX_MATERIAL_PILES = 64, commented "safety cap for
material pile spawning". The attachment list has no such cap, which is how it
reaches 2^24.
We have no deterministic minimal repro - we could not identify the trigger. It
reproduces on both of our Nasdara servers on its own, with no intervention.
1. A server running Nasdara, -mod=nasdara, scheduled restart every 2 hours.
2. Players restore houses (Land_House_*) using brick and mortar.
3. A digital code lock with a 9V battery is attached to a restored house.
4. After several world loads, check the file size:
dir "...\mpmissions\<mission>\storage_N\data\building_*.bin"
A healthy building_001.bin is a few megabytes. Inside the file, look for the
repeated string Att_CombinationLock<N>_<Wood|Metal> with its 2-byte length
prefix 1a 00.
RECORD LAYOUT OF A DAMAGED OBJECT
Offsets from the 1,815 MB file, byte order little-endian:
45236 coordinates e6 5c e8 45 2f 63 83 43 e9 18 06 46
= 7435.61 / 262.77 / 8582.23
... orientation and ids
45292 uint32 00 00 00 01 = 16777216
45296 uint32 00 00 00 01 = 16777216
45300 run begins 1a 00 "Att_CombinationLock3_Metal" x 16,777,216
469807211 run ends, normal object records resume
The file carries one STORAGE_BUILDING header and one _EOF marker, so this is a
single stream and not concatenated images. The four runs sit at offsets 45300,
475871253, 951697343 and 1427523433, each preceded by its own copy of the same
object record.
WHAT REPAIRS IT
Removing the surplus entries and setting the uint32 at (run_start - 4) to 1
produces a file the server loads normally:
- server A: 1,815 MB -> 1.04 MB; the fence registry reported the same count
before and after
- server B: a 1,730.84 MB snapshot -> 2.84 MB in 26.7 seconds, with 20,590
coordinate triples preserved in the tail
A lock slot's attachment list must not grow on world load, an object record must
be written once per save, and the persistence writer needs a safety cap - as the
material piles already have with MAX_MATERIAL_PILES = 64 - instead of corrupting
the file irreversibly past 2 GiB.
- nasdara - map content, loaded as -mod=nasdara
- @KirpichTweaks - our own server-side mod, server side only, not required by
clients. It touches combination locks: the owner pops their own lock on any
dial turn, auto-unlock when the owner is nearby, and an owner registry.
The mod is not the cause, and that is verifiable three ways:
1. The two affected servers run DIFFERENT builds of that mod, one of them two
weeks older (sha256 B08D49D3... versus 21E97B28...), and both bloat identically.
2. Three of our servers on Chernarus, Livonia and Sakhal run the SAME mod on the
same restart schedule and are completely clean - every building_*.bin stays
under 1 MB.
3. The rebuildable houses have no script-side persistence at all, so a mod has
nowhere to interfere with these bytes.
FACTORS THAT ONLY COME WITH THE MAP (our data cannot separate them)
- cfgexternallocks.json - ExternalLockData, the lock brute-force protection
added in 1.30. It ships with the Nasdara missions and with none of the clean
maps:
{"locksSettings":{"protectionCountStageOne":3,"protectionCountStageTwo":1,
"protectionTime":30,"protectionResetTime":3600}}
- the rebuildable house system itself. The records of the affected objects
contain RB_LvL1_* material slots, so these are restored houses, and each
carries a digital code lock with a battery. How many lock slots such a house
declares cannot be determined from server files: the slot names we found come
from the game's global slot registry, and building configs are binarized.
What matters is that these are static map objects which were given a
Construction section in 1.30, and the game identifies them exactly that way:
if (g_Game.ConfigIsExisting("cfgVehicles " + typeName + " Construction")
&& !g_Game.IsKindOf(typeName, "BaseBuildingBase"))
Server A:
-config=serverDZ_map2.cfg -port=2402 -profiles=profiles_map2
-serverMod=@KirpichTweaks
-dologs -adminlog -freezecheck
-mod=nasdara
-cpuCount=8
Server B:
-config=serverDZ_n6.cfg -port=2802 -profiles=profiles_n6
-serverMod=@KirpichTweaks
-dologs -adminlog -freezecheck
-mod=nasdara
Clean servers used for comparison run the same -serverMod=@KirpichTweaks on
Chernarus (no -mod), Livonia (no -mod) and Sakhal (-mod=sakhal).
Activity
You are not signed in. Please sign in to see more details and to reply.
State