Files
owniverse/world/owniverse/owniverse_entity.gd
T
Kirill e48d4bbe88 Add comprehensive tests and optimizations for simulation and UI performance
- Introduced a new benchmark save script to create a stress test scenario with extreme values for simulation performance.
- Added a full UI benchmark script to measure frame rates and performance metrics during UI interactions.
- Implemented tests for coarse generations to ensure population transitions are handled correctly.
- Created tests for extra parameters to validate the loading and application of configuration settings.
- Developed simulation optimization tests to verify the efficiency of population drift and rounding mechanisms.
- Added split optimization tests to ensure accurate allocation and rounding behavior in population management.
- Included startup parameter tests to confirm the correct initialization of global parameters before scene readiness.
- Enhanced the audit rounding ledger to compare selective and full rounding results for consistency.
2026-10-05 22:16:59 +03:00

158 lines
6.2 KiB
GDScript

extends Node
class_name OwniverseEntity
const E = preload("res://world/owniverse/math/exact.gd")
const QuantityMath = preload("res://world/owniverse/quantity_math.gd")
var id: String
var is_visible: bool = false
var unlock: Dictionary = {}
var cost: Dictionary = {}
var bind: Dictionary = {}
var mass: Variant
var space: int
var life_rule: Dictionary = {}
var life_fall_weights: Dictionary = {}
var generation_plan: Dictionary = {}
var lifespan: Variant
var lifespan_delta: Variant
var auto: Variant
var gamma: Variant
var blast: int
var blastability: bool = false
var life_product: Dictionary = {}
var product_per_year_type: String = ""
var product_per_year_amount: Variant = 0
var voids: int
var output_or: Dictionary = {}
var output_and: Dictionary = {}
var destroy_level: int
var degradation: Dictionary = {}
var planets: Dictionary = {}
var count_as: String
var group_as: String
var event_group: String
var space_bonus: Variant
var civ_bonus: Variant
var claim: String
var amount: Variant = 0
func _init(values: Dictionary) -> void:
id = values.id
is_visible = E.eq(values.is_visible, "1")
unlock = _parse_and_string(values.unlock)
cost = _parse_and_string(values.cost)
bind = _parse_and_string(values.bind)
#print(id, " | ", cost, " | ", bind)
mass = E.of(values.mass)
space = E.integer(values.space)
life_rule = Global.LifeRules.get(id, {}).duplicate(true)
if Global.CivilizationRules.has(id):
life_rule = {"ethical": true, "span": Global.CivilizationRules[id].span}
elif not life_rule.is_empty():
life_fall_weights = QuantityMath.rule_weights(str(life_rule.get("fall", "")))
lifespan = (E.of(life_rule.span) if (not life_rule.is_empty()) else E.of(values.lifespan))
lifespan_delta = (E.divide(lifespan, Global.batch_count) if E.gt(lifespan, 10) else lifespan)
auto = E.of(values.auto)
gamma = E.of(values.gamma if str(values.gamma).is_valid_float() else "0")
blast = E.integer(values.blast)
blastability = E.eq(str(values.get("blastability", "")), "1")
life_product = _parse_and_string(values.life_product)
for key in life_product.keys():
product_per_year_type = key
product_per_year_amount = (E.divide(life_product[key], lifespan) if E.ne(lifespan, 0) else 0)
#print(id, " | ", lifespan_delta, " | ", lifespan)
voids = E.integer(values.voids)
output_or = _parse_or_string(values.output)
output_and = _parse_and_string(values.output)
destroy_level = E.integer(values.destroy_level)
degradation = _parse_and_string(values.degradation)
planets = _parse_planet_string(values.planets)
count_as = values.count_as
group_as = values.group_as
event_group = values.event_group
space_bonus = E.of(values.space_bonus)
civ_bonus = E.of(values.civ_bonus)
claim = values.claim
refresh_generation_plan()
func refresh_generation_plan() -> void:
var fall_text: String = str(life_rule.get("fall", ""))
if not generation_plan.is_empty() \
and E.eq(generation_plan.outputs, output_and) \
and E.eq(generation_plan.chance, output_or.get("chance", 0)) \
and E.eq(generation_plan.positive, output_or.get("positive", "")) \
and E.eq(generation_plan.negative, output_or.get("negative", "")) \
and E.eq(generation_plan.blast, blast) \
and E.eq(generation_plan.life_progress, life_rule.get("progress", 0)) \
and E.eq(generation_plan.life_degradation, life_rule.get("degradation", 0)) \
and E.eq(generation_plan.life_next, str(life_rule.get("next", id))) \
and E.eq(generation_plan.life_fall_text, fall_text):
return
life_fall_weights = QuantityMath.rule_weights(fall_text) if not fall_text.is_empty() else {}
generation_plan = {
"life": not life_rule.is_empty(),
"life_progress": E.of(life_rule.get("progress", 0)),
"life_degradation": E.of(life_rule.get("degradation", 0)),
"life_next": str(life_rule.get("next", id)),
"life_fall": life_fall_weights,
"outputs": output_and,
"chance": output_or.get("chance", 0),
"positive": output_or.get("positive", ""),
"negative": output_or.get("negative", ""),
"life_fall_text": fall_text,
"positive_terms": QuantityMath.output_terms(str(output_or.get("positive", ""))),
"negative_terms": QuantityMath.output_terms(str(output_or.get("negative", ""))),
"blast": blast,
"destroy_level": destroy_level
}
generation_plan.make_read_only()
func _parse_or_string(source_line: String) -> Dictionary:
var result = {}
if source_line.contains("^"):
var first_split = source_line.split("^")
var second_split = first_split[1].split("%")
var probability = E.of(second_split[1])
result["chance"] = probability
result["positive"] = second_split[0]
result["negative"] = first_split[0]
return result
func _parse_and_string(source_line: String) -> Dictionary:
var result = {}
var first_split = source_line.split("&")
for elem in first_split:
var second_split = elem.split(":")
if E.eq(len(second_split), 2):
result[second_split[0]] = E.of(second_split[1])
return result
func _parse_planet_string(source_line: String) -> Dictionary:
var result = {}
for elem in source_line.split("&", false):
var parts: PackedStringArray = elem.strip_edges().split(":")
if (E.ne(parts.size(), 3) or parts[0].strip_edges().is_empty()):
push_warning(("Invalid planet definition for %s: %s" % [id, elem]))
continue
if ((not parts[1].is_valid_float()) or (not parts[2].is_valid_float())):
push_warning(("Invalid planet numbers for %s: %s" % [id, elem]))
continue
var count: Variant = E.of(parts[1])
var chance: Variant = E.of(parts[2])
if ((((((not E.finite(count)) or (not E.finite(chance))) or E.lt(count, 0)) or E.ne(count, E.floor_value(count))) or E.lt(chance, 0)) or E.gt(chance, 1)):
push_warning(("Planet values out of range for %s: %s" % [id, elem]))
continue
# Planet chances are fractions (0.01 = 1%), unlike output_or percentages.
result[parts[0].strip_edges()] = {"amount": count, "chance": chance}
return result