extends SceneTree const Clock = preload("res://world/owniverse/simulation_time.gd") var checks: int = 0 var failures: int = 0 func _initialize() -> void: call_deferred("run") func check(condition: bool, message: String) -> void: checks += 1 if not condition: failures += 1 push_error(message) func fixture(): var world = load("res://world/owniverse/owniverse.gd").new() var global: Node = root.get_node("Global") for id in global.OwniverseEntities: var entity = load("res://world/owniverse/owniverse_entity.gd").new(global.OwniverseEntities[id]) world.entities[id] = entity world.state.amount[id] = 0.0 world.state.stats.total_amount[id] = 0.0 if entity.group_as != "": world.state.amount[entity.group_as] = 0.0 world.state.stats.total_amount[entity.group_as] = 0.0 world.entities["N"].life_product = {} world.entities["N"].product_per_year_type = "H" world.entities["N"].product_per_year_amount = 10.0 world.entities["N"].auto = 0.0 world.state.amount.N = 1.0 return world func dispose(world) -> void: for entity in world.entities.values(): entity.free() world.free() func run() -> void: var saves: Node = root.get_node("SaveManager") var world = fixture() world.evolute(0.09) check(world.state.time.year == 0.0, "Do not process before a tenth boundary") check(world.state.amount.H == 0.0, "No premature production") world.evolute(0.01) check(world.state.time.year == 0.1, "Process the first tenth") check(world.state.amount.H == 1.0, "Production runs at 0.1 year") world.evolute(0.2) check(world.state.time.year == 0.3 and world.state.amount.H == 3.0, "Do not reprocess previous tenths") var before: Dictionary = world.state.duplicate(true) for invalid in [0.0, -1.0, NAN, INF, 1e308]: world.evolute(invalid) check(world.state == before, "Invalid/overflow interval rejected") check(saves.validate_data({"state": world.state}) == "", "Fractional save is valid") var invalid_save: Dictionary = world.state.duplicate(true) invalid_save.time.year = 0.25 check(saves.validate_data({"state": invalid_save}) != "", "Reject inconsistent fractional clock") dispose(world) for fps in [30, 60, 144]: world = fixture() for frame in fps: world.evolute(1.0 / fps) check(world.state.time.year == 1.0, "One second at %d fps" % fps) check(world.state.amount.H == 10.0, "Production across frames at %d fps" % fps) dispose(world) world = fixture() world.evolute(0.05) world.speed = 2 world.evolute(0.005) check(world.state.time.year == 0.1, "Speed change preserves accumulated fraction") world.speed = 100 check(world.speed == 5 and world.state.speed_in_year == 10000.0, "Upper speed limit unchanged") world.speed = -10 check(world.speed == 1 and world.state.speed_in_year == 1.0, "Lower speed limit unchanged") dispose(world) world = fixture() world.state.version = "0.1.0" world.state.time = {"datetime": 0.45, "year": 0.0} check(saves.validate_data({"state": world.state}) == "", "Accept legacy integer-year save") world.migrate_time_precision() check(world.state.version == "0.1.1", "Migrate schema version") check(world.state.time.year == 0.4 and world.state.time.datetime == 0.45, "Keep unprocessed sub-tenth remainder") check(world.state.amount.H == 4.0, "Migration processes pending legacy time") check(saves.validate_data({"state": world.state}) == "", "Migrated state validates") before = world.state.duplicate(true) world.migrate_time_precision() check(world.state == before, "Migration is idempotent") # Verify in-memory save roundtrip without touching the player's save. var restored = fixture() restored.state = bytes_to_var(var_to_bytes(world.state)) world.evolute(0.05) restored.evolute(0.05) check(world.state == restored.state, "Save continuation preserves time and production") check(world.state.time.year == 0.5 and world.state.amount.H == 5.0, "No double-counted migration time") dispose(world) dispose(restored) world = fixture() world.entities.N.output_and = {"He": 1.0} world.entities.N.output_or = {} world.state.batches.N = [{"start_year": 0.1, "end_year": 0.1, "amount": 1.0}] world.evolute(0.1) check(world.state.amount.N == 0.0 and world.state.amount.He == 1.0, "Existing evolution executes at fractional boundary") dispose(world) check(Clock.processed_year(0.099) == 0.0, "Do not round a genuine incomplete tenth forward") check(Clock.processed_year(1e9 + 0.45) == 1e9 + 0.4, "Large ages preserve fractional precision") print("Time migration: %d checks, %d failures" % [checks, failures]) quit(0 if failures == 0 else 1)