Refactor save management; update validation logic in save_manager.gd and enhance action handling in actions.gd for improved data integrity and user experience
This commit is contained in:
+121
-43
@@ -12,13 +12,8 @@ var items_to_update: Dictionary[String, float] = {}
|
||||
var auto_production: Array = []
|
||||
var locked_entities: Array = []
|
||||
|
||||
#var cumulative_amount: Dictionary[String, float] = {}
|
||||
#var current_amount: Dictionary[String, float] = {}
|
||||
|
||||
|
||||
# ------------------------------------
|
||||
|
||||
|
||||
var state: Dictionary = {
|
||||
'version': '0.1.0',
|
||||
'time': {
|
||||
@@ -226,7 +221,7 @@ func _credit(target: Dictionary, id: String, amount: float) -> float:
|
||||
target.production_remainders[id] = expected - amount
|
||||
target.amount[id] = target.amount.get(id, 0.0) + amount
|
||||
target.stats.total_amount[id] = target.stats.total_amount.get(id, 0.0) + amount
|
||||
if entities.has(id) and entities[id].group_as != "":
|
||||
if entities.has(id) and entities[id].group_as != "" and entities[id].group_as != id:
|
||||
var group: String = entities[id].group_as
|
||||
target.stats.total_amount[group] = target.stats.total_amount.get(group, 0.0) + amount
|
||||
return amount
|
||||
@@ -238,10 +233,10 @@ func _round_object_allocations(target: Dictionary) -> void:
|
||||
for id in physical:
|
||||
if not _is_discrete(id):
|
||||
continue
|
||||
var slots: Array = [{"owner": "", "value": target.amount.get(id, 0.0)}]
|
||||
for owner in target.binds:
|
||||
if target.binds[owner].has(id):
|
||||
slots.append({"owner": owner, "value": target.binds[owner][id]})
|
||||
var slots: Array = [ {"owner": "", "value": target.amount.get(id, 0.0)}]
|
||||
for owner_id in target.binds:
|
||||
if target.binds[owner_id].has(id):
|
||||
slots.append({"owner": owner_id, "value": target.binds[owner_id][id]})
|
||||
var assigned: float = 0.0
|
||||
for slot: Dictionary in slots:
|
||||
slot.whole = floorf(slot.value)
|
||||
@@ -426,21 +421,21 @@ func _evolve_batch_generation(target: Dictionary, to_year: float) -> bool:
|
||||
# Use a frozen binding table so simultaneous transitions cannot cascade by type order.
|
||||
var bindings: Dictionary = target.binds.duplicate(true)
|
||||
var incoming: Dictionary = {}
|
||||
for owner in bindings:
|
||||
var owner_survival: float = 1.0 - fractions.get(owner, 0.0)
|
||||
target.binds[owner] = {}
|
||||
for id in bindings[owner]:
|
||||
var held: float = bindings[owner][id]
|
||||
for owner_id in bindings:
|
||||
var owner_survival: float = 1.0 - fractions.get(owner_id, 0.0)
|
||||
target.binds[owner_id] = {}
|
||||
for id in bindings[owner_id]:
|
||||
var held: float = bindings[owner_id][id]
|
||||
var released: float = held * (1.0 - owner_survival)
|
||||
target.amount[id] = target.amount.get(id, 0.0) + released
|
||||
var fraction: float = fractions.get(id, 0.0)
|
||||
var remaining: float = held * owner_survival * (1.0 - fraction)
|
||||
target.binds[owner][id] = target.binds[owner].get(id, 0.0) + remaining
|
||||
target.binds[owner_id][id] = target.binds[owner_id].get(id, 0.0) + remaining
|
||||
for successor in outputs.get(id, {}):
|
||||
var transferred: float = held * owner_survival * fraction * maxf(0.0, outputs[id][successor])
|
||||
if not incoming.has(owner):
|
||||
incoming[owner] = {}
|
||||
incoming[owner][successor] = incoming[owner].get(successor, 0.0) + transferred
|
||||
if not incoming.has(owner_id):
|
||||
incoming[owner_id] = {}
|
||||
incoming[owner_id][successor] = incoming[owner_id].get(successor, 0.0) + transferred
|
||||
|
||||
for id in fractions:
|
||||
target.amount[id] = maxf(0.0, target.amount.get(id, 0.0) * (1.0 - fractions[id]))
|
||||
@@ -453,10 +448,10 @@ func _evolve_batch_generation(target: Dictionary, to_year: float) -> bool:
|
||||
amount = _credit(target, successor, amount)
|
||||
_append_batch(target, successor, amount, part.from, part.to)
|
||||
new_owners[successor] = new_owners.get(successor, 0.0) + amount
|
||||
for owner in incoming:
|
||||
for id in incoming[owner]:
|
||||
var transferred: float = minf(incoming[owner][id], target.amount.get(id, 0.0))
|
||||
target.binds[owner][id] = target.binds[owner].get(id, 0.0) + transferred
|
||||
for owner_id in incoming:
|
||||
for id in incoming[owner_id]:
|
||||
var transferred: float = minf(incoming[owner_id][id], target.amount.get(id, 0.0))
|
||||
target.binds[owner_id][id] = target.binds[owner_id].get(id, 0.0) + transferred
|
||||
target.amount[id] = maxf(0.0, target.amount.get(id, 0.0) - transferred)
|
||||
_bind_new_owners(target, new_owners)
|
||||
_round_object_allocations(target)
|
||||
@@ -467,15 +462,15 @@ func _evolve_batch_generation(target: Dictionary, to_year: float) -> bool:
|
||||
func _bind_full(target: Dictionary, amounts: Dictionary) -> bool:
|
||||
var trial: Dictionary = target.duplicate(true)
|
||||
var requests: Array = []
|
||||
for owner in amounts:
|
||||
if not entities.has(owner):
|
||||
for owner_id in amounts:
|
||||
if not entities.has(owner_id):
|
||||
return false
|
||||
for id in entities[owner].bind:
|
||||
var quantity: float = amounts[owner] * maxf(0.0, entities[owner].bind[id])
|
||||
for id in entities[owner_id].bind:
|
||||
var quantity: float = amounts[owner_id] * maxf(0.0, entities[owner_id].bind[id])
|
||||
if not is_equal_approx(quantity, roundf(quantity)):
|
||||
return false
|
||||
if quantity > 0.0:
|
||||
requests.append({"owner": owner, "id": id, "amount": roundf(quantity), "members": _members(id).size()})
|
||||
requests.append({"owner": owner_id, "id": id, "amount": roundf(quantity), "members": _members(id).size()})
|
||||
requests.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
|
||||
if a.members != b.members:
|
||||
return a.members < b.members
|
||||
@@ -532,11 +527,11 @@ func _bind_new_owners(target: Dictionary, amounts: Dictionary, require_full: boo
|
||||
if require_full:
|
||||
return _bind_full(target, amounts)
|
||||
var requests: Dictionary = {}
|
||||
for owner in amounts:
|
||||
if not entities.has(owner):
|
||||
for owner_id in amounts:
|
||||
if not entities.has(owner_id):
|
||||
continue
|
||||
for id in entities[owner].bind:
|
||||
var quantity: float = amounts[owner] * maxf(0.0, entities[owner].bind[id])
|
||||
for id in entities[owner_id].bind:
|
||||
var quantity: float = amounts[owner_id] * maxf(0.0, entities[owner_id].bind[id])
|
||||
var weights: Dictionary = {}
|
||||
for member in _members(id):
|
||||
weights[member] = target.amount.get(member, 0.0)
|
||||
@@ -544,18 +539,18 @@ func _bind_new_owners(target: Dictionary, amounts: Dictionary, require_full: boo
|
||||
for member in weights:
|
||||
if not requests.has(member):
|
||||
requests[member] = {}
|
||||
requests[member][owner] = requests[member].get(owner, 0.0) + quantity * weights[member]
|
||||
requests[member][owner_id] = requests[member].get(owner_id, 0.0) + quantity * weights[member]
|
||||
for id in requests:
|
||||
var requested: float = 0.0
|
||||
for quantity in requests[id].values():
|
||||
requested += quantity
|
||||
var available: float = _available(target, id)
|
||||
var factor: float = minf(1.0, available / requested) if requested > 0.0 else 0.0
|
||||
for owner in requests[id]:
|
||||
var quantity: float = requests[id][owner] * factor
|
||||
if not target.binds.has(owner):
|
||||
target.binds[owner] = {}
|
||||
target.binds[owner][id] = target.binds[owner].get(id, 0.0) + quantity
|
||||
for owner_id in requests[id]:
|
||||
var quantity: float = requests[id][owner_id] * factor
|
||||
if not target.binds.has(owner_id):
|
||||
target.binds[owner_id] = {}
|
||||
target.binds[owner_id][id] = target.binds[owner_id].get(id, 0.0) + quantity
|
||||
target.amount[id] = maxf(0.0, target.amount.get(id, 0.0) - quantity)
|
||||
|
||||
return true
|
||||
@@ -774,7 +769,90 @@ func _auto_capacity(source: Dictionary, entity: OwniverseEntity, budget: Diction
|
||||
## @param item_id - entity id to produce
|
||||
## @param desired_amount - desired quantity to produce
|
||||
## @return actual amount produced based on available resources
|
||||
func _smbh_sources() -> Dictionary:
|
||||
var masses: Dictionary = {}
|
||||
for id in entities:
|
||||
var entity: OwniverseEntity = entities[id]
|
||||
if entity.count_as == "BH" and entity.mass > 0.0:
|
||||
masses[id] = floorf(maxf(0.0, state.amount.get(id, 0.0))) * entity.mass
|
||||
return masses
|
||||
|
||||
|
||||
func _smbh_available() -> float:
|
||||
var mass: float = 0.0
|
||||
for value in _smbh_sources().values():
|
||||
mass += value
|
||||
return floorf(mass)
|
||||
|
||||
|
||||
func _plan_smbh(desired_amount: float) -> Dictionary:
|
||||
var empty: Dictionary = {"amount": 0.0, "taken": {}}
|
||||
if desired_amount <= 0.0 or not is_finite(desired_amount):
|
||||
return empty
|
||||
var total_mass: float = _smbh_available()
|
||||
if total_mass <= 0.0:
|
||||
return empty
|
||||
var requested: float = minf(floorf(desired_amount), total_mass)
|
||||
if requested <= 0.0:
|
||||
return empty
|
||||
var masses: Dictionary = _smbh_sources()
|
||||
var distribution: Dictionary = _normalize_distribution(masses)
|
||||
var taken: Dictionary = {}
|
||||
var order: Array = []
|
||||
var consumed_mass: float = 0.0
|
||||
for id in distribution:
|
||||
var expected: float = requested * distribution[id] / entities[id].mass
|
||||
taken[id] = minf(floorf(expected), floorf(state.amount[id]))
|
||||
consumed_mass += taken[id] * entities[id].mass
|
||||
order.append({"id": id, "remainder": expected - taken[id]})
|
||||
order.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
|
||||
return a.remainder > b.remainder if a.remainder != b.remainder else a.id < b.id)
|
||||
# Consume whole BH only; all excess mass becomes SMBH, never disappears.
|
||||
for candidate: Dictionary in order:
|
||||
if consumed_mass >= requested:
|
||||
break
|
||||
var id: String = candidate.id
|
||||
if taken[id] < floorf(state.amount[id]):
|
||||
taken[id] += 1.0
|
||||
consumed_mass += entities[id].mass
|
||||
if consumed_mass <= 0.0 or consumed_mass != floorf(consumed_mass):
|
||||
return empty
|
||||
return {"amount": consumed_mass, "taken": taken}
|
||||
|
||||
|
||||
func _produce_smbh(desired_amount: float) -> float:
|
||||
var plan: Dictionary = _plan_smbh(desired_amount)
|
||||
var consumed_mass: float = plan.amount
|
||||
var taken: Dictionary = plan.taken
|
||||
if consumed_mass <= 0.0:
|
||||
return 0.0
|
||||
var next: Dictionary = state.duplicate(true)
|
||||
var physical: Dictionary = _physical_amounts(state)
|
||||
for id in taken:
|
||||
if taken[id] <= 0.0:
|
||||
continue
|
||||
next.amount[id] -= taken[id]
|
||||
var fraction: float = taken[id] / physical[id]
|
||||
_scale_batches(next, id, 1.0 - fraction)
|
||||
# Release the consumed owners' share of any resources they held.
|
||||
for resource in next.binds.get(id, {}):
|
||||
var released: float = next.binds[id][resource] * fraction
|
||||
next.binds[id][resource] -= released
|
||||
next.amount[resource] = next.amount.get(resource, 0.0) + released
|
||||
_credit(next, "SMBH", consumed_mass)
|
||||
_append_batch(next, "SMBH", consumed_mass, state.time.datetime, state.time.datetime)
|
||||
_round_object_allocations(next)
|
||||
_refresh_groups(next)
|
||||
_clamp_auto_resources(next)
|
||||
state = next
|
||||
new_state = next
|
||||
refresh_item_amounts()
|
||||
return consumed_mass
|
||||
|
||||
|
||||
func produce(item_id: String, desired_amount: float) -> float:
|
||||
if item_id == "SMBH":
|
||||
return _produce_smbh(desired_amount)
|
||||
# Use special production for S and H
|
||||
if item_id == "S" or item_id == "H":
|
||||
return produce_hs(item_id, desired_amount)
|
||||
@@ -852,6 +930,8 @@ func _whole_gcd(a: float, b: float) -> float:
|
||||
|
||||
|
||||
func calculate_max_producible(entity: OwniverseEntity, desired_amount: float = 1.0E150) -> float:
|
||||
if entity.id == "SMBH":
|
||||
return _plan_smbh(desired_amount).amount
|
||||
var requirements: Dictionary = {}
|
||||
for resource in entity.cost:
|
||||
requirements[resource] = maxf(0.0, entity.cost[resource])
|
||||
@@ -930,9 +1010,9 @@ func consume_from_batches(entity: OwniverseEntity, current_year: float) -> float
|
||||
total += part.amount
|
||||
var fraction: float = clampf(total / physical[entity.id], 0.0, 1.0) if physical.get(entity.id, 0.0) > 0.0 else 0.0
|
||||
state.amount[entity.id] = state.amount.get(entity.id, 0.0) * (1.0 - fraction)
|
||||
for owner in state.binds:
|
||||
if state.binds[owner].has(entity.id):
|
||||
state.binds[owner][entity.id] *= 1.0 - fraction
|
||||
for owner_id in state.binds:
|
||||
if state.binds[owner_id].has(entity.id):
|
||||
state.binds[owner_id][entity.id] *= 1.0 - fraction
|
||||
_round_object_allocations(state)
|
||||
_refresh_groups(state)
|
||||
refresh_item_amounts()
|
||||
@@ -999,8 +1079,6 @@ func _process_enitity(entity_id: String, amount: float) -> void:
|
||||
refresh_item_amounts()
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Time
|
||||
|
||||
Reference in New Issue
Block a user