extends SceneTree const E = preload("res://world/owniverse/math/exact.gd") 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 = E.add(checks, 1) if (not condition): failures = E.add(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.catalog.entities[id] = entity world.state.amount[id] = 0 world.state.stats.total_amount[id] = 0 if E.ne(entity.group_as, ""): world.state.amount[entity.group_as] = 0 world.state.stats.total_amount[entity.group_as] = 0 world.catalog.entities["N"].life_product = {} world.catalog.entities["N"].product_per_year_type = "H" world.catalog.entities["N"].product_per_year_amount = 10 world.catalog.entities["N"].auto = 0 world.state.amount.N = 1 return world func dispose(world) -> void: for entity in world.catalog.entities.values(): entity.free() world.free() func run() -> void: var saves: Node = root.get_node("SaveManager") var world = fixture() world.evolute(E.of("0.09")) check(E.eq(world.state.time.year, 0), "Do not process before a tenth boundary") check(E.eq(world.state.amount.H, 0), "No premature production") world.evolute(E.of("0.01")) check(E.eq(world.state.time.year, E.of("0.1")), "Process the first tenth") check(E.eq(world.state.amount.H, 1), "Production runs at 0.1 year") world.evolute(E.of("0.2")) check((E.eq(world.state.time.year, E.of("0.3")) and E.eq(world.state.amount.H, 3)), "Do not reprocess previous tenths") var before: Dictionary = world.state.duplicate(true) for invalid in [0, E.neg(1), NAN, INF, E.of("1e308")]: world.evolute(invalid) check(E.eq(world.state, before), "Invalid/overflow interval rejected") check(E.eq(saves.validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Fractional save is valid") var invalid_save: Dictionary = world.state.duplicate(true) invalid_save.time.year = E.of("0.25") check(E.ne(saves.validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": invalid_save}), ""), "Reject inconsistent fractional clock") dispose(world) for fps in [30, 60, 144]: world = fixture() for frame in fps: world.evolute(E.divide(1, fps)) check(E.eq(world.state.time.year, 1), ("One second at %d fps" % fps)) check(E.eq(world.state.amount.H, 10), ("Production across frames at %d fps" % fps)) dispose(world) world = fixture() world.evolute(E.of("0.05")) world.speed = 2 world.evolute(E.of("0.005")) check(E.eq(world.state.time.year, E.of("0.1")), "Speed change preserves accumulated fraction") world.speed = 100 var speed_limit: int = root.get_node("Global").SPEED_LIMIT check((E.eq(world.speed, speed_limit) and E.eq(world.state.speed_in_year, E.power(10, E.subtract(speed_limit, 1)))), "Configured upper speed limit") world.speed = E.neg(10) check((E.eq(world.speed, 1) and E.eq(world.state.speed_in_year, 1)), "Lower speed limit unchanged") dispose(world) world = fixture() dispose(world) world = fixture() world.catalog.entities.N.output_and = {"He": 1} world.catalog.entities.N.output_or = {} world.state.batches.N = [{"start_year": E.of("0.1"), "end_year": E.of("0.1"), "amount": 1}] world.evolute(E.of("0.1")) check((E.eq(world.state.amount.N, 0) and E.eq(world.state.amount.He, 1)), "Existing evolution executes at fractional boundary") dispose(world) check(E.eq(Clock.processed_year(E.of("0.099")), 0), "Do not round a genuine incomplete tenth forward") check(E.eq(Clock.processed_year(E.add(E.of("1e9"), E.of("0.45"))), E.add(E.of("1e9"), E.of("0.4"))), "Large ages preserve fractional precision") print(("Time state: %d checks, %d failures" % [checks, failures])) quit((0 if E.eq(failures, 0) else 1))