removing intended_commands
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
use rsbwapi::{Order, Position, Unit, UnitType, UpgradeType};
|
use rsbwapi::{UnitType, UpgradeType};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::state::build_stages::BuildStage;
|
use crate::state::build_stages::BuildStage;
|
||||||
|
|
||||||
pub struct GameState {
|
pub struct GameState {
|
||||||
pub intended_commands: HashMap<usize, IntendedCommand>,
|
|
||||||
pub unit_build_history: Vec<BuildHistoryEntry>,
|
pub unit_build_history: Vec<BuildHistoryEntry>,
|
||||||
pub build_stages: Vec<BuildStage>,
|
pub build_stages: Vec<BuildStage>,
|
||||||
pub current_stage_index: usize,
|
pub current_stage_index: usize,
|
||||||
@@ -15,7 +14,6 @@ pub struct GameState {
|
|||||||
impl Default for GameState {
|
impl Default for GameState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
intended_commands: HashMap::new(),
|
|
||||||
unit_build_history: Vec::new(),
|
unit_build_history: Vec::new(),
|
||||||
build_stages: crate::state::build_stages::get_build_stages(),
|
build_stages: crate::state::build_stages::get_build_stages(),
|
||||||
current_stage_index: 0,
|
current_stage_index: 0,
|
||||||
@@ -25,13 +23,6 @@ impl Default for GameState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct IntendedCommand {
|
|
||||||
pub order: Order,
|
|
||||||
pub target_position: Option<Position>,
|
|
||||||
pub target_unit: Option<Unit>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum BuildStatus {
|
pub enum BuildStatus {
|
||||||
Assigned,
|
Assigned,
|
||||||
|
|||||||
@@ -1,65 +1,25 @@
|
|||||||
use rsbwapi::{Game, Order, Player, Unit, UnitType};
|
use rsbwapi::{Game, Player, Unit, UnitType};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
state::game_state::{BuildHistoryEntry, GameState, IntendedCommand},
|
state::game_state::{BuildHistoryEntry, GameState},
|
||||||
utils::build_location_utils,
|
utils::build_location_utils,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn on_frame(game: &Game, player: &Player, state: &mut GameState) {
|
pub fn on_frame(game: &Game, player: &Player, state: &mut GameState) {
|
||||||
cleanup_stale_commands(player, state);
|
// No intended command tracking; directly manage builds and stages.
|
||||||
check_and_advance_stage(player, state);
|
check_and_advance_stage(player, state);
|
||||||
state.stage_item_status = get_status_for_stage_items(game, player, state);
|
state.stage_item_status = get_status_for_stage_items(game, player, state);
|
||||||
try_start_next_build(game, player, state);
|
try_start_next_build(game, player, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_building_create(unit: &Unit, state: &mut GameState) {
|
pub fn on_building_create(_unit: &Unit, _state: &mut GameState) {
|
||||||
// When a building is created, clear any intended command for the worker that was assigned to build it.
|
// No intended command tracking needed.
|
||||||
if let Some(entry) = state
|
|
||||||
.unit_build_history
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.find(|e| e.unit_type == Some(unit.get_type()))
|
|
||||||
{
|
|
||||||
if let Some(builder_id) = entry.assigned_unit_id {
|
|
||||||
state.intended_commands.remove(&builder_id);
|
|
||||||
println!(
|
|
||||||
"Building {} started. Removed assignment for worker {}",
|
|
||||||
unit.get_type().name(),
|
|
||||||
builder_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when a non‑building unit (e.g., a trained unit) is created.
|
/// Called when a non‑building unit (e.g., a trained unit) is created.
|
||||||
/// This clears any pending assignment for the building that trained it.
|
/// This clears any pending assignment for the building that trained it.
|
||||||
pub fn on_unit_create(unit: &Unit, state: &mut GameState) {
|
pub fn on_unit_create(_unit: &Unit, _state: &mut GameState) {
|
||||||
// Find the most recent history entry for this unit type.
|
// No intended command tracking needed for unit creation.
|
||||||
if let Some(entry) = state
|
|
||||||
.unit_build_history
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.find(|e| e.unit_type == Some(unit.get_type()))
|
|
||||||
{
|
|
||||||
if let Some(builder_id) = entry.assigned_unit_id {
|
|
||||||
// For training, we didn't store an intended command, but clear just in case.
|
|
||||||
state.intended_commands.remove(&builder_id);
|
|
||||||
println!(
|
|
||||||
"Unit {} created. Cleared assignment for builder {}",
|
|
||||||
unit.get_type().name(),
|
|
||||||
builder_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cleanup_stale_commands(player: &Player, state: &mut GameState) {
|
|
||||||
// Retain intended commands as long as the unit still exists.
|
|
||||||
// The command will be cleared when the building/unit is created (on_building_create) or when the unit dies.
|
|
||||||
let unit_ids: Vec<usize> = player.get_units().iter().map(|u| u.get_id()).collect();
|
|
||||||
state
|
|
||||||
.intended_commands
|
|
||||||
.retain(|unit_id, _cmd| unit_ids.contains(unit_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_start_next_build(game: &Game, player: &Player, state: &mut GameState) {
|
fn try_start_next_build(game: &Game, player: &Player, state: &mut GameState) {
|
||||||
@@ -84,7 +44,6 @@ fn try_start_next_build(game: &Game, player: &Player, state: &mut GameState) {
|
|||||||
tile_position: tile_pos,
|
tile_position: tile_pos,
|
||||||
};
|
};
|
||||||
state.unit_build_history.push(entry);
|
state.unit_build_history.push(entry);
|
||||||
let current_stage = &state.build_stages[state.current_stage_index];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +53,6 @@ fn should_start_next_build(_game: &Game, player: &Player, state: &mut GameState)
|
|||||||
!has_ongoing_constructions(state, player)
|
!has_ongoing_constructions(state, player)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removed: pending assignment tracking now relies on actual unit state via has_ongoing_constructions.
|
|
||||||
|
|
||||||
fn has_ongoing_constructions(state: &GameState, player: &Player) -> bool {
|
fn has_ongoing_constructions(state: &GameState, player: &Player) -> bool {
|
||||||
state.unit_build_history.iter().any(|entry| {
|
state.unit_build_history.iter().any(|entry| {
|
||||||
if let Some(unit_id) = entry.assigned_unit_id {
|
if let Some(unit_id) = entry.assigned_unit_id {
|
||||||
@@ -200,7 +157,7 @@ fn check_need_more_supply(_game: &Game, player: &Player, _state: &GameState) ->
|
|||||||
fn find_builder_for_unit(
|
fn find_builder_for_unit(
|
||||||
player: &Player,
|
player: &Player,
|
||||||
unit_type: UnitType,
|
unit_type: UnitType,
|
||||||
state: &GameState,
|
_state: &GameState,
|
||||||
) -> Option<rsbwapi::Unit> {
|
) -> Option<rsbwapi::Unit> {
|
||||||
let builder_type = unit_type.what_builds().0;
|
let builder_type = unit_type.what_builds().0;
|
||||||
player
|
player
|
||||||
@@ -211,7 +168,6 @@ fn find_builder_for_unit(
|
|||||||
&& !u.is_constructing()
|
&& !u.is_constructing()
|
||||||
&& !u.is_training()
|
&& !u.is_training()
|
||||||
&& (u.is_idle() || u.is_gathering_minerals() || u.is_gathering_gas())
|
&& (u.is_idle() || u.is_gathering_minerals() || u.is_gathering_gas())
|
||||||
&& !state.intended_commands.contains_key(&u.get_id())
|
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,28 @@
|
|||||||
use rsbwapi::{Game, Order, Player, Unit};
|
use rsbwapi::{Game, Player, Unit};
|
||||||
|
|
||||||
use crate::state::game_state::{GameState, IntendedCommand};
|
use crate::state::game_state::GameState;
|
||||||
|
|
||||||
pub fn assign_idle_workers_to_minerals(game: &Game, player: &Player, state: &mut GameState) {
|
pub fn assign_idle_workers_to_minerals(game: &Game, player: &Player, state: &mut GameState) {
|
||||||
let all_units = player.get_units();
|
let all_units = player.get_units();
|
||||||
let workers: Vec<Unit> = all_units
|
let workers: Vec<Unit> = all_units
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|u| u.get_type().is_worker() && u.is_completed())
|
.filter(|u| {
|
||||||
|
// Worker must be a completed worker unit
|
||||||
|
u.get_type().is_worker() && u.is_completed()
|
||||||
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Assign idle workers to mining
|
// Assign idle workers that are not already assigned in the build history
|
||||||
for worker in workers {
|
for worker in workers {
|
||||||
|
// Skip if this worker is already recorded as assigned in any ongoing build history entry
|
||||||
|
let already_assigned = state
|
||||||
|
.unit_build_history
|
||||||
|
.iter()
|
||||||
|
.any(|entry| entry.assigned_unit_id == Some(worker.get_id()));
|
||||||
|
if already_assigned {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
assign_worker_to_mineral(game, &worker, state);
|
assign_worker_to_mineral(game, &worker, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,32 +30,26 @@ pub fn assign_idle_workers_to_minerals(game: &Game, player: &Player, state: &mut
|
|||||||
fn assign_worker_to_mineral(game: &Game, worker: &Unit, state: &mut GameState) {
|
fn assign_worker_to_mineral(game: &Game, worker: &Unit, state: &mut GameState) {
|
||||||
let worker_id = worker.get_id();
|
let worker_id = worker.get_id();
|
||||||
|
|
||||||
if let Some(cmd) = state.intended_commands.get(&worker_id) {
|
// Skip if the worker is currently assigned to an in‑progress building construction.
|
||||||
if cmd.order != Order::MiningMinerals {
|
let has_in_progress_build = state.unit_build_history.iter().any(|entry| {
|
||||||
return;
|
entry.assigned_unit_id == Some(worker_id)
|
||||||
}
|
&& entry.unit_type.map(|ut| ut.is_building()).unwrap_or(false)
|
||||||
}
|
});
|
||||||
|
if has_in_progress_build {
|
||||||
if !worker.is_idle() {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if worker.is_gathering_minerals() || worker.is_gathering_gas() {
|
// Worker must be idle and not already gathering resources.
|
||||||
|
if !worker.is_idle() || worker.is_gathering_minerals() || worker.is_gathering_gas() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find a mineral patch to assign.
|
||||||
let Some(mineral) = find_available_mineral(game, worker, state) else {
|
let Some(mineral) = find_available_mineral(game, worker, state) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let intended_cmd = IntendedCommand {
|
// Assign worker to gather minerals (ignore intended command tracking).
|
||||||
order: Order::MiningMinerals,
|
|
||||||
target_position: None,
|
|
||||||
target_unit: Some(mineral.clone()),
|
|
||||||
};
|
|
||||||
|
|
||||||
state.intended_commands.insert(worker_id, intended_cmd);
|
|
||||||
|
|
||||||
if worker.gather(&mineral).is_ok() {
|
if worker.gather(&mineral).is_ok() {
|
||||||
println!(
|
println!(
|
||||||
"Assigned worker {} to mine from mineral at {:?}",
|
"Assigned worker {} to mine from mineral at {:?}",
|
||||||
@@ -54,34 +59,17 @@ fn assign_worker_to_mineral(game: &Game, worker: &Unit, state: &mut GameState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_available_mineral(game: &Game, worker: &Unit, state: &GameState) -> Option<Unit> {
|
fn find_available_mineral(game: &Game, worker: &Unit, _state: &GameState) -> Option<Unit> {
|
||||||
let worker_pos = worker.get_position();
|
let worker_pos = worker.get_position();
|
||||||
let minerals = game.get_static_minerals();
|
let minerals = game.get_static_minerals();
|
||||||
let mut mineral_list: Vec<Unit> = minerals.iter().filter(|m| m.exists()).cloned().collect();
|
let mut mineral_list: Vec<Unit> = minerals.iter().filter(|m| m.exists()).cloned().collect();
|
||||||
|
|
||||||
|
// Sort minerals by distance to the worker.
|
||||||
mineral_list.sort_by_key(|m| {
|
mineral_list.sort_by_key(|m| {
|
||||||
let pos = m.get_position();
|
let pos = m.get_position();
|
||||||
((pos.x - worker_pos.x).pow(2) + (pos.y - worker_pos.y).pow(2)) as i32
|
((pos.x - worker_pos.x).pow(2) + (pos.y - worker_pos.y).pow(2)) as i32
|
||||||
});
|
});
|
||||||
|
|
||||||
for mineral in mineral_list.iter() {
|
// Return the closest mineral, ignoring any intended command tracking.
|
||||||
let mineral_id: usize = mineral.get_id();
|
|
||||||
|
|
||||||
let worker_count = state
|
|
||||||
.intended_commands
|
|
||||||
.values()
|
|
||||||
.filter(|cmd| {
|
|
||||||
if let Some(target) = &cmd.target_unit {
|
|
||||||
target.get_id() == mineral_id
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.count();
|
|
||||||
|
|
||||||
if worker_count < 2 {
|
|
||||||
return Some(mineral.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mineral_list.first().cloned()
|
mineral_list.first().cloned()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user