2 Commits

Author SHA1 Message Date
42fc93f68d sound event inspection 2026-03-06 20:04:52 -08:00
030adf2a87 prototype advanced api 2026-03-06 19:49:28 -08:00
4 changed files with 145 additions and 1 deletions

View File

@@ -66,6 +66,9 @@ impl PlaybackHead{
self.state.process_event(bot.timelines(),event_type,self.head.get_event_index(event_type));
self.head.push(event_type);
}
pub fn get_event_index(&self,event_type:EventType)->usize{
self.head.get_event_index(event_type)
}
pub fn advance_time(&mut self,bot:&CompleteBot,time:SessionTime){
let mut simulation_time=bot.time(self.time(time));
let mut time_float=simulation_time.into();

121
wasm-module/src/event.rs Normal file
View File

@@ -0,0 +1,121 @@
use wasm_bindgen::prelude::wasm_bindgen;
use strafesnet_roblox_bot_file::v0;
use strafesnet_roblox_bot_file::v0::{EventType,Timed};
use strafesnet_roblox_bot_player::bot;
/// A timeline event that has not been processed yet.
#[wasm_bindgen]
pub struct Event{
time:f64,
event:TimelineEvent,
}
impl Event{
pub(crate) fn event_type(&self)->EventType{
match &self.event{
TimelineEvent::Input(..)=>EventType::Input,
TimelineEvent::Output(..)=>EventType::Output,
TimelineEvent::Sound(..)=>EventType::Sound,
TimelineEvent::World(..)=>EventType::World,
TimelineEvent::Gravity(..)=>EventType::Gravity,
TimelineEvent::Run(..)=>EventType::Run,
TimelineEvent::Camera(..)=>EventType::Camera,
TimelineEvent::Setting(..)=>EventType::Setting,
}
}
}
enum TimelineEvent{
Input(v0::InputEvent),
Output(v0::OutputEvent),
Sound(v0::SoundEvent),
World(v0::WorldEvent),
Gravity(v0::GravityEvent),
Run(v0::RunEvent),
Camera(v0::CameraEvent),
Setting(v0::SettingEvent),
}
// helper macro for converting v0::Timed<v0::InputEvent> into Event
// (used in Event::new)
macro_rules! impl_into_event{
($event:path,$variant:ident)=>{
impl From<Timed<$event>> for Event{
fn from(Timed{time,event}:Timed<$event>)->Self{
Self{time,event:TimelineEvent::$variant(event)}
}
}
};
}
impl_into_event!(v0::InputEvent,Input);
impl_into_event!(v0::OutputEvent,Output);
impl_into_event!(v0::SoundEvent,Sound);
impl_into_event!(v0::WorldEvent,World);
impl_into_event!(v0::GravityEvent,Gravity);
impl_into_event!(v0::RunEvent,Run);
impl_into_event!(v0::CameraEvent,Camera);
impl_into_event!(v0::SettingEvent,Setting);
#[wasm_bindgen]
impl Event{
pub(crate) fn new(bot:&bot::CompleteBot,event:v0::EventType,event_index:usize)->Self{
let mut event:Self=match event{
EventType::Input=>bot.timelines().input_events[event_index].clone().into(),
EventType::Output=>bot.timelines().output_events[event_index].clone().into(),
EventType::Sound=>bot.timelines().sound_events[event_index].clone().into(),
EventType::World=>bot.timelines().world_events[event_index].clone().into(),
EventType::Gravity=>bot.timelines().gravity_events[event_index].clone().into(),
EventType::Run=>bot.timelines().run_events[event_index].clone().into(),
EventType::Camera=>bot.timelines().camera_events[event_index].clone().into(),
EventType::Setting=>bot.timelines().setting_events[event_index].clone().into(),
};
event.time-=bot.timelines().output_events.first().unwrap().time;
event
}
#[wasm_bindgen]
pub fn time(&self)->f64{
self.time
}
#[wasm_bindgen]
pub fn type_id(&self)->u32{
self.event_type() as u32
}
#[wasm_bindgen]
pub fn into_inner(self)->wasm_bindgen::JsValue{
match self.event{
TimelineEvent::Input(input_event)=>InputEvent(input_event).into(),
TimelineEvent::Output(output_event)=>OutputEvent(output_event).into(),
TimelineEvent::Sound(sound_event)=>SoundEvent(sound_event).into(),
TimelineEvent::World(world_event)=>WorldEvent(world_event).into(),
TimelineEvent::Gravity(gravity_event)=>GravityEvent(gravity_event).into(),
TimelineEvent::Run(run_event)=>RunEvent(run_event).into(),
TimelineEvent::Camera(camera_event)=>CameraEvent(camera_event).into(),
TimelineEvent::Setting(setting_event)=>SettingEvent(setting_event).into(),
}
}
}
#[wasm_bindgen]
pub struct InputEvent(v0::InputEvent);
#[wasm_bindgen]
pub struct OutputEvent(v0::OutputEvent);
#[wasm_bindgen]
pub struct SoundEvent(v0::SoundEvent);
impl SoundEvent{
pub fn material(&self)->u32{
self.0.material
}
pub fn sound_type(&self)->u32{
self.0.sound_type as u32
}
}
#[wasm_bindgen]
pub struct WorldEvent(v0::WorldEvent);
#[wasm_bindgen]
pub struct GravityEvent(v0::GravityEvent);
#[wasm_bindgen]
pub struct RunEvent(v0::RunEvent);
#[wasm_bindgen]
pub struct CameraEvent(v0::CameraEvent);
#[wasm_bindgen]
pub struct SettingEvent(v0::SettingEvent);

View File

@@ -4,6 +4,9 @@ use strafesnet_roblox_bot_file::v0;
use strafesnet_roblox_bot_player::{bot,head,time,graphics};
use strafesnet_graphics::setup;
mod event;
pub use event::*;
// Hack to keep the code compiling,
// SurfaceTarget::Canvas is not available in IDE for whatever reason.
struct ToSurfaceTarget(web_sys::HtmlCanvasElement);
@@ -116,11 +119,24 @@ impl PlaybackHead{
head:head::PlaybackHead::new(&bot.bot,time),
}
}
/// Simple api: call advance_time and then graphics.render()
#[wasm_bindgen]
pub fn advance_time(&mut self,bot:&CompleteBot,time:f64){
let time=time::from_float(time).unwrap();
self.head.advance_time(&bot.bot,time);
}
/// Advanced api: In a loop, call next_event and pass the result to process_event to advance the playback head.
#[wasm_bindgen]
pub fn next_event(&mut self,bot:&CompleteBot)->Option<Event>{
let next_event=self.head.next_event(&bot.bot)?;
let event_index=self.head.get_event_index(next_event.event);
Some(Event::new(&bot.bot,next_event.event,event_index))
}
/// Advanced api: In a loop, call next_event and pass the result to process_event to advance the playback head.
#[wasm_bindgen]
pub fn process_event(&mut self,bot:&CompleteBot,event:Event){
self.head.process_event(&bot.bot,event.event_type());
}
#[wasm_bindgen]
pub fn set_paused(&mut self,time:f64,paused:bool){
let time=time::from_float(time).unwrap();

View File

@@ -100,7 +100,11 @@ function animate(now) {
const elapsedSec = elapsedMs / 1000; // wasm expects seconds
// Advance the playback head to the current time
playback.advance_time(bot, elapsedSec);
var event = playback.next_event(bot);
while (event && event.time() < elapsedSec) {
playback.process_event(bot, event);
event = playback.next_event(bot);
}
// update the timer text
const time = playback.get_run_time(bot, elapsedSec, MODE_MAIN);