perf: harden runtime for weaker hardware
This commit is contained in:
@@ -23,6 +23,7 @@ const STRONG_STRENGTH := 5.0
|
||||
const DEFENSE_DECISION_INTERVAL := 200
|
||||
const TRIBE_FOOD_DECAY := 0.05
|
||||
const WOLF_HUNT_RADIUS := 18.0
|
||||
const DEFAULT_TICK_INTERVAL := 1.2
|
||||
const RAID_SPAWN_OFFSET := Vector3(42.0, 0.0, 42.0)
|
||||
const RAID_SPEED := 1.2
|
||||
const RAID_SIZE := 4
|
||||
@@ -32,15 +33,23 @@ var combatants: Dictionary = {}
|
||||
var factions: Dictionary = {}
|
||||
var economy: RefCounted
|
||||
var npcs: Array[SimNPC] = []
|
||||
var _npcs_by_id: Dictionary = {}
|
||||
var next_combatant_id := 0
|
||||
var next_wolf_id := 0
|
||||
var current_tick := 0
|
||||
var village_center := Vector3.ZERO
|
||||
var last_war_resolved_tick := -1
|
||||
var tick_interval := DEFAULT_TICK_INTERVAL
|
||||
var player_attack_cooldown_remaining := 0.0
|
||||
var _sorted_combatant_ids_cache: Array[StringName] = []
|
||||
var _combatant_ids_dirty := true
|
||||
|
||||
|
||||
func configure(economy_service: RefCounted) -> void:
|
||||
func configure(
|
||||
economy_service: RefCounted, simulation_tick_interval: float = DEFAULT_TICK_INTERVAL
|
||||
) -> void:
|
||||
economy = economy_service
|
||||
tick_interval = maxf(simulation_tick_interval, 0.0001)
|
||||
|
||||
|
||||
func initialize_factions() -> void:
|
||||
@@ -69,6 +78,7 @@ func _ensure_player_combatant() -> void:
|
||||
sword.item_id if sword != null else SimulationIds.ITEM_SWORD,
|
||||
CombatantStateRecord.NO_NPC_ID
|
||||
)
|
||||
_combatant_ids_dirty = true
|
||||
|
||||
|
||||
func set_player_combatant_position(position: Vector3) -> void:
|
||||
@@ -87,13 +97,9 @@ func set_player_health(health: float, downed: bool) -> void:
|
||||
player_combatant = get_combatant(PLAYER_COMBATANT_ID)
|
||||
if player_combatant == null:
|
||||
return
|
||||
if not downed and player_combatant.is_alive():
|
||||
var target := clampf(health, 0.0, player_combatant.get_max_health())
|
||||
var current := player_combatant.get_health()
|
||||
if target < current:
|
||||
player_combatant.take_damage(current - target)
|
||||
elif target > current:
|
||||
player_combatant.data["health"] = target
|
||||
player_combatant.set_health_and_alive(health, not downed)
|
||||
if downed:
|
||||
player_attack_cooldown_remaining = 0.0
|
||||
|
||||
|
||||
func is_player_downed() -> bool:
|
||||
@@ -101,8 +107,30 @@ func is_player_downed() -> bool:
|
||||
return player_combatant != null and not player_combatant.is_alive()
|
||||
|
||||
|
||||
func advance_realtime(delta: float) -> void:
|
||||
if not is_finite(delta) or delta <= 0.0:
|
||||
return
|
||||
player_attack_cooldown_remaining = maxf(player_attack_cooldown_remaining - delta, 0.0)
|
||||
|
||||
|
||||
func is_player_attack_ready() -> bool:
|
||||
var player_combatant := get_combatant(PLAYER_COMBATANT_ID)
|
||||
return (
|
||||
player_combatant != null
|
||||
and player_combatant.is_alive()
|
||||
and player_attack_cooldown_remaining <= 0.0
|
||||
)
|
||||
|
||||
|
||||
func get_player_attack_cooldown_remaining() -> float:
|
||||
return player_attack_cooldown_remaining
|
||||
|
||||
|
||||
func register_npc_combatants(npc_list: Array[SimNPC]) -> void:
|
||||
npcs = npc_list
|
||||
_npcs_by_id.clear()
|
||||
for npc in npcs:
|
||||
_npcs_by_id[npc.id] = npc
|
||||
var existing_ids := {}
|
||||
for combatant in combatants.values():
|
||||
var candidate := combatant as CombatantStateRecord
|
||||
@@ -133,6 +161,7 @@ func _create_npc_combatant(npc: SimNPC) -> CombatantStateRecord:
|
||||
npc.id
|
||||
)
|
||||
combatants[combatant.get_combatant_id()] = combatant
|
||||
_combatant_ids_dirty = true
|
||||
return combatant
|
||||
|
||||
|
||||
@@ -170,12 +199,26 @@ func _advance_raider_positions() -> void:
|
||||
|
||||
|
||||
func player_attack(combatant_id: StringName) -> float:
|
||||
var player_combatant := get_combatant(PLAYER_COMBATANT_ID)
|
||||
var combatant := get_combatant(combatant_id)
|
||||
if combatant == null or not combatant.is_alive():
|
||||
if (
|
||||
not is_player_attack_ready()
|
||||
or combatant == null
|
||||
or not combatant.is_alive()
|
||||
or not combatant.is_hostile()
|
||||
or combatant.get_faction_id() == player_combatant.get_faction_id()
|
||||
or (
|
||||
_horizontal_distance(player_combatant.get_position(), combatant.get_position())
|
||||
> _reach(player_combatant)
|
||||
)
|
||||
):
|
||||
return 0.0
|
||||
var sword := SimulationItems.get_weapon(SimulationIds.ITEM_SWORD)
|
||||
var damage := sword.damage if sword != null else 24.0
|
||||
return _apply_damage(combatant, damage, SimulationIds.PLAYER_ACTOR_ID)
|
||||
var applied := _apply_damage(combatant, damage, SimulationIds.PLAYER_ACTOR_ID)
|
||||
if applied > 0.0:
|
||||
player_attack_cooldown_remaining = sword.attack_cooldown if sword != null else 0.6
|
||||
return applied
|
||||
|
||||
|
||||
func spawn_wolf(position: Vector3) -> StringName:
|
||||
@@ -194,6 +237,7 @@ func spawn_wolf(position: Vector3) -> StringName:
|
||||
true
|
||||
)
|
||||
combatants[wolf_id] = wolf
|
||||
_combatant_ids_dirty = true
|
||||
combatant_spawned.emit(wolf_id)
|
||||
return wolf_id
|
||||
|
||||
@@ -225,6 +269,11 @@ func _apply_damage(target: CombatantStateRecord, damage: float, actor_id: int) -
|
||||
|
||||
func _kill_combatant(target: CombatantStateRecord, killer_id: int) -> void:
|
||||
var npc_id := target.get_npc_id()
|
||||
if npc_id >= 0:
|
||||
var npc := _find_npc(npc_id)
|
||||
if npc != null and not npc.is_dead:
|
||||
npc.last_task = npc.current_task
|
||||
npc.die_from_combat()
|
||||
_narrative_event_requested(
|
||||
SimulationIds.EVENT_COMBATANT_KILLED,
|
||||
killer_id,
|
||||
@@ -235,10 +284,6 @@ func _kill_combatant(target: CombatantStateRecord, killer_id: int) -> void:
|
||||
0.0
|
||||
)
|
||||
combatant_died.emit(target.get_combatant_id())
|
||||
if npc_id >= 0:
|
||||
var npc := _find_npc(npc_id)
|
||||
if npc != null and not npc.is_dead:
|
||||
npc.die_from_combat()
|
||||
|
||||
|
||||
func _advance_wolves() -> void:
|
||||
@@ -253,6 +298,17 @@ func _advance_wolves() -> void:
|
||||
continue
|
||||
if not combatant.is_hostile():
|
||||
combatant.set_hostile(true)
|
||||
var reach := _reach(combatant)
|
||||
var to_target := target.get_position() - combatant.get_position()
|
||||
to_target.y = 0.0
|
||||
if to_target.length() > reach:
|
||||
var definition := SimulationEnemies.get_enemy(&"enemy_wolf")
|
||||
var speed := definition.move_speed if definition != null else 3.2
|
||||
var step_distance := minf(speed * tick_interval, to_target.length() - reach)
|
||||
combatant.set_position(
|
||||
combatant.get_position() + to_target.normalized() * maxf(step_distance, 0.0)
|
||||
)
|
||||
continue
|
||||
_attack_target(combatant, target)
|
||||
|
||||
|
||||
@@ -386,6 +442,7 @@ func _start_raid(tribe: FactionStateRecord, simulation_tick: int) -> void:
|
||||
true
|
||||
)
|
||||
combatants[raider_id] = raider
|
||||
_combatant_ids_dirty = true
|
||||
raider_ids.append(raider_id)
|
||||
combatant_spawned.emit(raider_id)
|
||||
raid_started.emit(raider_ids)
|
||||
@@ -456,8 +513,13 @@ func _finish_war(next_plan: StringName, outcome: StringName) -> void:
|
||||
tribe.set_war_plan(next_plan, current_tick)
|
||||
tribe.set_stance(SimulationIds.STANCE_NEUTRAL)
|
||||
if village != null and outcome == &"village_lost":
|
||||
var stolen := minf(village.get_food() * 0.6, 15.0)
|
||||
village.set_food(maxf(village.get_food() - stolen, 0.0))
|
||||
var stolen := 0.0
|
||||
if economy != null:
|
||||
var pantry: StorageStateRecord = economy.get_pantry()
|
||||
if pantry != null:
|
||||
var requested := minf(pantry.get_amount(SimulationIds.RESOURCE_FOOD) * 0.6, 15.0)
|
||||
stolen = economy.withdraw_resource(SimulationIds.RESOURCE_FOOD, requested)
|
||||
village.set_food(pantry.get_amount(SimulationIds.RESOURCE_FOOD))
|
||||
if tribe != null:
|
||||
tribe.set_food(tribe.get_food() + stolen)
|
||||
elif tribe != null:
|
||||
@@ -486,7 +548,7 @@ func _attack_target(attacker: CombatantStateRecord, target: CombatantStateRecord
|
||||
var damage := _attack_damage(attacker)
|
||||
var applied := _apply_damage(target, damage, _actor_id_for(attacker))
|
||||
if applied > 0.0:
|
||||
attacker.mark_attacked()
|
||||
attacker.mark_attacked(tick_interval)
|
||||
|
||||
|
||||
func _attack_damage(attacker: CombatantStateRecord) -> float:
|
||||
@@ -540,6 +602,10 @@ func _reach(combatant: CombatantStateRecord) -> float:
|
||||
return weapon.reach
|
||||
|
||||
|
||||
static func _horizontal_distance(first: Vector3, second: Vector3) -> float:
|
||||
return Vector2(first.x, first.z).distance_to(Vector2(second.x, second.z))
|
||||
|
||||
|
||||
func _actor_id_for(combatant: CombatantStateRecord) -> int:
|
||||
if combatant.get_npc_id() >= 0:
|
||||
return combatant.get_npc_id()
|
||||
@@ -607,22 +673,22 @@ func get_living_hostiles() -> Array[CombatantStateRecord]:
|
||||
return hostiles
|
||||
|
||||
|
||||
func _sorted_combatant_ids() -> Array:
|
||||
func _sorted_combatant_ids() -> Array[StringName]:
|
||||
if not _combatant_ids_dirty:
|
||||
return _sorted_combatant_ids_cache
|
||||
var keys: Array[String] = []
|
||||
for combatant_id in combatants.keys():
|
||||
keys.append(String(combatant_id))
|
||||
keys.sort()
|
||||
var ids: Array = []
|
||||
_sorted_combatant_ids_cache.clear()
|
||||
for key in keys:
|
||||
ids.append(StringName(key))
|
||||
return ids
|
||||
_sorted_combatant_ids_cache.append(StringName(key))
|
||||
_combatant_ids_dirty = false
|
||||
return _sorted_combatant_ids_cache
|
||||
|
||||
|
||||
func _find_npc(npc_id: int) -> SimNPC:
|
||||
for npc in npcs:
|
||||
if npc.id == npc_id:
|
||||
return npc
|
||||
return null
|
||||
return _npcs_by_id.get(npc_id) as SimNPC
|
||||
|
||||
|
||||
func _get_faction(faction_id: StringName) -> FactionStateRecord:
|
||||
@@ -668,9 +734,11 @@ func restore_state_records(
|
||||
restored_tick: int
|
||||
) -> void:
|
||||
current_tick = restored_tick
|
||||
player_attack_cooldown_remaining = 0.0
|
||||
combatants.clear()
|
||||
for combatant in combatant_records:
|
||||
combatants[combatant.get_combatant_id()] = combatant
|
||||
_combatant_ids_dirty = true
|
||||
factions.clear()
|
||||
for faction in faction_records:
|
||||
factions[faction.get_faction_id()] = faction
|
||||
|
||||
Reference in New Issue
Block a user