fix green bug

This commit is contained in:
2026-02-27 08:49:48 -08:00
parent a4c4f20bad
commit 299a2b8051
6 changed files with 60 additions and 63 deletions

8
Cargo.lock generated
View File

@@ -1632,9 +1632,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strafesnet_common"
version = "0.8.3"
version = "0.8.4"
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
checksum = "c51de04816a98559f315d57b8a13a3bc010e2dc9bb033906a424ec8d56601731"
checksum = "1cc4c74ee1ba0c68431290db6f2573f208557a2bf63ec45c667d332de200d9f2"
dependencies = [
"arrayvec",
"bitflags 2.10.0",
@@ -1661,9 +1661,9 @@ dependencies = [
[[package]]
name = "strafesnet_roblox_bot_file"
version = "0.9.2"
version = "0.9.3"
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
checksum = "f3764f94fb71eba824aeabde808b490ef719331673f3f485c8b176895e4955dd"
checksum = "423d931e4f4f97406a86519a22172d1fc0d5b9d8c3b2d4553ae89b641bbd555c"
dependencies = [
"binrw",
"bitflags 2.10.0",

View File

@@ -12,7 +12,7 @@ strip = true
codegen-units = 1
[workspace.dependencies]
strafesnet_common = { version = "0.8.3", registry = "strafesnet" }
strafesnet_common = { version = "0.8.4", registry = "strafesnet" }
strafesnet_graphics = { version = "0.0.2", registry = "strafesnet" }
strafesnet_roblox_bot_file = { version = "0.9.2", registry = "strafesnet" }
strafesnet_roblox_bot_file = { version = "0.9.3", registry = "strafesnet" }
strafesnet_snf = { version = "0.3.2", registry = "strafesnet" }

View File

@@ -20,19 +20,16 @@ pub struct PlaybackHead{
timer:Timer<Scaled<SessionTimeInner,TimeInner>>,
state:PlaybackState,
}
const HEAD_NO_CRASH:Head={
let mut head=Head::new();
// push one output event so that output-1 doesn't underflow
head.push(EventType::Output);
head
};
impl PlaybackHead{
pub fn new(time:SessionTime)->Self{
pub fn new(bot:&CompleteBot,time:SessionTime)->Self{
let timer=Timer::unpaused(time,Time::ZERO);
let head=Head::after_time(bot.timelines(),bot.time(Time::ZERO).into());
let mut state=PlaybackState::new();
state.process_head(bot.timelines(),&head);
Self{
head:HEAD_NO_CRASH,
head,
timer,
state:PlaybackState::new(),
state,
}
}
pub const fn state(&self)->&PlaybackState{
@@ -48,18 +45,11 @@ impl PlaybackHead{
_=self.timer.set_paused(time,paused);
}
pub fn set_time(&mut self,bot:&CompleteBot,time:SessionTime,new_time:Time){
let new_time=new_time.rem_euclid(bot.duration().coerce());
self.timer.set_time(time,new_time);
// reset head
self.head=Head::after_time(bot.timelines(),bot.time(new_time).into());
// nudge indices as a hack to avoid oob index
if self.head.get_event_index(EventType::Output)==0{
self.head.push(EventType::Output);
}
if self.head.get_event_index(EventType::Output)==bot.timelines().output_events.len(){
self.head.set_event_index(EventType::Output,bot.timelines().output_events.len()-1);
}
self.state=PlaybackState::new();
self.state.process_head(bot.timelines(),&self.head);
}
@@ -90,8 +80,9 @@ impl PlaybackHead{
},
None=>{
//reset playback
self.head=HEAD_NO_CRASH;
self.head=Head::after_time(bot.timelines(),bot.time(Time::ZERO).into());
self.state=PlaybackState::new();
self.state.process_head(bot.timelines(),&self.head);
// hack to wind back timer offset without precise session timestamp
let (mut state,paused)=self.timer.clone().into_state();

View File

@@ -28,58 +28,59 @@ fn speed_ratio(speed:i8)->strafesnet_common::integer::Ratio64{
}
}
struct Playback{
bot:CompleteBot,
playback_head:PlaybackHead,
playback_speed:i8,
}
pub struct PlayerWorker<'a>{
surface:wgpu::Surface<'a>,
graphics_thread:Graphics,
bot:Option<CompleteBot>,
playback_head:PlaybackHead,
playback_speed:i8,
playback:Option<Playback>,
}
impl<'a> PlayerWorker<'a>{
pub fn new(
surface:wgpu::Surface<'a>,
graphics_thread:Graphics,
)->Self{
let playback_head=PlaybackHead::new(SessionTime::ZERO);
Self{
surface,
graphics_thread,
bot:None,
playback_head,
playback_speed:0,
playback:None,
}
}
pub fn send(&mut self,ins:TimedInstruction<Instruction,SessionTime>){
match ins.instruction{
Instruction::SessionControl(SessionControlInstruction::SetPaused(paused))=>{
self.playback_head.set_paused(ins.time,paused);
Instruction::SessionControl(SessionControlInstruction::SetPaused(paused))=>if let Some(playback)=&mut self.playback{
playback.playback_head.set_paused(ins.time,paused);
},
Instruction::SessionControl(SessionControlInstruction::Restart)=>if let Some(bot)=&self.bot{
self.playback_head.set_time(bot,ins.time,PlaybackTime::ZERO);
Instruction::SessionControl(SessionControlInstruction::Restart)=>if let Some(playback)=&mut self.playback{
playback.playback_head.set_time(&playback.bot,ins.time,PlaybackTime::ZERO);
},
Instruction::SessionControl(SessionControlInstruction::SkipForward)=>if let Some(bot)=&self.bot{
let head_time=self.playback_head.timer().clone().into_state().0.get_time(ins.time+SessionTime::from_secs(2));
self.playback_head.set_time(bot,ins.time,head_time);
Instruction::SessionControl(SessionControlInstruction::SkipForward)=>if let Some(playback)=&mut self.playback{
let head_time=playback.playback_head.timer().clone().into_state().0.get_time(ins.time+SessionTime::from_secs(2));
playback.playback_head.set_time(&playback.bot,ins.time,head_time);
},
Instruction::SessionControl(SessionControlInstruction::SkipBack)=>if let Some(bot)=&self.bot{
let head_time=self.playback_head.timer().clone().into_state().0.get_time(ins.time-SessionTime::from_secs(2));
self.playback_head.set_time(bot,ins.time,head_time);
Instruction::SessionControl(SessionControlInstruction::SkipBack)=>if let Some(playback)=&mut self.playback{
let head_time=playback.playback_head.timer().clone().into_state().0.get_time(ins.time-SessionTime::from_secs(2));
playback.playback_head.set_time(&playback.bot,ins.time,head_time);
},
Instruction::SessionControl(SessionControlInstruction::DecreaseTimescale)=>{
self.playback_speed=self.playback_speed.saturating_sub(1).max(-27);
self.playback_head.set_scale(ins.time,speed_ratio(self.playback_speed));
Instruction::SessionControl(SessionControlInstruction::DecreaseTimescale)=>if let Some(playback)=&mut self.playback{
playback.playback_speed=playback.playback_speed.saturating_sub(1).max(-27);
playback.playback_head.set_scale(ins.time,speed_ratio(playback.playback_speed));
},
Instruction::SessionControl(SessionControlInstruction::IncreaseTimescale)=>{
self.playback_speed=self.playback_speed.saturating_add(1).min(27);
self.playback_head.set_scale(ins.time,speed_ratio(self.playback_speed));
Instruction::SessionControl(SessionControlInstruction::IncreaseTimescale)=>if let Some(playback)=&mut self.playback{
playback.playback_speed=playback.playback_speed.saturating_add(1).min(27);
playback.playback_head.set_scale(ins.time,speed_ratio(playback.playback_speed));
},
Instruction::Render=>if let Some(bot)=&self.bot{
self.playback_head.advance_time(bot,ins.time);
let (pos,angles)=self.playback_head.get_position_angles(bot,ins.time);
Instruction::Render=>if let Some(playback)=&mut self.playback{
playback.playback_head.advance_time(&playback.bot,ins.time);
let (pos,angles)=playback.playback_head.get_position_angles(&playback.bot,ins.time);
self.graphics_thread.render(&self.surface,pos,angles);
},
Instruction::Resize(physical_size)=>{
let fov_y=self.playback_head.state().get_fov_y();
Instruction::Resize(physical_size)=>if let Some(playback)=&self.playback{
let fov_y=playback.playback_head.state().get_fov_y();
let fov_x=fov_y*physical_size.width as f64/physical_size.height as f64;
self.graphics_thread.resize(&self.surface,glam::uvec2(physical_size.width,physical_size.height),glam::vec2(fov_x as f32,fov_y as f32));
},
@@ -87,7 +88,13 @@ impl<'a> PlayerWorker<'a>{
self.graphics_thread.change_map(&complete_map);
},
Instruction::LoadReplay(bot)=>{
self.bot=Some(CompleteBot::new(bot));
let bot=CompleteBot::new(bot);
let playback_head=PlaybackHead::new(&bot,SessionTime::ZERO);
self.playback=Some(Playback{
bot,
playback_head,
playback_speed:0,
});
},
}
}

View File

@@ -105,10 +105,10 @@ pub struct PlaybackHead{
#[wasm_bindgen]
impl PlaybackHead{
#[wasm_bindgen(constructor)]
pub fn new(time:f64)->Result<Self,JsValue>{
pub fn new(bot:&CompleteBot,time:f64)->Result<Self,JsValue>{
let time=time::from_float(time).unwrap();
Ok(Self{
head:head::PlaybackHead::new(time),
head:head::PlaybackHead::new(&bot.bot,time),
})
}
#[wasm_bindgen]

View File

@@ -16,10 +16,7 @@ const canvas = document.getElementById("viewport");
const graphics = await setup_graphics(canvas);
const bot = new CompleteBot(new Uint8Array(await b.arrayBuffer()));
const map = new CompleteMap(new Uint8Array(await m.arrayBuffer()));
const playback = new PlaybackHead(0);
// Initialize playback (fill playback state from bot)
playback.advance_time(bot, 0);
const playback = new PlaybackHead(bot, 0);
graphics.change_map(map);
@@ -66,13 +63,15 @@ document.getElementById("control_pause").addEventListener("click", (e) => {
});
document.getElementById("control_forward").addEventListener("click", (e) => {
const time_now = elapsed();
const playback_time = playback.get_head_time(time_now) + playback.get_scale() * SEEK_DURATION;
playback.set_head_time(bot, time_now, playback_time);
const playback_time = playback.get_head_time(time_now);
const time_offset = playback.get_scale() * SEEK_DURATION;
playback.set_head_time(bot, time_now, playback_time + time_offset);
});
document.getElementById("control_backward").addEventListener("click", (e) => {
const time_now = elapsed();
const playback_time = playback.get_head_time(time_now) + playback.get_scale() * SEEK_DURATION;
playback.set_head_time(bot, time_now, playback_time);
const playback_time = playback.get_head_time(time_now);
const time_offset = playback.get_scale() * SEEK_DURATION;
playback.set_head_time(bot, time_now, playback_time - time_offset);
});
document.getElementById("control_slower").addEventListener("click", (e) => {
set_scale((scale * 4) / 5);