diff --git a/Cargo.toml b/Cargo.toml index 35dfd36..ba0b36d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ description = "Visualizer experiments for Starcraft II - Replay data" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rerun = "0.5.1" +rerun = {version = "0.7.0", features = ["native_viewer"] } s2protocol = "1.1.1" nom-mpq = "0.1.1" colored = "2.0.0" diff --git a/src/game_events/mod.rs b/src/game_events/mod.rs index 5e7dc15..42735ae 100644 --- a/src/game_events/mod.rs +++ b/src/game_events/mod.rs @@ -2,8 +2,9 @@ use super::*; use rerun::components::Arrow3D; +use rerun::transform::TranslationRotationScale3D; use rerun::{ - components::{Box3D, Quaternion, Radius, Rigid3, Transform, Vec3D}, + components::{Box3D, Radius, Transform3D, Vec3D}, MsgSender, }; use s2protocol::game_events::*; @@ -15,21 +16,26 @@ pub fn register_camera_update( game_loop: i64, user_id: i64, camera_update: &CameraUpdateEvent, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { if let Some(target) = &camera_update.m_target { MsgSender::new(format!("Unit/999{}/Player", user_id)) .with_time(sc2_rerun.timeline, game_loop) .with_splat(Box3D::new(3.0, 3.0, 0.0))? - .with_splat(Transform::Rigid3(Rigid3 { - rotation: Quaternion::new(0., 0., 0., 0.), - translation: Vec3D::new( - (target.x as f32 / 250f32) - 1.5, - (-1. * target.y as f32 / 250f32) - 1.5, - 0., + .with_splat(Transform3D::new(TranslationRotationScale3D { + translation: Some( + [ + (target.x as f32 / 250f32) - 1.5, + (-1. * target.y as f32 / 250f32) - 1.5, + 0., + ] + .into(), ), + rotation: None, + scale: None, }))? .with_splat(user_color(user_id))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } Ok(()) } @@ -39,13 +45,20 @@ pub fn register_cmd( game_loop: i64, user_id: i64, game_cmd: &GameSCmdEvent, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { match &game_cmd.m_data { GameSCmdData::TargetPoint(target) => { - register_update_target_point(sc2_rerun, game_loop, user_id, target)?; + register_update_target_point(sc2_rerun, game_loop, user_id, target, recording_stream)?; } GameSCmdData::TargetUnit(target_unit) => { - register_update_target_unit(sc2_rerun, game_loop, user_id, target_unit)?; + register_update_target_unit( + sc2_rerun, + game_loop, + user_id, + target_unit, + recording_stream, + )?; } GameSCmdData::Data(data) => { tracing::info!("GameSCmdData: {}", data); @@ -60,6 +73,7 @@ pub fn register_update_target_point( game_loop: i64, user_id: i64, target_point: &GameSMapCoord3D, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { let unit_target_pos = Vec3D::new( target_point.x as f32 / GAME_EVENT_POS_RATIO, @@ -85,7 +99,7 @@ pub fn register_update_target_point( ), })? .with_splat(user_color(user_id))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } } Ok(()) @@ -96,6 +110,7 @@ pub fn register_update_target_unit( game_loop: i64, user_id: i64, target_unit: &GameSCmdDataTargetUnit, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { let unit_target_pos = Vec3D::new( target_unit.m_snapshot_point.x as f32 / GAME_EVENT_POS_RATIO, @@ -121,7 +136,7 @@ pub fn register_update_target_unit( ), })? .with_splat(user_color(user_id))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } } Ok(()) @@ -132,6 +147,7 @@ pub fn unmark_previously_selected_units( sc2_rerun: &SC2Rerun, game_loop: i64, user_id: i64, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { if let Some(state) = sc2_rerun.sc2_state.user_state.get(&user_id) { for prev_unit in &state.control_groups[ACTIVE_UNITS_GROUP_IDX] { @@ -143,7 +159,7 @@ pub fn unmark_previously_selected_units( MsgSender::new(format!("Unit/{}/Born", unit_index)) .with_time(sc2_rerun.timeline, game_loop) .with_splat(Radius(unit.radius))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } } } @@ -156,6 +172,7 @@ pub fn mark_selected_units( game_loop: i64, _user_id: i64, selected_units: &[u32], + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { for new_selected_unit in selected_units { let unit_index = unit_tag_index(*new_selected_unit as i64); @@ -166,7 +183,7 @@ pub fn mark_selected_units( MsgSender::new(format!("Unit/{}/Born", unit_index)) .with_time(sc2_rerun.timeline, game_loop) .with_splat(Radius(unit.radius))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } } Ok(()) @@ -185,14 +202,16 @@ pub fn register_selection_delta( game_loop: i64, user_id: i64, selection_delta: &GameSSelectionDeltaEvent, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { if selection_delta.m_control_group_id == ACTIVE_UNITS_GROUP_IDX as u8 { - unmark_previously_selected_units(sc2_rerun, game_loop, user_id)?; + unmark_previously_selected_units(sc2_rerun, game_loop, user_id, recording_stream)?; mark_selected_units( sc2_rerun, game_loop, user_id, &selection_delta.m_delta.m_add_unit_tags, + recording_stream, )?; } Ok(()) @@ -206,13 +225,17 @@ pub fn update_control_group( user_id: i64, ctrl_group_evt: &GameSControlGroupUpdateEvent, updated_units: Vec, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { - unmark_previously_selected_units(sc2_rerun, game_loop, user_id)?; - match ctrl_group_evt.m_control_group_update { - GameEControlGroupUpdate::ERecall => { - mark_selected_units(sc2_rerun, game_loop, user_id, &updated_units)?; - } - _ => {} + unmark_previously_selected_units(sc2_rerun, game_loop, user_id, recording_stream)?; + if ctrl_group_evt.m_control_group_update == GameEControlGroupUpdate::ERecall { + mark_selected_units( + sc2_rerun, + game_loop, + user_id, + &updated_units, + recording_stream, + )?; } Ok(()) } @@ -224,25 +247,57 @@ pub fn add_game_event( user_id: i64, evt: &ReplayGameEvent, updated_units: Vec, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { match &evt { ReplayGameEvent::CameraUpdate(camera_update) => { - register_camera_update(&sc2_rerun, game_loop, user_id, camera_update)?; + register_camera_update( + sc2_rerun, + game_loop, + user_id, + camera_update, + recording_stream, + )?; } ReplayGameEvent::Cmd(game_cmd) => { - register_cmd(sc2_rerun, game_loop, user_id, game_cmd)?; + register_cmd(sc2_rerun, game_loop, user_id, game_cmd, recording_stream)?; } ReplayGameEvent::CmdUpdateTargetPoint(target_point) => { - register_update_target_point(sc2_rerun, game_loop, user_id, &target_point.m_target)?; + register_update_target_point( + sc2_rerun, + game_loop, + user_id, + &target_point.m_target, + recording_stream, + )?; } ReplayGameEvent::CmdUpdateTargetUnit(target_unit) => { - register_update_target_unit(sc2_rerun, game_loop, user_id, &target_unit.m_target)?; + register_update_target_unit( + sc2_rerun, + game_loop, + user_id, + &target_unit.m_target, + recording_stream, + )?; } ReplayGameEvent::SelectionDelta(selection_delta) => { - register_selection_delta(sc2_rerun, game_loop, user_id, &selection_delta)?; + register_selection_delta( + sc2_rerun, + game_loop, + user_id, + selection_delta, + recording_stream, + )?; } ReplayGameEvent::ControlGroupUpdate(ctrl_group) => { - update_control_group(sc2_rerun, game_loop, user_id, &ctrl_group, updated_units)?; + update_control_group( + sc2_rerun, + game_loop, + user_id, + ctrl_group, + updated_units, + recording_stream, + )?; } _ => {} } diff --git a/src/lib.rs b/src/lib.rs index b9f29b0..7321410 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ use rerun::components::{ColorRGBA, Vec3D}; use rerun::external::re_log_types::DataTableError; use rerun::external::re_viewer::external::eframe::Error as eframe_Error; use rerun::time::Timeline; -use rerun::Session; +use rerun::RecordingStream; use rerun::{time, MsgSenderError}; use s2protocol::{S2ProtocolError, SC2EventType, SC2ReplayFilters, SC2ReplayState}; pub use tracker_events::*; @@ -55,11 +55,11 @@ pub struct SC2Rerun { /// The absolute GameEvevnt loop timeline, the tracker loop should be relative to it. pub timeline: Timeline, - /// The rerun session to display data. - pub rerun_session: Session, - /// The SC2 replay state as it steps through game loops. pub sc2_state: SC2ReplayState, + + /// The file path containing the SC2 Replay + pub file_path: String, } impl SC2Rerun { @@ -68,38 +68,50 @@ impl SC2Rerun { filters: SC2ReplayFilters, include_stats: bool, ) -> Result { - let rerun_session = rerun::SessionBuilder::new(file_path).buffered(); let timeline = rerun::time::Timeline::new("game_timeline", time::TimeType::Sequence); let sc2_state = SC2ReplayState::new(file_path, filters, include_stats)?; Ok(Self { timeline, - rerun_session, sc2_state, + file_path: file_path.to_string(), }) } - pub fn add_events(&mut self) -> Result<(), SwarmyError> { + pub fn add_events(&mut self, recording_stream: &RecordingStream) -> Result<(), SwarmyError> { while let Some((event, updated_units)) = self.sc2_state.transduce() { match event { SC2EventType::Tracker { tracker_loop, event, - } => add_tracker_event(&self, tracker_loop, &event, updated_units)?, + } => { + add_tracker_event(self, tracker_loop, &event, updated_units, recording_stream)? + } SC2EventType::Game { game_loop, user_id, event, - } => add_game_event(&self, game_loop, user_id, &event, updated_units)?, + } => add_game_event( + self, + game_loop, + user_id, + &event, + updated_units, + recording_stream, + )?, } } Ok(()) } - pub fn show(&self) -> Result<(), SwarmyError> { - Ok(rerun::native_viewer::show(&self.rerun_session)?) + pub fn show(mut self) -> Result<(), SwarmyError> { + let recording_info = rerun::new_recording_info(self.file_path.clone()); + rerun::native_viewer::spawn(recording_info, Default::default(), move |rec_stream| { + self.add_events(&rec_stream).unwrap(); + })?; + Ok(()) } } pub fn from_vec3d(source: s2protocol::Vec3D) -> Vec3D { - Vec3D::new(source.0[0] as f32, source.0[1] as f32, source.0[2] as f32) + Vec3D::new(source.0[0], source.0[1], source.0[2]) } diff --git a/src/main.rs b/src/main.rs index 435f48d..851a973 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use clap::Parser; use s2protocol::SC2ReplayFilters; use swarmy::*; -use tracing_subscriber; use rerun::external::re_memory::AccountingAllocator; @@ -66,8 +65,7 @@ fn main() -> Result<(), Box> { max_events: cli.filter_max_events, }; tracing::info!("Filters: {:?}", filters); - let mut sc2_rerun = SC2Rerun::new(&cli.source, filters, cli.include_stats)?; - sc2_rerun.add_events()?; + let sc2_rerun = SC2Rerun::new(&cli.source, filters, cli.include_stats)?; sc2_rerun.show()?; Ok(()) } diff --git a/src/tracker_events/mod.rs b/src/tracker_events/mod.rs index f3d0f11..8290203 100644 --- a/src/tracker_events/mod.rs +++ b/src/tracker_events/mod.rs @@ -12,6 +12,7 @@ pub fn register_unit_init( game_loop: i64, unit_init: &UnitInitEvent, updated_units: Vec, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { for unit_tag in updated_units { if let Some(unit) = sc2_rerun.sc2_state.units.get(&unit_tag) { @@ -24,7 +25,7 @@ pub fn register_unit_init( .with_splat(unit_color)? .with_splat(TextEntry::new(&unit.name, None))? .with_splat(Radius(unit_size))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } } Ok(()) @@ -35,6 +36,7 @@ pub fn register_unit_born( game_loop: i64, unit_born: &UnitBornEvent, updated_units: Vec, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { for unit_tag in updated_units { if let Some(unit) = sc2_rerun.sc2_state.units.get(&unit_tag) { @@ -47,7 +49,7 @@ pub fn register_unit_born( .with_splat(unit_color)? .with_splat(TextEntry::new(&unit.name, None))? .with_splat(Radius(unit_size))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } } Ok(()) @@ -57,21 +59,22 @@ pub fn register_unit_died( sc2_rerun: &SC2Rerun, game_loop: i64, unit_dead: &UnitDiedEvent, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { // Clear up the previous unit target. let timepoint = [( sc2_rerun.timeline, rerun::time::TimeInt::from_sequence(game_loop), )]; - let _ = &sc2_rerun.rerun_session.send_path_op( - &timepoint.into(), + recording_stream.record_path_op( + timepoint.into(), rerun::log::PathOp::clear( true, format!("Unit/{}/Target", unit_dead.unit_tag_index).into(), ), ); - let _ = &sc2_rerun.rerun_session.send_path_op( - &timepoint.into(), + recording_stream.record_path_op( + timepoint.into(), rerun::log::PathOp::clear( true, format!("Unit/{}/Born", unit_dead.unit_tag_index).into(), @@ -93,7 +96,7 @@ pub fn register_unit_died( ))? .with_splat(FREYA_DARK_RED)? .with_splat(Radius(0.75))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; Ok(()) } @@ -101,6 +104,7 @@ pub fn register_unit_position( sc2_rerun: &SC2Rerun, game_loop: i64, unit_pos: UnitPositionsEvent, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { let unit_positions = unit_pos.to_unit_positions_vec(); for unit_pos_item in unit_positions { @@ -109,7 +113,7 @@ pub fn register_unit_position( MsgSender::new(format!("Unit/{}/Position", unit_pos_item.tag)) .with_time(sc2_rerun.timeline, game_loop) .with_splat(Point3D::new(unit_pos.x(), unit_pos.y(), unit_pos.z()))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } else { tracing::error!( "Unit {} did not exist but position registered.", @@ -124,18 +128,19 @@ pub fn register_player_stats( sc2_rerun: &SC2Rerun, game_loop: i64, player_stats: &PlayerStatsEvent, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { if !sc2_rerun.sc2_state.include_stats { return Ok(()); } for stat_entity_value in player_stats.stats.as_prop_name_value_vec() { println!("Stat: {}", stat_entity_value.0); - let entity_path = stat_entity_value.0.replace("/", "_").to_case(Case::Pascal); + let entity_path = stat_entity_value.0.replace('/', "_").to_case(Case::Pascal); MsgSender::new(format!("{}/{}", entity_path, player_stats.player_id,)) .with_time(sc2_rerun.timeline, game_loop) .with_splat(Scalar::from(stat_entity_value.1 as f64))? .with_splat(user_color(player_stats.player_id as i64))? - .send(&sc2_rerun.rerun_session)?; + .send(recording_stream)?; } Ok(()) } @@ -146,22 +151,35 @@ pub fn add_tracker_event( tracker_loop: i64, evt: &ReplayTrackerEvent, updated_units: Vec, + recording_stream: &RecordingStream, ) -> Result<(), SwarmyError> { match &evt { ReplayTrackerEvent::UnitInit(unit_init) => { - register_unit_init(sc2_rerun, tracker_loop, unit_init, updated_units)?; + register_unit_init( + sc2_rerun, + tracker_loop, + unit_init, + updated_units, + recording_stream, + )?; } ReplayTrackerEvent::UnitBorn(unit_born) => { - register_unit_born(sc2_rerun, tracker_loop, unit_born, updated_units)?; + register_unit_born( + sc2_rerun, + tracker_loop, + unit_born, + updated_units, + recording_stream, + )?; } ReplayTrackerEvent::UnitDied(unit_died) => { - register_unit_died(sc2_rerun, tracker_loop, unit_died)?; + register_unit_died(sc2_rerun, tracker_loop, unit_died, recording_stream)?; } ReplayTrackerEvent::UnitPosition(unit_pos) => { - register_unit_position(sc2_rerun, tracker_loop, unit_pos.clone())?; + register_unit_position(sc2_rerun, tracker_loop, unit_pos.clone(), recording_stream)?; } ReplayTrackerEvent::PlayerStats(player_stats) => { - register_player_stats(sc2_rerun, tracker_loop, player_stats)?; + register_player_stats(sc2_rerun, tracker_loop, player_stats, recording_stream)?; } _ => {} }