Files
owniverse/world/owniverse/entity_catalog.gd
T
Kirill c4e7302567 Add new tests and implement frame budget management
- Introduced `civilization_benchmark.gd` and `legacy_quantity_math.gd` for benchmarking and legacy quantity calculations.
- Created `test_dynamic_math.gd`, `test_frame_evolution.gd`, and `test_sparse_batches.gd` to validate mathematical operations and frame evolution logic.
- Implemented `frame_budget.gd` to manage cooperative work on the main thread, ensuring no partially calculated state is published.
- Added UID files for all new scripts to maintain unique identifiers.
2026-10-01 23:43:34 +03:00

98 lines
4.1 KiB
GDScript

extends RefCounted
const E = preload("res://world/owniverse/math/exact.gd")
## Definitions and their indexes only: no population, batches or UI state.
## Definitions are Nodes owned by the caller, as before this extraction.
var entities: Dictionary[String, OwniverseEntity] = {}
var groups: Dictionary[String, Array] = {}
var event_groups: Dictionary[String, Array] = {}
var automatic_producers: Array = []
var unlockable_entities: Array = []
var _group_members: Dictionary = {}
var index_revision: int = 0
var _indexed_entity_count: int = -1
var _civilization_layout: Dictionary = {}
var _civilization_rules: Dictionary = {}
## Populate an empty catalog; replacement uses a new catalog to preserve ownership.
func load_definitions(rows: Dictionary) -> void:
assert(entities.is_empty(), "Load definitions into an empty catalog")
for id in rows:
var entity := OwniverseEntity.new(rows[id])
entities[id] = entity
if not entity.unlock.is_empty(): unlockable_entities.append(entity)
if entity.product_per_year_type != "": automatic_producers.append(entity)
if entity.group_as != "":
if not groups.has(entity.group_as): groups[entity.group_as] = []
groups[entity.group_as].append(id)
if entity.event_group != "":
if not event_groups.has(entity.event_group): event_groups[entity.event_group] = []
event_groups[entity.event_group].append(id)
rebuild_group_index()
## Call explicitly after modifying group_as without changing the entity count.
func rebuild_group_index() -> void:
index_revision += 1
_civilization_layout.clear()
_group_members.clear()
for id in entities:
var group: String = entities[id].group_as
if not _group_members.has(group): _group_members[group] = []
_group_members[group].append(id)
_indexed_entity_count = entities.size()
func _ensure_group_index() -> void:
if _indexed_entity_count != entities.size(): rebuild_group_index()
func is_group(id: String) -> bool:
_ensure_group_index()
return groups.has(id) or _group_members.has(id)
func members(id: String) -> Array:
if not is_group(id): return [id]
return _group_members.get(id, []).duplicate()
## Definition-only cache. Rebuild indexes after changing claims or bonuses;
## invalidate this layout after changing stage homes in an existing rules table.
func invalidate_civilization_layout() -> void:
_civilization_layout.clear()
func civilization_layout(rules: Dictionary) -> Dictionary:
_ensure_group_index()
if not _civilization_layout.is_empty() and is_same(_civilization_rules, rules):
return _civilization_layout
_civilization_rules = rules
var structures: Array = []
for id in entities:
if entities[id].claim != "": structures.append(id)
structures.sort_custom(func(a, b): return E.gt(entities[a].civ_bonus, entities[b].civ_bonus) if E.ne(entities[a].civ_bonus, entities[b].civ_bonus) else str(a) < str(b))
var stages: Array = []
for id in rules:
if str(rules[id].home) != "": stages.append(id)
stages.sort()
var anchors: Dictionary = {}
var requirements: Dictionary = {}
var anchor: String = ""
var units: Variant = 1
for id in stages:
var direct: String = ""
for structure in structures:
if entities[structure].claim == id: direct = structure
if direct != "":
anchor = direct
units = 1
else:
units = E.multiply(units, 10)
anchors[id] = anchor
if id.begins_with("C3.") or id.begins_with("C4."):
requirements[id] = {"id": anchor, "units": units}
var star_homes: Dictionary = {}
for id in entities:
var homes: Array = []
for home in ["DwStar", "GiStar", "WD", "NS", "MGT", "BH"]:
if entities[id].event_group == home or entities[id].count_as == home or id == home:
homes.append(home)
if not homes.is_empty(): star_homes[id] = homes
_civilization_layout = {"structures": structures, "stages": stages, "anchors": anchors, "requirements": requirements, "star_homes": star_homes}
return _civilization_layout