/ TaskMaster.gd
TaskMaster.gd
 1  extends Node
 2  @onready var pathfinding_service = get_node("/root/MainGame/Simulation/PathfindingService")
 3  @onready var message_bus = get_node("/root/MainGame/NetworkLayer/RPC/MessageBus")
 4  # The master queue of pending tasks
 5  var pending_jobs: Array[Dictionary] = []
 6  var job_id: int = 0
 7  
 8  func _ready():
 9  	Lib.auto_wire_events(self)
10  	if not multiplayer.is_server():
11  		set_process(false)
12  
13  ## Adds a new job to the queue and sorts it by priority
14  func add_job(work_def: String, target_pos: Vector2i, target_object: Node2D = null):
15  	job_id = job_id + 1
16  	if (job_id > 2147483600):
17  		job_id = 0
18  		tLogger.error("Job ID hit max Int probably something cooked")
19  	var dict = Defs.get(work_def)
20  	var new_job = {
21  		"work_name": work_def,
22  		"work_type": dict.work_type,
23  		"level_required": dict.level_required,
24  		"target_pos": target_pos,
25  		"status": "available",
26  		"priority": 1,
27  		"work_left": dict.work_max,
28  		"output": dict.output,
29  		"job_id": job_id
30  	}
31  	# check against duplicate jobs
32  	if _is_job_already_queued(new_job):
33  		return
34  		
35  	pending_jobs.append(new_job)
36  	_sort_queue()
37  	tLogger.info("TaskMaster: Added job " + str(dict.work_type) + " at " + str(target_pos) + " and ID: " + str(job_id))
38  
39  
40  func get_next_available_job(colonist: Node2D) -> Dictionary:
41  	if pending_jobs.is_empty():
42  		tLogger.warn("no jobs available in taskmaster>get_next_available_job")
43  		return {} 
44  	var min_distance = INF
45  	var closest_job = -1
46  	for i in range(pending_jobs.size()):
47  		var job = pending_jobs[i]
48  		var target_pos = job.get("target_pos")
49  		if job.get("status") != "available":
50  			continue
51  		# Check if the colonist has the skill (expand this later)
52  		if not _can_colonist_do_job(colonist, job):
53  			continue
54  		if not pathfinding_service.short_reachability_check(target_pos):
55  			continue
56  		var distance = pathfinding_service.get_distance(Lib.get_grid_position(colonist.global_position),target_pos)
57  		if distance < min_distance:
58  			closest_job = i
59  			min_distance = distance
60  	if closest_job != -1:
61  		pending_jobs[closest_job].status = "claimed"
62  		return pending_jobs[closest_job]
63  	return {} 
64  
65  func finish_work(work: int):
66  	for i in pending_jobs.size():
67  		if pending_jobs[i].job_id == work:
68  			if pending_jobs[i].output != "":
69  				message_bus.sync_item_dropped.rpc(pending_jobs[i].output, 5, pending_jobs[i].target_pos)
70  			message_bus.sync_structure_changed.rpc("structure_dict_clear", pending_jobs[i].target_pos)
71  			tLogger.info("Job " + str(pending_jobs[i].job_id) + " completed and removed.")
72  			pending_jobs.pop_at(i)
73  			return
74  	
75  #func _on_work_changed(job_id :int, amount: float):
76  #	pass
77  
78  func _sort_queue():
79  	#to do sort into different queues for different work types
80  	pending_jobs.sort_custom(func(a, b): return a["priority"] < b["priority"])
81  
82  ## Helper: Prevents identical tasks from stacking
83  func _is_job_already_queued(new_job: Dictionary) -> bool:
84  	for job in pending_jobs:
85  		if job.get("work_type") == new_job["work_type"] and job.get("target_pos") == new_job["target_pos"]:
86  			return true
87  	return false
88  
89  
90  
91  func _can_colonist_do_job(_colonist: Node2D, _job: Dictionary) -> bool:
92  	# Future: if job["type"] == "mine" and colonist.mining_skill == 0: return false
93  	return true # Currently, anyone can do anything