separate map from graphics

This commit is contained in:
2026-02-18 10:20:43 -08:00
parent 2646e96c33
commit d0e71b8431
7 changed files with 100 additions and 74 deletions

View File

@@ -1,23 +1,5 @@
use strafesnet_graphics::graphics::GraphicsState;
#[derive(Debug)]
pub enum Error{
File(strafesnet_snf::Error),
Map(strafesnet_snf::map::Error),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for Error{}
pub enum Instruction{
Render{pos:glam::Vec3,angles:glam::Vec2},
Resize(glam::UVec2),
ChangeMap(strafesnet_common::map::CompleteMap),
}
/// The graphics state, essentially a handle to all the information on the GPU.
pub struct Graphics{
graphics:GraphicsState,
@@ -26,53 +8,44 @@ pub struct Graphics{
queue:wgpu::Queue,
}
impl Graphics{
pub fn new(data:&[u8],device:wgpu::Device,queue:wgpu::Queue,config:wgpu::SurfaceConfiguration)->Result<Self,Error>{
pub fn new(device:wgpu::Device,queue:wgpu::Queue,config:wgpu::SurfaceConfiguration)->Self{
let mut graphics=strafesnet_graphics::graphics::GraphicsState::new(&device,&queue,&config);
graphics.resize(&device,&config,glam::Vec2::ONE);
let map=strafesnet_snf::read_map(std::io::Cursor::new(data))
.map_err(Error::File)?
.into_complete_map()
.map_err(Error::Map)?;
graphics.generate_models(&device,&queue,&map);
Ok(Self{
Self{
graphics,
device,
queue,
config,
})
}
pub fn send(&mut self,surface:&wgpu::Surface<'_>,ins:Instruction){
match ins{
Instruction::ChangeMap(map)=>{
self.graphics.clear();
self.graphics.generate_models(&self.device,&self.queue,&map);
},
Instruction::Resize(size)=>{
self.config.width=size.x.max(1);
self.config.height=size.y.max(1);
surface.configure(&self.device,&self.config);
self.graphics.resize(&self.device,&self.config,glam::Vec2::ONE);
}
Instruction::Render{pos,angles}=>{
//this has to go deeper somehow
let frame=match surface.get_current_texture(){
Ok(frame)=>frame,
Err(_)=>{
surface.configure(&self.device,&self.config);
surface
.get_current_texture()
.expect("Failed to acquire next surface texture!")
}
};
let view=frame.texture.create_view(&wgpu::TextureViewDescriptor{
format:Some(self.config.view_formats[0]),
..wgpu::TextureViewDescriptor::default()
});
self.graphics.render(&view,&self.device,&self.queue,strafesnet_graphics::graphics::view_inv(pos,angles));
frame.present();
}
}
}
pub fn change_map(&mut self,map:&crate::map::CompleteMap){
self.graphics.clear();
self.graphics.generate_models(&self.device,&self.queue,map.map());
}
pub fn resize(&mut self,surface:&wgpu::Surface<'_>,size:glam::UVec2){
self.config.width=size.x.max(1);
self.config.height=size.y.max(1);
surface.configure(&self.device,&self.config);
self.graphics.resize(&self.device,&self.config,glam::Vec2::ONE);
}
pub fn render(&mut self,surface:&wgpu::Surface<'_>,pos:glam::Vec3,angles:glam::Vec2){
//this has to go deeper somehow
let frame=match surface.get_current_texture(){
Ok(frame)=>frame,
Err(_)=>{
surface.configure(&self.device,&self.config);
surface
.get_current_texture()
.expect("Failed to acquire next surface texture!")
}
};
let view=frame.texture.create_view(&wgpu::TextureViewDescriptor{
format:Some(self.config.view_formats[0]),
..wgpu::TextureViewDescriptor::default()
});
self.graphics.render(&view,&self.device,&self.queue,strafesnet_graphics::graphics::view_inv(pos,angles));
frame.present();
}
}

View File

@@ -1,7 +1,8 @@
pub mod bot;
pub mod graphics;
pub mod map;
pub mod head;
pub mod surface;
// pub mod surface;
pub mod graphics;
// Create Surface
// Create Graphics from map file and with surface as sample

29
lib/src/map.rs Normal file
View File

@@ -0,0 +1,29 @@
#[derive(Debug)]
pub enum Error{
File(strafesnet_snf::Error),
Map(strafesnet_snf::map::Error),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for Error{}
pub struct CompleteMap{
complete_map:strafesnet_common::map::CompleteMap,
}
impl CompleteMap{
pub fn new(
data:&[u8],
)->Result<Self,Error>{
let complete_map=strafesnet_snf::read_map(std::io::Cursor::new(data))
.map_err(Error::File)?
.into_complete_map()
.map_err(Error::Map)?;
Ok(Self{complete_map})
}
pub const fn map(&self)->&strafesnet_common::map::CompleteMap{
&self.complete_map
}
}

View File

@@ -46,10 +46,10 @@ impl<'a> PlayerWorker<'a>{
Instruction::Render=>{
self.playback_head.advance_time(&self.bot,ins.time);
let (pos,angles)=self.playback_head.get_position_angles(&self.bot,ins.time);
self.graphics_thread.send(&self.surface,strafesnet_roblox_bot_player::graphics::Instruction::Render{pos,angles});
self.graphics_thread.render(&self.surface,pos,angles);
},
Instruction::Resize(physical_size)=>{
self.graphics_thread.send(&self.surface,strafesnet_roblox_bot_player::graphics::Instruction::Resize(glam::uvec2(physical_size.width,physical_size.height)));
self.graphics_thread.resize(&self.surface,glam::uvec2(physical_size.width,physical_size.height));
},
}
}

View File

@@ -201,8 +201,10 @@ impl WindowContext<'_>{
let screen_size=glam::uvec2(config.width,config.height);
let bot=include_bytes!("../../web-demo/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d.qbot");
let map=include_bytes!("../../web-demo/bhop_marble_5692093612.snfm");
let graphics=strafesnet_roblox_bot_player::graphics::Graphics::new(map,device,queue,config).unwrap();
let bot=strafesnet_roblox_bot_player::bot::Bot::new(bot).unwrap();
let map=strafesnet_roblox_bot_player::map::CompleteMap::new(map).unwrap();
let mut graphics=strafesnet_roblox_bot_player::graphics::Graphics::new(device,queue,config);
graphics.change_map(&map);
WindowContext{
manual_mouse_lock:false,
mouse_pos:glam::DVec2::ZERO,

View File

@@ -1,6 +1,6 @@
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsValue;
use strafesnet_roblox_bot_player::{bot,graphics,head};
use strafesnet_roblox_bot_player::{bot,map,head,graphics};
use strafesnet_graphics::setup;
use strafesnet_common::session::Time as SessionTime;
@@ -48,23 +48,26 @@ impl Graphics{
#[wasm_bindgen(constructor)]
pub fn new(
setup:Setup,
data:&[u8],
)->Result<Self,JsValue>{
Ok(Self{
graphics:graphics::Graphics::new(data,setup.device,setup.queue,setup.config).map_err(|e|JsValue::from_str(&e.to_string()))?,
)->Self{
Self{
graphics:graphics::Graphics::new(setup.device,setup.queue,setup.config),
surface:setup.surface,
})
}
}
#[wasm_bindgen]
pub fn render(&mut self,bot:&Bot,head:&PlaybackHead,time:f64){
// TODO: check f64 range
let time=SessionTime::raw((time*SessionTime::ONE_SECOND.get() as f64) as i64);
let (pos,angles)=head.head.get_position_angles(&bot.bot,time);
self.graphics.send(&self.surface,strafesnet_roblox_bot_player::graphics::Instruction::Render{pos,angles});
self.graphics.render(&self.surface,pos,angles);
}
#[wasm_bindgen]
pub fn resize(&mut self,width:u32,height:u32){
self.graphics.send(&self.surface,strafesnet_roblox_bot_player::graphics::Instruction::Resize([width,height].into()));
self.graphics.resize(&self.surface,[width,height].into());
}
#[wasm_bindgen]
pub fn change_map(&mut self,map:&CompleteMap){
self.graphics.change_map(&map.map);
}
}
@@ -82,6 +85,20 @@ impl Bot{
}
}
#[wasm_bindgen]
pub struct CompleteMap{
map:map::CompleteMap,
}
#[wasm_bindgen]
impl CompleteMap{
#[wasm_bindgen(constructor)]
pub fn new(data:&[u8])->Result<Self,JsValue>{
Ok(Self{
map:map::CompleteMap::new(data).map_err(|e|JsValue::from_str(&e.to_string()))?,
})
}
}
#[wasm_bindgen]
pub struct PlaybackHead{
head:head::PlaybackHead,

View File

@@ -1,7 +1,8 @@
import init, {
setup,
Graphics,
Bot,
Graphics,
CompleteMap,
PlaybackHead,
} from "./pkg/strafesnet_roblox_bot_player_wasm_module.js";
@@ -13,10 +14,13 @@ const m = await fetch("bhop_marble_5692093612.snfm");
const canvas = document.querySelector("canvas");
const context = await setup(canvas);
const graphics = new Graphics(context, new Uint8Array(await m.arrayBuffer()));
const graphics = new Graphics(context);
const bot = new Bot(new Uint8Array(await b.arrayBuffer()));
const map = new CompleteMap(new Uint8Array(await m.arrayBuffer()));
const playback = new PlaybackHead(0);
graphics.change_map(map);
const startTime = performance.now();
function animate(now) {