feat: add completition of work only after work is done

This commit is contained in:
Rijad Zuzo
2026-06-21 00:11:34 +02:00
parent 8a85c6fbba
commit 052b36a4e7
5 changed files with 109 additions and 20 deletions
+17 -5
View File
@@ -49,6 +49,7 @@ height = 5.774
[sub_resource type="BoxMesh" id="BoxMesh_kek77"] [sub_resource type="BoxMesh" id="BoxMesh_kek77"]
[sub_resource type="PrismMesh" id="PrismMesh_5vw27"] [sub_resource type="PrismMesh" id="PrismMesh_5vw27"]
size = Vector3(3, 5, 2)
[sub_resource type="BoxMesh" id="BoxMesh_4c57u"] [sub_resource type="BoxMesh" id="BoxMesh_4c57u"]
@@ -146,30 +147,41 @@ mesh = SubResource("BoxMesh_5vw27")
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 0, -6) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 0, -6)
[node name="smallTree" parent="TaskZone/ForestZone" instance=ExtResource("6_5vw27")] [node name="smallTree" parent="TaskZone/ForestZone" instance=ExtResource("6_5vw27")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.13034248, 0.23380828, -0.6683569) transform = Transform3D(3, 0, 0, 0, 3, 0, 0, 0, 3, 1.891, 0, -0.22)
[node name="smallTree2" parent="TaskZone/ForestZone" instance=ExtResource("6_5vw27")]
transform = Transform3D(2, 0, 0, 0, 2, 0, 0, 0, 2, -0.043, 0, -1.767)
[node name="smallTree3" parent="TaskZone/ForestZone" instance=ExtResource("6_5vw27")]
transform = Transform3D(3, 0, 0, 0, 3, 0, 0, 0, 3, 0.13, 0, 0.614)
[node name="highTree" parent="TaskZone/ForestZone" instance=ExtResource("7_kek77")] [node name="highTree" parent="TaskZone/ForestZone" instance=ExtResource("7_kek77")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.78092957, 0.23380828, 0.17081833) transform = Transform3D(3, 0, 0, 0, 3, 0, 0, 0, 3, -1.539, 0, 0.171)
[node name="GuardZone" type="Marker3D" parent="TaskZone"] [node name="GuardZone" type="Marker3D" parent="TaskZone"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 8) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 8)
[node name="MeshInstance3D" type="MeshInstance3D" parent="TaskZone/GuardZone"] [node name="MeshInstance3D" type="MeshInstance3D" parent="TaskZone/GuardZone"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.354011, 0)
mesh = SubResource("CylinderMesh_5vw27") mesh = SubResource("CylinderMesh_5vw27")
[node name="StudyZone" type="Marker3D" parent="TaskZone"] [node name="StudyZone" type="Marker3D" parent="TaskZone"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 0, 6) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 0, 6)
[node name="MeshInstance3D" type="MeshInstance3D" parent="TaskZone/StudyZone"] [node name="MeshInstance3D" type="MeshInstance3D" parent="TaskZone/StudyZone"]
transform = Transform3D(1, 0, 0, 0, 10, 0, 0, 0, 1, 0, 5, 0) transform = Transform3D(3.279775, 0, 0, 0, 5.511466, 0, 0, 0, 1, 0, 2.8180213, 0)
mesh = SubResource("BoxMesh_kek77") mesh = SubResource("BoxMesh_kek77")
metadata/_edit_group_ = true
[node name="RestZone" type="Marker3D" parent="TaskZone"] [node name="RestZone" type="Marker3D" parent="TaskZone"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, 5) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, 5)
[node name="MeshInstance3D" type="MeshInstance3D" parent="TaskZone/RestZone"] [node name="MeshInstance3D" type="MeshInstance3D" parent="TaskZone/RestZone"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.4911091, 0)
mesh = SubResource("PrismMesh_5vw27")
[node name="MeshInstance3D2" type="MeshInstance3D" parent="TaskZone/RestZone"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.3897309, 1.399735, 1.0352364)
mesh = SubResource("PrismMesh_5vw27") mesh = SubResource("PrismMesh_5vw27")
[node name="FoodZone" type="Marker3D" parent="TaskZone"] [node name="FoodZone" type="Marker3D" parent="TaskZone"]
+27
View File
@@ -1,5 +1,7 @@
extends CharacterBody3D extends CharacterBody3D
signal arrived_at_target(sim_id: int)
const DEBUG_LOGS := false const DEBUG_LOGS := false
@export var move_speed := 3.0 @export var move_speed := 3.0
@@ -8,6 +10,7 @@ const DEBUG_LOGS := false
@onready var nav_agent: NavigationAgent3D = $NavigationAgent3D @onready var nav_agent: NavigationAgent3D = $NavigationAgent3D
var has_reported_arrival := false
var sim_id: int = -1 var sim_id: int = -1
var npc_name: String = "" var npc_name: String = ""
var profession: String = "" var profession: String = ""
@@ -30,6 +33,24 @@ func set_target_position(pos: Vector3) -> void:
if current_target.distance_to(pos) < 0.1: if current_target.distance_to(pos) < 0.1:
return return
current_target = pos
has_reported_arrival = false
nav_agent.target_position = pos
await get_tree().physics_frame
current_path = NavigationServer3D.map_get_path(
get_world_3d().navigation_map,
global_position,
pos,
true
)
path_index = 0
debug_log("New target: %s Path points: %s" % [pos, current_path.size()])
if current_target.distance_to(pos) < 0.1:
return
current_target = pos current_target = pos
nav_agent.target_position = pos nav_agent.target_position = pos
@@ -50,6 +71,12 @@ func _physics_process(delta: float) -> void:
if current_path.is_empty() or path_index >= current_path.size(): if current_path.is_empty() or path_index >= current_path.size():
velocity = Vector3.ZERO velocity = Vector3.ZERO
move_and_slide() move_and_slide()
if not has_reported_arrival and current_target != Vector3.INF:
has_reported_arrival = true
debug_log("Arrived at target")
arrived_at_target.emit(sim_id)
return return
var next_pos := current_path[path_index] var next_pos := current_path[path_index]
+25 -11
View File
@@ -1,6 +1,11 @@
class_name SimNPC class_name SimNPC
extends RefCounted extends RefCounted
const TASK_STATE_IDLE := "idle"
const TASK_STATE_TRAVELING := "traveling"
const TASK_STATE_WORKING := "working"
const TASK_STATE_COMPLETE := "complete"
var id: int var id: int
var npc_name: String var npc_name: String
var profession: String var profession: String
@@ -9,6 +14,7 @@ var energy: float
var strength: float var strength: float
var intelligence: float var intelligence: float
var current_task: String = "idle" var current_task: String = "idle"
var task_state: String = TASK_STATE_IDLE
var position: Vector3 var position: Vector3
var is_starving := false var is_starving := false
@@ -31,7 +37,6 @@ func _init(
intelligence = _intelligence intelligence = _intelligence
hunger = randf_range(20.0, 80.0) hunger = randf_range(20.0, 80.0)
energy = randf_range(40.0, 100.0) energy = randf_range(40.0, 100.0)
position = Vector3(randf_range(-8.0, 8.0), 0.0, randf_range(-8.0, 8.0)) position = Vector3(randf_range(-8.0, 8.0), 0.0, randf_range(-8.0, 8.0))
func simulate_tick(village: SimVillage) -> void: func simulate_tick(village: SimVillage) -> void:
@@ -48,30 +53,30 @@ func simulate_tick(village: SimVillage) -> void:
energy = clamp(energy, 0.0, 100.0) energy = clamp(energy, 0.0, 100.0)
if not task_complete: if task_state == TASK_STATE_IDLE or task_state == TASK_STATE_COMPLETE:
task_progress += 1.0 choose_new_task(village)
if task_progress >= task_duration:
task_complete = true
return return
choose_new_task(village) if task_state == TASK_STATE_TRAVELING:
return
if task_state == TASK_STATE_WORKING:
task_progress += 1.0
if task_progress >= task_duration:
task_complete = true
task_state = TASK_STATE_COMPLETE
func choose_new_task(village: SimVillage) -> void: func choose_new_task(village: SimVillage) -> void:
task_progress = 0.0
task_complete = false
if hunger > 75.0: if hunger > 75.0:
if village.food > 0: if village.food > 0:
set_task("eat", 2.0) set_task("eat", 2.0)
hunger -= 25.0
else: else:
set_task("gather_food", 5.0) set_task("gather_food", 5.0)
return return
if energy < 30.0: if energy < 30.0:
set_task("rest", 4.0) set_task("rest", 4.0)
energy += 20.0
return return
if village.food < 15.0: if village.food < 15.0:
@@ -107,3 +112,12 @@ func set_task(task: String, duration: float) -> void:
task_duration = duration task_duration = duration
task_progress = 0.0 task_progress = 0.0
task_complete = false task_complete = false
task_state = TASK_STATE_TRAVELING
func start_working() -> void:
if task_state != TASK_STATE_TRAVELING:
return
task_state = TASK_STATE_WORKING
task_progress = 0.0
task_complete = false
+20
View File
@@ -56,6 +56,7 @@ func simulate_tick() -> void:
for npc in npcs: for npc in npcs:
var old_task := npc.current_task var old_task := npc.current_task
var old_state := npc.task_state
var was_complete := npc.task_complete var was_complete := npc.task_complete
npc.simulate_tick(village) npc.simulate_tick(village)
@@ -67,6 +68,10 @@ func simulate_tick() -> void:
village.apply_npc_task(npc) village.apply_npc_task(npc)
village_was_changed = true village_was_changed = true
npc.task_complete = true
npc.task_state = SimNPC.TASK_STATE_IDLE
npc.current_task = "idle"
if DEBUG_LOGS: if DEBUG_LOGS:
print( print(
npc.npc_name, npc.npc_name,
@@ -74,6 +79,8 @@ func simulate_tick() -> void:
npc.profession, npc.profession,
" | task: ", " | task: ",
npc.current_task, npc.current_task,
" | state: ",
npc.task_state,
" | progress: ", " | progress: ",
npc.task_progress, npc.task_progress,
"/", "/",
@@ -86,12 +93,25 @@ func simulate_tick() -> void:
round(npc.energy) round(npc.energy)
) )
if old_state != npc.task_state:
print("[SimulationManager] State changed: ", npc.npc_name, " ", old_state, " -> ", npc.task_state)
if village_was_changed: if village_was_changed:
village_changed.emit(village) village_changed.emit(village)
if DEBUG_LOGS: if DEBUG_LOGS:
print(village.get_summary()) print(village.get_summary())
func notify_npc_arrived(npc_id: int) -> void:
for npc in npcs:
if npc.id == npc_id:
if npc.task_state == SimNPC.TASK_STATE_TRAVELING:
npc.start_working()
if DEBUG_LOGS:
print("[SimulationManager] ", npc.npc_name, " arrived and started working on: ", npc.current_task)
return
func eat_food(amount: float) -> void: func eat_food(amount: float) -> void:
village.food -= amount village.food -= amount
village_changed.emit(village) village_changed.emit(village)
+17 -1
View File
@@ -61,8 +61,12 @@ func spawn_npc_visual(npc: SimNPC) -> void:
visual.global_position = npc.position visual.global_position = npc.position
visual.setup_from_sim(npc) visual.setup_from_sim(npc)
active_npc_visuals[npc.id] = visual if visual.has_signal("arrived_at_target"):
visual.arrived_at_target.connect(_on_npc_visual_arrived)
else:
push_error("WorldViewManager: NPCVisual has no arrived_at_target signal")
active_npc_visuals[npc.id] = visual
debug_log("Spawned visual for %s at %s" % [npc.npc_name, npc.position]) debug_log("Spawned visual for %s at %s" % [npc.npc_name, npc.position])
func update_npc_targets() -> void: func update_npc_targets() -> void:
@@ -111,3 +115,15 @@ func _on_npc_task_changed(npc: SimNPC, old_task: String, new_task: String) -> vo
if target != null: if target != null:
visual.set_target_position(target.global_position) visual.set_target_position(target.global_position)
func _on_npc_visual_arrived(sim_id: int) -> void:
debug_log("NPC visual arrived. sim_id=%s" % sim_id)
if simulation_manager == null:
push_error("WorldViewManager: simulation_manager missing during arrival report")
return
if simulation_manager.has_method("notify_npc_arrived"):
simulation_manager.notify_npc_arrived(sim_id)
else:
push_error("WorldViewManager: SimulationManager has no notify_npc_arrived method")