Files
roblox-bot-player/wasm-module/src/lib.rs
2026-02-24 08:50:49 -08:00

168 lines
5.0 KiB
Rust

use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsValue;
use strafesnet_roblox_bot_file::v0;
use strafesnet_roblox_bot_player::{bot,head,time,graphics};
use strafesnet_graphics::setup;
use strafesnet_common::physics::Time as PhysicsTime;
mod ratio;
// Hack to keep the code compiling,
// SurfaceTarget::Canvas is not available in IDE for whatever reason.
struct ToSurfaceTarget(web_sys::HtmlCanvasElement);
impl From<ToSurfaceTarget> for wgpu::SurfaceTarget<'static>{
fn from(ToSurfaceTarget(canvas):ToSurfaceTarget)->Self{
#[cfg(target_arch = "wasm32")]
let target=wgpu::SurfaceTarget::Canvas(canvas);
#[expect(unused)]
#[cfg(not(target_arch = "wasm32"))]
let target=panic!("{canvas:?}");
#[allow(unused)]
target
}
}
#[wasm_bindgen]
pub struct Graphics{
graphics:graphics::Graphics,
surface:wgpu::Surface<'static>,
}
#[wasm_bindgen]
pub async fn setup_graphics(canvas:web_sys::HtmlCanvasElement)->Graphics{
let size=(canvas.width(),canvas.height());
let instance=setup::step1::create_instance();
let surface=setup::step2::create_surface(&instance,ToSurfaceTarget(canvas)).unwrap();
let adapter=setup::step3::pick_adapter(&instance,&surface).await.expect("No suitable GPU adapters found on the system!");
let (device,queue)=setup::step4::request_device(&adapter).await;
let config=setup::step5::configure_surface(&adapter,&device,&surface,size);
Graphics{
graphics:graphics::Graphics::new(device,queue,config),
surface:surface,
}
}
#[wasm_bindgen]
impl Graphics{
#[wasm_bindgen]
pub fn render(&mut self,bot:&CompleteBot,head:&PlaybackHead,time:f64){
let time=time::from_float(time).unwrap();
let (pos,angles)=head.head.get_position_angles(&bot.bot,time);
self.graphics.render(&self.surface,pos,angles);
}
#[wasm_bindgen]
pub fn resize(&mut self,width:u32,height:u32){
self.graphics.resize(&self.surface,[width,height].into());
}
#[wasm_bindgen]
pub fn change_map(&mut self,map:&CompleteMap){
self.graphics.change_map(&map.map);
}
}
#[wasm_bindgen]
pub struct CompleteBot{
bot:bot::CompleteBot,
}
#[wasm_bindgen]
impl CompleteBot{
#[wasm_bindgen(constructor)]
pub fn new(data:&[u8])->Result<Self,JsValue>{
let timelines=v0::read_all_to_block(std::io::Cursor::new(data)).map_err(|e|JsValue::from_str(&e.to_string()))?;
Ok(Self{
bot:bot::CompleteBot::new(timelines),
})
}
#[wasm_bindgen]
pub fn duration(&self)->f64{
self.bot.duration().get() as f64/PhysicsTime::ONE_SECOND.get() as f64
}
#[wasm_bindgen]
pub fn run_duration(&self,mode_id:u32)->Option<f64>{
let mode=v0::ModeID(mode_id);
Some(self.bot.run_duration(mode)?.get() as f64/PhysicsTime::ONE_SECOND.get() as f64)
}
}
#[wasm_bindgen]
pub struct CompleteMap{
map:strafesnet_common::map::CompleteMap,
}
#[wasm_bindgen]
impl CompleteMap{
#[wasm_bindgen(constructor)]
pub fn new(data:&[u8])->Result<Self,JsValue>{
let map=strafesnet_snf::read_map(std::io::Cursor::new(data))
.map_err(|e|JsValue::from_str(&e.to_string()))?
.into_complete_map()
.map_err(|e|JsValue::from_str(&e.to_string()))?;
Ok(Self{
map,
})
}
}
#[wasm_bindgen]
pub struct PlaybackHead{
head:head::PlaybackHead,
}
#[wasm_bindgen]
impl PlaybackHead{
#[wasm_bindgen(constructor)]
pub fn new(time:f64)->Result<Self,JsValue>{
let time=time::from_float(time).unwrap();
Ok(Self{
head:head::PlaybackHead::new(time),
})
}
#[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);
}
#[wasm_bindgen]
pub fn get_run_time(&self,bot:&CompleteBot,time:f64,mode_id:u32)->Option<f64>{
let time=time::from_float(time).unwrap();
let time=self.head.time(&bot.bot,time);
let mode=v0::ModeID(mode_id);
let run_time=self.head.state().get_run(mode)?.time(time);
Some(run_time.get() as f64/strafesnet_common::run::Time::ONE_SECOND.get() as f64)
}
#[wasm_bindgen]
pub fn is_run_in_progress(&self,mode_id:u32)->Option<bool>{
let mode=v0::ModeID(mode_id);
Some(self.head.state().get_run(mode)?.is_in_progress())
}
#[wasm_bindgen]
pub fn is_run_finished(&self,mode_id:u32)->Option<bool>{
let mode=v0::ModeID(mode_id);
Some(self.head.state().get_run(mode)?.is_finished())
}
#[wasm_bindgen]
pub fn set_paused(&mut self,time:f64,paused:bool){
let time=time::from_float(time).unwrap();
self.head.set_paused(time,paused);
}
#[wasm_bindgen]
pub fn set_scale(&mut self,time:f64,scale:f64){
let time=time::from_float(time).unwrap();
let scale=crate::ratio::ratio_from_float(scale).unwrap();
self.head.set_scale(time,scale);
}
#[wasm_bindgen]
pub fn seek_to(&mut self,time:f64,new_time:f64){
let time=time::from_float(time).unwrap();
let new_time=time::from_float(new_time).unwrap();
self.head.seek_to(time,new_time);
}
#[wasm_bindgen]
pub fn seek_forward(&mut self,time_offset:f64){
let time_offset=time::from_float(time_offset).unwrap();
self.head.seek_forward(time_offset);
}
#[wasm_bindgen]
pub fn seek_backward(&mut self,time_offset:f64){
let time_offset=time::from_float(time_offset).unwrap();
self.head.seek_backward(time_offset);
}
}