Add new music tracks to the sound directory

- Added cosmic_unicorns.ogg
- Added funky_eldritch.ogg
- Added meditative_beings.ogg
- Added owniverse_main_theme.ogg

These tracks enhance the audio experience of the project.
This commit is contained in:
Kirill
2026-10-01 07:48:52 +03:00
parent fad862d618
commit befb377774
58 changed files with 378 additions and 262 deletions
+14 -13
View File
@@ -6,24 +6,25 @@
godot --headless --path Owniverse.GI --script res://tests/benchmark_saved_state.gd -- /tmp/save.adventure.json
```
Читает диагностический JSON формата 3 в отдельные экземпляры мира и замеряет
Читает диагностический JSON формата 4 в отдельные экземпляры мира и замеряет
шесть последовательных шагов на скоростях 1, 4, 6. Запись сохранений не вызывается.
Последним аргументом можно задать длительность шага в реальных секундах
(по умолчанию 1/60). Это время расчёта симуляции, без отрисовки интерфейса.
При проверке регрессии на копии сохранения с 120 партиями шаг на скорости 6
занимал около 1,3 секунды. Главная причина — перебор пустых завершённых окон
коротких взрывов; дополнительная — повторное сокращение уже сокращённых дробей.
После пропуска таких окон и устранения повторных НОД замеры составили 90–99 мс
на шаг 1/60 секунды. Это ускорение примерно в 14 раз, но ещё не бюджет 60 FPS.
Размер партии, точность чисел и правила эволюции не изменены. Разреженные
сценарии дополнительно сравниваются с полным расчётом в `test_short_lived_events.gd`.
На диагностической копии с 120 партиями прежняя рациональная арифметика после
оптимизации пустых окон давала 90–99 мс на шаг 1/60 секунды на скорости 6.
После перехода на целые блоки и float-остаток повторный замер дал 58–62 мс.
При шаге 0,1 секунды: 71–82 мс вместо 117–138 мс. Это замеры расчёта на данной
копии, а не обещание FPS. Для сравнения старый JSON был преобразован только
во временный тестовый файл; в загрузчик игры миграция не добавлена.
Разреженные сценарии сравниваются с полным расчётом в `test_short_lived_events.gd`.
## Точная арифметика
## Целые блоки и дробные остатки
`godot --headless --path Owniverse.GI --script res://tests/test_exact_math.gd`
Независимый эталон Python Fraction, границы int64 и 10^27, точная сериализация,
Независимый эталон Python Fraction: 160 пар с произведением внутри E27; целые
проверяются точно, дроби — с допуском 10^-12. Также границы int64/E27, сериализация,
рецепты с дробными стоимостями, сохранение сумм, время и 100 циклов с меняющимися
долями. Все остальные тесты используют числовое сравнение и сериализацию через
`E`, а не сравнение ссылок на большие числа. Границы точности и новый формат
@@ -90,14 +91,14 @@ godot --headless --path Owniverse.GI --script res://tests/test_time.gd
Проверяются границы десятых долей года, производство ресурсов на этих границах, накопление дробного остатка, скорости 1–10 000 лет/сек, продолжение после загрузки и недопустимые интервалы.
Схема состояния `0.1.1` хранит:
Схема состояния `0.3.0` хранит:
- `time.datetime` — накопленный возраст, включая необработанную дробную часть;
- `time.year` — последний рассчитанный возраст с точностью до десятой доли года.
Сохранения используют формат 2 и актуальную структуру состояния. Проверяются целостность данных, фоновая запись и повторная загрузка; поддержка и миграция прежних форматов отсутствуют.
Сохранения используют формат 4 и актуальную структуру состояния. Проверяются целостность данных, фоновая запись и повторная загрузка; поддержка и миграция прежних форматов отсутствуют.
Файл с несовместимым номером формата при загрузке переносится в `*.adventure.incompatible.bak` (при совпадении имени добавляется числовой суффикс). Игра начинает новую сессию и может сохранять её в формате 2. Прогресс несовместимого файла не переносится, исходные байты сохраняются в архиве. Ошибка архивирования, расшифровки или повреждение данных текущего формата по-прежнему блокируют перезапись.
Файл с несовместимым номером формата при загрузке переносится в `*.adventure.incompatible.bak` (при совпадении имени добавляется числовой суффикс). Игра начинает новую сессию и может сохранять её в формате 4. Прогресс несовместимого файла не переносится, исходные байты сохраняются в архиве. Ошибка архивирования, расшифровки или повреждение данных текущего формата по-прежнему блокируют перезапись.
## Согласованные правила эволюции
+2 -2
View File
@@ -22,8 +22,8 @@ func run():
quit(1)
return
var data = JSON.parse_string(FileAccess.get_file_as_string(args[0]))
if not data is Dictionary or data.get("format_version") != 3:
push_error("Expected diagnostic JSON format 3")
if not data is Dictionary or data.get("format_version") != 4:
push_error("Expected diagnostic JSON format 4")
quit(1)
return
var initial: Dictionary = E.decode(restore_json_integers(data)).state
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -16,7 +16,7 @@ func check(value: bool, message: String) -> void:
func run() -> void:
var actions = load("res://ui/actions/actions.tscn").instantiate()
root.add_child(actions)
for maximum in [0, E.of("0.1"), E.of("0.99"), 1, E.of("1.9"), 10, 100, 123, 1000, 10000, E.of("1e9"), E.of("1.1e9"), E.of("1e150")]:
for maximum in [0, E.of("0.1"), E.of("0.99"), 1, E.of("1.9"), 10, 100, 123, 1000, 10000, E.of("1e9"), E.of("1.1e9"), E.of("9e27")]:
actions.set_actions("test", maximum)
var labels: Array = []
var values: Array = []
+1 -1
View File
@@ -53,7 +53,7 @@ func invariants(world) -> void:
check(E.eq(sum_ethics(world, id), physical.get(id, 0)), E.add("Ethics equal physical population for ", id))
for n in world.state.ethics[id].values():
if (E.lt(n, 0) or E.ne(n, E.floor_value(n))): check(false, "Invalid ethic amount")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Civilization state validates")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Civilization state validates")
func run() -> void:
var global: Node = root.get_node("Global")
+2 -2
View File
@@ -59,7 +59,7 @@ func run() -> void:
world.state.amount["C0.2"] = 3
world.evolution.initialize_life_batches()
check(E.eq(world.state.ethics["C0.2"].m, 3), "Losses reduce ethics without inventing population")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Ethics state validates")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Ethics state validates")
var restored = fixture()
restored.state = E.decode(bytes_to_var(var_to_bytes(E.encode(world.state))))
restored.evolution.initialize_life_batches()
@@ -117,7 +117,7 @@ func run() -> void:
world.evolution.initialize_life_batches()
check(E.eq(world.state.amount["C4.2"], 2), "SMBH capacity uses stellar mass equivalent")
check(E.eq(world.ledger.physical_amounts(world.state)["C1.9"], 1), "Unsupported civilization degrades through missing habitat families")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Capacity-limited state validates")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Capacity-limited state validates")
dispose(world)
world = fixture()
+30 -10
View File
@@ -15,20 +15,27 @@ func check(actual, expected: String, label: String):
failures += 1
push_error(label + ": " + str(actual) + " != " + expected)
func check_number(actual, expected: String, label: String):
var reference = E.of(expected)
checks += 1
if E.gt(E.absolute(E.subtract(actual, reference)), E.of("1e-12")):
failures += 1
push_error(label + ": " + str(actual) + " != " + expected)
func run():
# Expected strings were generated independently with Python fractions.Fraction.
var cases = JSON.parse_string(FileAccess.get_file_as_string("res://tests/fixtures/exact_oracle.json"))
for row in cases:
var a = E.of(row[0])
var b = E.of(row[1])
check(E.add(a, b), row[2], "sum")
check(E.subtract(a, b), row[3], "difference")
check(E.multiply(a, b), row[4], "product")
check(E.divide(a, b), row[5], "quotient")
check_number(E.add(a, b), row[2], "sum")
check_number(E.subtract(a, b), row[3], "difference")
check_number(E.multiply(a, b), row[4], "product")
check_number(E.divide(a, b), row[5], "quotient")
check(E.floor_value(E.divide(a, b)), row[6], "floor")
for text in ["9223372036854775807", "-9223372036854775808", "9007199254740993", "1000000000000000000000000001", "-1/10000000000000"]:
var value = E.of(text)
check(E.decode(JSON.parse_string(JSON.stringify(E.encode(value)))), text, "JSON round trip")
check(E.eq(E.decode(JSON.parse_string(JSON.stringify(E.encode(value)))), value), "true", "JSON round trip")
check(E.add(E.of("9223372036854775807"), 1), "9223372036854775808", "int64 overflow promoted")
check(E.subtract(E.of("-9223372036854775808"), 1), "-9223372036854775809", "int64 underflow promoted")
check(Q.production_step([E.of("1e27")]), "1", "large integral recipe")
@@ -38,7 +45,7 @@ func run():
check(Q.sum(allocation), str(count), "allocation conserves every unit")
check(allocation.a, "333333333333333333333333334", "deterministic remainder")
var clock = Clock.advance({"datetime": E.of("1e27")}, 0.000000001, 1)
check(E.subtract(clock.datetime, E.of("1e27")), "1/1000000000", "single tick at huge age")
check_number(E.subtract(clock.datetime, E.of("1e27")), "1/1000000000", "single tick at huge age")
var world = load("res://world/owniverse/owniverse.gd").new()
world.catalog.load_definitions(root.get_node("Global").OwniverseEntities)
for id in world.catalog.entities:
@@ -52,10 +59,23 @@ func run():
check(world.state.energy, "999999999999999999999999999", "spend one energy")
var life = world.life.life_products(world.state, world.catalog.entities.EON5, count)
check(Q.sum(life), str(count), "life conservation at 1e27")
var precise = E.divide(count, E.of("100000000000000000000000000000000000003"))
var bounded = E.bounded(precise)
check(E.lt(E.absolute(E.subtract(precise, bounded)), E.of("1e-36")), "true", "bounded fractional error")
check(E.bounded(count), str(count), "integer counts never quantized")
check(E.mul_div(E.of("1e27"), 15, 100), "150000000000000000000000000", "exact percentage")
check(E.mul_div(count, count, count), str(count), "fused product beyond storage range")
check(E.subtract(E.add(count, 1), count), "1", "single unit at E27")
check(E.floor_value(E.divide(E.subtract(count, 1), count)), "0", "division must not round up a whole object")
check(E.fixed(E.add(count, E.of("0.125")), 3), "1000000000000000000000000001.125", "formatting without oversized intermediate")
check(E.scientific(E.of("9.999999e27"), 2), "1.00E+28", "display rounding at upper boundary")
check(E.eq(E.power(10, -100), E.of("1e-100")), "true", "negative power needs no huge intermediate")
var largest = E.of("9999999999999999999999999999")
check(E.eq(E.decode(E.encode(largest)), largest), "true", "upper range round trip")
check(E.valid_encoded(E.encode(largest)), "true", "upper range encoding valid")
for tiny in ["1e-13", "1e-20", "1e-100", "1e-310"]:
var value = E.of(tiny)
check(E.gt(value, 0), "true", "tiny fraction remains nonzero")
check(E.eq(value, E.decode(JSON.parse_string(JSON.stringify(E.encode(value))))), "true", "tiny float round trip")
for invalid in [{"$fixed": ["0", "0", "ffffffffffffffff", 1]}, {"$fixed": ["0", "-1", "0000000000000000", 1]}, {"$exact": "1/3"}, {"$exact": "10000000000000000000000000000"}, 1e100]:
check(E.valid_encoded(invalid), "false", "reject invalid saved number")
world.state.amount.S = E.of("1e24")
world.state.amount.H = E.of("1e24")
world.state.amount.RD = 1234567
@@ -69,7 +89,7 @@ func run():
check(str(world.state.auto_star_deficits).length() < 500, "true", "fraction storage stays bounded")
print("100 changing-composition cycles: %d ms" % (Time.get_ticks_msec() - started))
var saves = root.get_node("SaveManager")
check(saves.validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), "", "long-running state saves")
check(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), "", "long-running state saves")
for entity in world.catalog.entities.values(): entity.free()
world.free()
print("Exact math: %d checks, %d failures" % [checks, failures])
+2 -2
View File
@@ -54,7 +54,7 @@ func run() -> void:
check(E.gt(world.state.batches.HP.size(), 0), "Survivors get next attempt")
var physical: Dictionary = world.ledger.physical_amounts(world.state)
check(E.eq(E.add(E.add(physical.HP, physical.EON1), physical.RP), 40000), "Life conserves planets")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Life save validates")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Life save validates")
var restored = fixture()
restored.state = E.decode(bytes_to_var(var_to_bytes(E.encode(world.state))))
world.evolution.evolve_batches(world.state, 11000000)
@@ -118,7 +118,7 @@ func run() -> void:
world.evolution.evolve_batches(world.state, 2050)
check(E.eq(world.state.binds.RD["C0.2"], 700), "C0.1 reaches ethical civilization without losing host")
check(E.eq(world.state.binds.RD["C0.0"], 1000), "C0.1 degradation follows Unity")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Extended life save validates")
check(E.eq(root.get_node("SaveManager").validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Extended life save validates")
dispose(world)
print(("Life: %d checks, %d failures" % [checks, failures]))
quit((0 if E.eq(failures, 0) else 1))
+13
View File
@@ -43,6 +43,19 @@ func run() -> void:
world.catalog.entities.N.bind = {"S": 3}
world.state.amount.H = 10
world.state.amount.S = 0
check(E.eq(world.production.calculate_max_producible(world.catalog.entities.N), 0), "Default maximum respects missing bindings")
world.state.amount.S = 30
check(E.eq(world.production.calculate_max_producible(world.catalog.entities.N), 5), "Default maximum uses recipe resources without an oversized sentinel")
check(E.eq(world.production.calculate_max_producible(world.catalog.entities.N, 2), 2), "Explicit production limit is preserved")
world.state.amount.H = E.of("1e27")
world.state.amount.S = E.of("1e27")
check(E.eq(world.production.calculate_max_producible(world.catalog.entities.N), E.floor_value(E.divide(E.of("1e27"), 3))), "Default maximum at E27 retains integer precision")
world.state.amount.BH25 = 4
check(E.eq(world.production.calculate_max_producible(world.catalog.entities.SMBH), world.production.smbh_available()), "Default SMBH maximum uses available black-hole mass")
world.state.amount.BH25 = 0
check(E.eq(world.production.calculate_max_producible(world.catalog.entities.SMBH), 0), "Empty SMBH maximum is zero")
world.state.amount.H = 10
world.state.amount.S = 0
world.state.auto_resources = {"H": 10}
world.state.batches.H = [{"amount": 10, "start_year": 1, "end_year": 2}]
var before: Dictionary = world.state.duplicate(true)
+3 -3
View File
@@ -96,7 +96,7 @@ func run() -> void:
check((E.eq(world.state.binds.RD.GG, 16) and E.eq(world.state.binds.RD.AB, 120)), "Planet multiplicity applied")
check((E.eq(world.state.amount.HP, 0) and E.eq(world.state.stats.total_amount.HP, 1)), "Created planets are bound, counted once")
var saves: Node = root.get_node("SaveManager")
check(E.eq(saves.validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Planet carry save validates")
check(E.eq(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Planet carry save validates")
restored = fixture()
restored.state = E.decode(bytes_to_var(var_to_bytes(E.encode(world.state))))
world.stellar.create_planets(world.state, "RD", 37, 0, 0, E.of("0.7"))
@@ -118,7 +118,7 @@ func run() -> void:
check((E.eq(world.state.amount.RP, 0) and E.eq(world.state.amount["C1.3"], 0)), "Inherited planets never become free")
world.evolution.evolve_batches(world.state, E.add(lifespan, width))
check((E.eq(world.state.binds.RD["C1.3"], 0) and E.eq(world.state.binds.TWD["C1.3"], 4)), "No planets left at extinct parent type")
check(E.eq(saves.validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Inherited state validates")
check(E.eq(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Inherited state validates")
dispose(world)
world = fixture()
@@ -158,7 +158,7 @@ func run() -> void:
check((E.eq(world.state.amount.SN, 0) and E.eq(world.state.amount.LNS, 1)), "Supernova produces a remnant")
check(((E.eq(world.state.amount.H, 8) and E.eq(world.state.amount.He, 50)) and E.eq(world.state.amount.Met, 11)), "Supernova returns table resources")
check((not world.state.amount.has("blast")), "Supernova dispatches blast output")
check(E.eq(saves.validate_data({"format_version": 3, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Blast state validates")
check(E.eq(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": world.state}), ""), "Blast state validates")
dispose(world)
world = fixture()
+3 -3
View File
@@ -48,13 +48,13 @@ func run() -> void:
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")]:
for invalid in [0, E.neg(1), NAN, INF, 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")
check(E.eq(saves.validate_data({"format_version": 4, "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")
check(E.ne(saves.validate_data({"format_version": 4, "app_version": "", "ui": {"current_page": 0}, "state": invalid_save}), ""), "Reject inconsistent fractional clock")
dispose(world)
for fps in [30, 60, 144]:
+1 -1
View File
@@ -133,7 +133,7 @@ func run() -> void:
Parameters.advance(source, world.state, rules, E.of("1.0e12"))
check((E.ge(world.state.trends.Integration, 0) and E.lt(world.state.trends.Integration, 1)), "Very large intervals finish with a valid trend fraction")
check(E.ge(world.state.world_parameters.Agg, 1), "Repeated integration events cannot reduce aggression below the scale")
var payload: Dictionary = {"format_version": 3, "app_version": "test", "ui": {"current_page": 1}, "state": world.state}
var payload: Dictionary = {"format_version": 4, "app_version": "test", "ui": {"current_page": 1}, "state": world.state}
var manager: Node = root.get_node("SaveManager")
check(E.eq(manager.validate_data(payload), ""), "New parameters and trends pass save validation")
var old: Dictionary = payload.duplicate(true)