fix(client): prevent signed overflow in world_seed generation and load
GDScript int is i64 — when randi() returns a value with bit 31 set, left-shifting by 32 sets bit 63, producing a negative i64. MessagePack encodes this as a negative integer, which Rust rmp_serde rejects when deserializing as u64, causing ~50% startup failure rate. Fix: mask bit 31 before shifting in new_game() to cap entropy at 63 bits. Also mask the sign bit in _read_seed_file() to handle save files written before this fix. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,9 +33,11 @@ func new_game() -> String:
|
||||
GameState.current_game_id = game_id
|
||||
|
||||
# #175: Generate world_seed for deterministic simulation (D-010, D-029).
|
||||
# Combines two randi() calls (u32 each) into full u64 entropy range.
|
||||
# Without this, upper 32 bits are always zero — halving the seed space.
|
||||
GameState.world_seed = (rng.randi() << 32) | rng.randi()
|
||||
# Combines two randi() calls (u32 each) into 63-bit entropy range.
|
||||
# Mask bit 31 of the upper word before shifting to prevent signed overflow:
|
||||
# GDScript int is i64 — if bit 63 is set, MessagePack encodes as negative,
|
||||
# and Rust rmp_serde rejects negative values when deserializing as u64.
|
||||
GameState.world_seed = ((rng.randi() & 0x7FFFFFFF) << 32) | rng.randi()
|
||||
|
||||
# Persist world_seed to save directory so resume_game() can restore it.
|
||||
# Without this, loaded sessions would send seed=0, breaking D-010 determinism.
|
||||
@@ -134,12 +136,14 @@ func _write_seed_file(save_path: String, seed: int) -> void:
|
||||
|
||||
|
||||
## Read world_seed from save directory. Returns 0 if file missing (legacy saves).
|
||||
## Masks the sign bit on read: save files written before the signed-overflow fix
|
||||
## may contain negative i64 values that Rust rmp_serde rejects as u64.
|
||||
func _read_seed_file(save_path: String) -> int:
|
||||
var file := FileAccess.open(save_path + "world_seed", FileAccess.READ)
|
||||
if file == null:
|
||||
push_warning("SessionManager: no seed file in %s — using seed=0 (legacy save)" % save_path)
|
||||
return 0
|
||||
return file.get_64()
|
||||
return file.get_64() & 0x7FFFFFFFFFFFFFFF
|
||||
|
||||
|
||||
func _find_newest_save(dir_path: String) -> String:
|
||||
|
||||
Reference in New Issue
Block a user