use super::*;
use crate::tracker_events::unit_tag_index;
use crate::*;
pub const GAME_EVENT_POS_RATIO: f32 = 4096f32;
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn handle_camera_save(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
camera_save: CameraSaveEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
if let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id) {
user_state.camera_pos.x = camera_save.m_target.x;
user_state.camera_pos.y = camera_save.m_target.y;
}
(
ReplayGameEvent::CameraSave(camera_save),
UnitChangeHint::None,
)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn handle_camera_update(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
camera_update: CameraUpdateEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
if let Some(target) = &camera_update.m_target
&& let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id)
{
user_state.camera_pos.x = target.x;
user_state.camera_pos.y = target.y;
}
(
ReplayGameEvent::CameraUpdate(camera_update),
UnitChangeHint::None,
)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn handle_cmd(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
mut cmd: GameSCmdEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
let target = if let GameSCmdData::TargetUnit(tu) = &cmd.m_data {
sc2_state.units.get(&tu.m_tag).cloned()
} else {
None
};
let mut user_selected_unit_ids: Vec<u32> = vec![];
let mut user_selected_units: Vec<SC2Unit> = vec![];
if let Some(state) = sc2_state.user_state.get(&user_id) {
user_selected_unit_ids = state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
}
for selected_unit in &user_selected_unit_ids {
let unit_index = unit_tag_index(*selected_unit as i64);
if let Some(ref mut registered_unit) = sc2_state.units.get_mut(&unit_index) {
match cmd.m_abil {
None => continue,
Some(ref mut val) => {
val.ability = get_indexed_ability_command_name(
&sc2_state.balance_units,
registered_unit.name.as_str(),
val.m_abil_link,
val.m_abil_cmd_index,
);
}
};
tracing::debug!(
"Unit {} executing command: {:?} on target: {:?}",
registered_unit.name,
cmd.m_abil,
target,
);
registered_unit.cmd = cmd.clone().into();
registered_unit.cmd.other_unit_name = target.as_ref().map(|u| u.name.clone());
registered_unit.last_game_loop = game_loop;
user_selected_units.push(registered_unit.clone());
}
}
(
ReplayGameEvent::Cmd(cmd.clone()),
UnitChangeHint::Abilities {
units: user_selected_units,
event: cmd,
target,
},
)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn handle_update_target_point(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
target_point: GameSCmdUpdateTargetPointEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
let mut user_selected_unit_ids: Vec<u32> = vec![];
let mut user_selected_units: Vec<SC2Unit> = vec![];
if let Some(state) = sc2_state.user_state.get(&user_id) {
user_selected_unit_ids = state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
}
for selected_unit in &user_selected_unit_ids {
let unit_index = unit_tag_index(*selected_unit as i64);
if let Some(ref mut registered_unit) = sc2_state.units.get_mut(&unit_index) {
registered_unit
.cmd
.set_data_target_point(target_point.m_target.clone());
registered_unit.cmd.other_unit = None;
registered_unit.last_game_loop = game_loop;
user_selected_units.push(registered_unit.clone());
} else {
tracing::error!(
"handle_update_target_point Unable to locate selected unit {} for user_id {}",
selected_unit,
user_id
);
}
}
(
ReplayGameEvent::CmdUpdateTargetPoint(target_point),
UnitChangeHint::TargetPoints(user_selected_units),
)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn handle_update_target_unit(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
target_unit: GameSCmdUpdateTargetUnitEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
let registered_target_unit = match sc2_state.units.get(&target_unit.m_target.m_tag) {
Some(x) => x.clone(),
None => {
match sc2_state
.units
.get(&unit_tag_index(target_unit.m_target.m_tag.into()))
{
Some(x) => x.clone(),
None => {
tracing::warn!(
"Unit not found for target unit: {}",
target_unit.m_target.m_tag
);
return (
ReplayGameEvent::CmdUpdateTargetUnit(target_unit),
UnitChangeHint::None,
);
}
}
}
};
let mut user_selected_unit_ids: Vec<u32> = vec![];
let mut user_selected_units: Vec<SC2Unit> = vec![];
if let Some(state) = sc2_state.user_state.get(&user_id) {
user_selected_unit_ids = state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
}
for selected_unit in &user_selected_unit_ids {
let unit_index = unit_tag_index(*selected_unit as i64);
if let Some(ref mut registered_unit) = sc2_state.units.get_mut(&unit_index) {
registered_unit
.cmd
.set_data_target_unit(target_unit.m_target.clone().into());
registered_unit.last_game_loop = game_loop;
user_selected_units.push(registered_unit.clone());
} else {
tracing::error!(
"handle_update_target_unit Unable to locate selected unit {} for user_id {}",
selected_unit,
user_id
);
}
}
(
ReplayGameEvent::CmdUpdateTargetUnit(target_unit),
UnitChangeHint::TargetUnits {
units: user_selected_units,
target: Box::new(registered_target_unit),
},
)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn unmark_previously_selected_units(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
) -> UnitChangeHint {
let mut updated_unit_ids = vec![];
if let Some(state) = sc2_state.user_state.get_mut(&user_id) {
for prev_unit in &state.control_groups[ACTIVE_UNITS_GROUP_IDX] {
let unit_index = unit_tag_index(*prev_unit as i64);
if let Some(ref mut unit) = sc2_state.units.get_mut(&unit_index) {
if unit.is_selected {
unit.is_selected = false;
unit.radius *= 0.5;
updated_unit_ids.push(unit_index);
}
unit.last_game_loop = game_loop;
}
}
}
let updated_units = updated_unit_ids
.iter()
.filter_map(|id| sc2_state.units.get(id))
.cloned()
.collect();
UnitChangeHint::Selection(updated_units)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn mark_selected_units(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
_user_id: i64,
selected_units: &[u32],
) -> UnitChangeHint {
let mut updated_unit_ids = vec![];
for new_selected_unit in selected_units {
let unit_index = unit_tag_index(*new_selected_unit as i64);
if let Some(ref mut unit) = sc2_state.units.get_mut(&unit_index) {
if !unit.is_selected {
unit.is_selected = true;
unit.radius *= 2.0;
updated_unit_ids.push(unit_index);
}
unit.last_game_loop = game_loop;
}
}
let updated_units = updated_unit_ids
.iter()
.filter_map(|id| sc2_state.units.get(id))
.cloned()
.collect();
UnitChangeHint::Selection(updated_units)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn handle_selection_delta(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
selection_delta: GameSSelectionDeltaEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
let mut updated_units = vec![];
if selection_delta.m_control_group_id == ACTIVE_UNITS_GROUP_IDX as u8 {
let mut unmarked_units =
match unmark_previously_selected_units(sc2_state, game_loop, user_id) {
UnitChangeHint::Selection(units) => units,
_ => unreachable!(),
};
updated_units.append(&mut unmarked_units);
let mut marked_units = match mark_selected_units(
sc2_state,
game_loop,
user_id,
&selection_delta.m_delta.m_add_unit_tags,
) {
UnitChangeHint::Selection(units) => units,
_ => unreachable!(),
};
updated_units.append(&mut marked_units);
}
if let Some(ref mut state) = sc2_state.user_state.get_mut(&user_id) {
state.control_groups[selection_delta.m_control_group_id as usize] =
selection_delta.m_delta.m_add_unit_tags.clone();
}
updated_units.sort_unstable();
updated_units.dedup();
(
ReplayGameEvent::SelectionDelta(selection_delta),
UnitChangeHint::Selection(updated_units),
)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn update_control_group(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
ctrl_group_evt: GameSControlGroupUpdateEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
let mut updated_units = match unmark_previously_selected_units(sc2_state, game_loop, user_id) {
UnitChangeHint::Selection(units) => units,
_ => unreachable!(),
};
match ctrl_group_evt.m_control_group_update {
GameEControlGroupUpdate::ESet => {
if let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id) {
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize] =
user_state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
}
}
GameEControlGroupUpdate::ESetAndSteal => {
if let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id) {
let current_selected_units =
user_state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
for group_idx in 0..9 {
for unit in ¤t_selected_units {
user_state.control_groups[group_idx].retain(|&x| x != *unit);
}
}
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize] =
user_state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
}
}
GameEControlGroupUpdate::EClear => {
if let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id) {
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize] = vec![];
}
}
GameEControlGroupUpdate::EAppend => {
if let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id) {
let mut current_selected_units =
user_state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize]
.append(&mut current_selected_units);
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize]
.sort_unstable();
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize].dedup();
}
}
GameEControlGroupUpdate::EAppendAndSteal => {
if let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id) {
let mut current_selected_units =
user_state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
for group_idx in 0..9 {
for unit in ¤t_selected_units {
user_state.control_groups[group_idx].retain(|&x| x != *unit);
}
}
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize]
.append(&mut current_selected_units);
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize]
.sort_unstable();
user_state.control_groups[ctrl_group_evt.m_control_group_index as usize].dedup();
}
}
GameEControlGroupUpdate::ERecall => {
let mut current_selected_units: Vec<u32> = vec![];
if let Some(ref mut user_state) = sc2_state.user_state.get_mut(&user_id) {
user_state.control_groups[ACTIVE_UNITS_GROUP_IDX] = user_state.control_groups
[ctrl_group_evt.m_control_group_index as usize]
.clone();
current_selected_units = user_state.control_groups[ACTIVE_UNITS_GROUP_IDX].clone();
}
let mut curr_units =
match mark_selected_units(sc2_state, game_loop, user_id, ¤t_selected_units) {
UnitChangeHint::Selection(units) => units,
_ => unreachable!(),
};
updated_units.append(&mut curr_units);
}
}
(
ReplayGameEvent::ControlGroupUpdate(ctrl_group_evt),
UnitChangeHint::Selection(updated_units),
)
}
#[tracing::instrument(level = "debug", skip(sc2_state))]
pub fn handle_game_event(
sc2_state: &mut SC2ReplayState,
game_loop: i64,
user_id: i64,
evt: ReplayGameEvent,
) -> (ReplayGameEvent, UnitChangeHint) {
match evt {
ReplayGameEvent::CameraSave(camera_save) => {
handle_camera_save(sc2_state, game_loop, user_id, camera_save)
}
ReplayGameEvent::CameraUpdate(camera_update) => {
handle_camera_update(sc2_state, game_loop, user_id, camera_update)
}
ReplayGameEvent::Cmd(game_cmd) => handle_cmd(sc2_state, game_loop, user_id, game_cmd),
ReplayGameEvent::CmdUpdateTargetPoint(target_point) => {
handle_update_target_point(sc2_state, game_loop, user_id, target_point)
}
ReplayGameEvent::CmdUpdateTargetUnit(target_unit) => {
handle_update_target_unit(sc2_state, game_loop, user_id, target_unit)
}
ReplayGameEvent::SelectionDelta(selection_delta) => {
handle_selection_delta(sc2_state, game_loop, user_id, selection_delta)
}
ReplayGameEvent::ControlGroupUpdate(ctrl_group) => {
update_control_group(sc2_state, game_loop, user_id, ctrl_group)
}
_ => (evt.clone(), UnitChangeHint::None),
}
}