Compare commits

..

51 Commits

Author SHA1 Message Date
f98ffe6e0b fix spin bug edge case 2025-01-15 00:48:03 -08:00
f9d4ca8370 remove single use function 2025-01-15 00:36:15 -08:00
fea5bf4398 low polling rate edge case 2025-01-15 00:29:45 -08:00
d393f9f187 change some function names 2025-01-15 00:26:40 -08:00
ada34237c9 fix timeout timestamp 2025-01-15 00:02:26 -08:00
292df72709 transpose next buffer state calculation 2025-01-14 23:49:31 -08:00
7476d7cdc7 the mouse spin bug 2025-01-14 23:49:31 -08:00
6138d70a6f unify timeout 😍 2025-01-14 23:49:31 -08:00
cac4d698c3 fix overall correctness 2025-01-14 23:23:50 -08:00
e0ea0d6119 remove holdover case 2025-01-14 23:00:46 -08:00
80a4431ee8 test mouse_interpolator 2025-01-14 23:00:46 -08:00
80424cf24c spawn on map change 2025-01-14 21:41:55 -08:00
c338826513 finish 2025-01-14 21:16:36 -08:00
a6a242175b rewrite enums again 2025-01-14 20:44:17 -08:00
08bd57ffe1 remove incorrect comment 2025-01-14 19:02:34 -08:00
0d9c6648e2 accumulate mouse_pos as float 2025-01-14 19:00:17 -08:00
405cba3549 discover ternary method on bool 2025-01-14 18:39:38 -08:00
38d8dc1302 InstructionCache 2025-01-14 18:26:59 -08:00
33ccefc411 pop_buffered_instruction can be accomplished with mem::replace 2025-01-14 03:44:23 -08:00
93277c042b make pain code smaller 2025-01-14 01:45:09 -08:00
90f6437817 wrong instruction 2025-01-14 01:36:50 -08:00
29f9d5298f work 2025-01-14 01:34:26 -08:00
b0489a3746 work work work 2025-01-13 23:59:16 -08:00
a8847d3632 ruin physics code 2025-01-13 23:55:42 -08:00
fb8c2a619a rename fields in MouseInstruction::ReplaceMouse 2025-01-13 23:51:13 -08:00
6898302fa5 move code to more relevant location 2025-01-13 23:23:58 -08:00
52bbaaddc7 don't mutate physics_timeline on the fly 2025-01-13 23:23:58 -08:00
a8581a2a4f don't reconstruct MouseState struct with noop 2025-01-13 23:23:58 -08:00
c6ff11dd3e use replace_with to replace the enum variant in-place without cloning 2025-01-13 23:11:43 -08:00
844c7a08e1 add replace_with dep 2025-01-13 22:46:16 -08:00
bd61d03c91 work 2025-01-13 22:32:26 -08:00
b58ebb2775 todos 2025-01-11 01:50:06 -08:00
9095215cad write pop_buffered_instruction 2025-01-11 01:38:45 -08:00
92c30c3b87 cool changes 2025-01-11 01:07:06 -08:00
1b35c96f6e cook a bit 2025-01-10 23:18:53 -08:00
47bf9f1af3 pain 2025-01-10 22:08:54 -08:00
719c702b95 actually need ReplaceMouse because of OS level issue
The operating system does not report the timestamp at which it checks that the mouse was not moving, so the mouse interpolation will necessarily be incorrect for up to 1 polling period.  The alternative is to guess / make up a timestamp, but I don't want to do this.
2025-01-10 22:01:02 -08:00
ceb2499ad2 delete ReplaceMouse instruction 2025-01-10 20:59:25 -08:00
fe43ce9df6 progress 2025-01-10 20:03:53 -08:00
1fcd18bc45 how does it work 2025-01-09 21:20:25 -08:00
e371f95a4b a 2025-01-09 21:14:17 -08:00
b02c1bc7b4 idk if dropinstruction is gonan work 2025-01-09 21:14:15 -08:00
89446a933a a 2025-01-09 20:48:11 -08:00
0a3d965bb6 work 2025-01-09 20:48:11 -08:00
b6206d52c8 work 2025-01-09 20:48:11 -08:00
498c628280 asd 2025-01-09 20:48:11 -08:00
273e915f67 no 2025-01-09 20:48:11 -08:00
5072e5d7a8 yeah 2025-01-09 20:48:11 -08:00
3f0e3e0d3c update mouse interpolator code 2025-01-09 20:48:11 -08:00
2e88ae0612 wip 2025-01-09 20:48:11 -08:00
4c216a5b28 wip 2025-01-09 20:48:11 -08:00
11 changed files with 346 additions and 589 deletions

View File

@@ -1,19 +1,10 @@
use crate::integer::Time;
#[derive(Clone,Debug)]
#[derive(Debug)]
pub struct TimedInstruction<I,T>{
pub time:Time<T>,
pub instruction:I,
}
impl<I,T> TimedInstruction<I,T>{
#[inline]
pub fn set_time<TimeInner>(self,new_time:Time<TimeInner>)->TimedInstruction<I,TimeInner>{
TimedInstruction{
time:new_time,
instruction:self.instruction,
}
}
}
/// Ensure all emitted instructions are processed before consuming external instructions
pub trait InstructionEmitter<I>{
@@ -30,7 +21,6 @@ pub trait InstructionFeedback<I,T>:InstructionEmitter<I,TimeInner=T>+Instruction
where
Time<T>:Copy,
{
#[inline]
fn process_exhaustive(&mut self,time_limit:Time<T>){
while let Some(instruction)=self.next_instruction(time_limit){
self.process_instruction(instruction);
@@ -43,6 +33,42 @@ impl<I,T,X> InstructionFeedback<I,T> for X
X:InstructionEmitter<I,TimeInner=T>+InstructionConsumer<I,TimeInner=T>,
{}
pub struct InstructionCache<S,I,T>{
instruction_machine:S,
cached_instruction:Option<TimedInstruction<I,T>>,
time_limit:Time<T>,
}
impl<S,I,T> InstructionCache<S,I,T>
where
Time<T>:Copy+Ord,
Option<TimedInstruction<I,T>>:Clone,
S:InstructionEmitter<I,TimeInner=T>+InstructionConsumer<I,TimeInner=T>
{
pub fn new(
instruction_machine:S,
)->Self{
Self{
instruction_machine,
cached_instruction:None,
time_limit:Time::MIN,
}
}
pub fn next_instruction_cached(&mut self,time_limit:Time<T>)->Option<TimedInstruction<I,T>>{
if time_limit<self.time_limit{
return self.cached_instruction.clone();
}
let next_instruction=self.instruction_machine.next_instruction(time_limit);
self.cached_instruction=next_instruction.clone();
self.time_limit=time_limit;
next_instruction
}
pub fn process_instruction(&mut self,instruction:TimedInstruction<I,T>){
// invalidate cache
self.time_limit=Time::MIN;
self.instruction_machine.process_instruction(instruction);
}
}
//PROPER PRIVATE FIELDS!!!
pub struct InstructionCollector<I,T>{
time:Time<T>,
@@ -51,7 +77,6 @@ pub struct InstructionCollector<I,T>{
impl<I,T> InstructionCollector<I,T>
where Time<T>:Copy+PartialOrd,
{
#[inline]
pub const fn new(time:Time<T>)->Self{
Self{
time,
@@ -63,18 +88,24 @@ impl<I,T> InstructionCollector<I,T>
self.time
}
pub fn collect(&mut self,instruction:Option<TimedInstruction<I,T>>){
if let Some(ins)=instruction{
if ins.time<self.time{
self.time=ins.time;
self.instruction=Some(ins.instruction);
}
match instruction{
Some(unwrap_instruction)=>{
if unwrap_instruction.time<self.time {
self.time=unwrap_instruction.time;
self.instruction=Some(unwrap_instruction.instruction);
}
},
None=>(),
}
}
pub fn instruction(self)->Option<TimedInstruction<I,T>>{
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
self.instruction.map(|instruction|TimedInstruction{
time:self.time,
instruction
})
match self.instruction{
Some(instruction)=>Some(TimedInstruction{
time:self.time,
instruction
}),
None=>None,
}
}
}

View File

@@ -568,7 +568,7 @@ pub mod vec3{
Planar64Vec3::new(array.map(Planar64::raw))
}
#[inline]
pub const fn raw_xyz(x:i64,y:i64,z:i64)->Planar64Vec3{
pub fn raw_xyz(x:i64,y:i64,z:i64)->Planar64Vec3{
Planar64Vec3::new([Planar64::raw(x),Planar64::raw(y),Planar64::raw(z)])
}
#[inline]

View File

@@ -7,14 +7,16 @@ pub type Time=crate::integer::Time<TimeInner>;
#[derive(Clone,Debug)]
pub enum Instruction{
Mouse(MouseInstruction),
SetControl(SetControlInstruction),
Mode(ModeInstruction),
Misc(MiscInstruction),
/// Idle: there were no input events, but the simulation is safe to advance to this timestep
Idle,
Other(OtherInstruction),
}
impl Instruction{
pub const IDLE:Self=Self::Idle;
pub const IDLE:Self=Self::Other(OtherInstruction::Other(OtherOtherInstruction::Idle));
}
#[derive(Clone,Debug)]
pub enum OtherInstruction{
SetControl(SetControlInstruction),
Mode(ModeInstruction),
Other(OtherOtherInstruction),
}
#[derive(Clone,Debug)]
pub enum MouseInstruction{
@@ -48,7 +50,9 @@ pub enum ModeInstruction{
Spawn(crate::gameplay_modes::ModeId,crate::gameplay_modes::StageId),
}
#[derive(Clone,Debug)]
pub enum MiscInstruction{
pub enum OtherOtherInstruction{
/// Idle: there were no input events, but the simulation is safe to advance to this timestep
Idle,
PracticeFly,
SetSensitivity(crate::integer::Ratio64Vec2),
}

View File

@@ -1,6 +1,6 @@
use bnum::{BInt,cast::As};
#[derive(Clone,Copy,Debug,Default,Hash,PartialEq,Eq,PartialOrd,Ord)]
#[derive(Clone,Copy,Debug,Default,Hash,PartialEq,PartialOrd,Ord)]
/// A Fixed point number for which multiply operations widen the bits in the output. (when the wide-mul feature is enabled)
/// N is the number of u64s to use
/// F is the number of fractional bits (always N*32 lol)
@@ -97,6 +97,7 @@ where
self.bits.eq(&other.into())
}
}
impl<const N:usize,const F:usize> Eq for Fixed<N,F>{}
impl<const N:usize,const F:usize,T> PartialOrd<T> for Fixed<N,F>
where

View File

@@ -86,7 +86,6 @@ for model_id in 0..num_models{
//if you hash the resource itself and set the first 8 bits to this, that's the resource uuid
#[binrw]
#[brw(little,repr=u8)]
#[repr(u8)]
enum ResourceType{
Mesh,
Texture,

View File

@@ -66,7 +66,6 @@ struct Face{
normal:Planar64Vec3,
dot:Planar64,
}
#[derive(Clone)]
struct Vert(Planar64Vec3);
pub trait MeshQuery{
type Face:Clone;
@@ -85,45 +84,41 @@ pub trait MeshQuery{
}
fn vert(&self,vert_id:Self::Vert)->Planar64Vec3;
fn face_nd(&self,face_id:Self::Face)->(Self::Normal,Self::Offset);
fn face_edges(&self,face_id:Self::Face)->Cow<[Self::Edge]>;
fn face_edges(&self,face_id:Self::Face)->Cow<Vec<Self::Edge>>;
fn edge_faces(&self,edge_id:<Self::Edge as DirectedEdge>::UndirectedEdge)->Cow<[Self::Face;2]>;
fn edge_verts(&self,edge_id:<Self::Edge as DirectedEdge>::UndirectedEdge)->Cow<[Self::Vert;2]>;
fn vert_edges(&self,vert_id:Self::Vert)->Cow<[Self::Edge]>;
fn vert_faces(&self,vert_id:Self::Vert)->Cow<[Self::Face]>;
fn vert_edges(&self,vert_id:Self::Vert)->Cow<Vec<Self::Edge>>;
fn vert_faces(&self,vert_id:Self::Vert)->Cow<Vec<Self::Face>>;
}
#[derive(Clone)]
struct FaceRefs{
edges:Cow<'static,[SubmeshDirectedEdgeId]>,
//verts:Cow<'static,[VertId]>,
edges:Vec<SubmeshDirectedEdgeId>,
//verts:Vec<VertId>,
}
#[derive(Clone)]
struct EdgeRefs{
faces:[SubmeshFaceId;2],//left, right
verts:[SubmeshVertId;2],//bottom, top
}
#[derive(Clone)]
struct VertRefs{
faces:Cow<'static,[SubmeshFaceId]>,
edges:Cow<'static,[SubmeshDirectedEdgeId]>,
faces:Vec<SubmeshFaceId>,
edges:Vec<SubmeshDirectedEdgeId>,
}
// I don't want to use cow in the mesh, I'd rather have another type and monomorphize using the MeshQuery trait
pub struct PhysicsMeshData{
//this contains all real and virtual faces used in both the complete mesh and convex submeshes
//faces are sorted such that all faces that belong to the complete mesh appear first, and then
//all remaining faces are virtual to operate internal logic of the face crawler
//and cannot be part of a physics collision
//virtual faces are only used in convex submeshes.
faces:Cow<'static,[Face]>,//MeshFaceId indexes this list
verts:Cow<'static,[Vert]>,//MeshVertId indexes this list
faces:Vec<Face>,//MeshFaceId indexes this list
verts:Vec<Vert>,//MeshVertId indexes this list
}
pub struct PhysicsMeshTopology{
//mapping of local ids to PhysicsMeshData ids
faces:Cow<'static,[MeshFaceId]>,//SubmeshFaceId indexes this list
verts:Cow<'static,[MeshVertId]>,//SubmeshVertId indexes this list
faces:Vec<MeshFaceId>,//SubmeshFaceId indexes this list
verts:Vec<MeshVertId>,//SubmeshVertId indexes this list
//all ids here are local to this object
face_topology:Cow<'static,[FaceRefs]>,
edge_topology:Cow<'static,[EdgeRefs]>,
vert_topology:Cow<'static,[VertRefs]>,
face_topology:Vec<FaceRefs>,
edge_topology:Vec<EdgeRefs>,
vert_topology:Vec<VertRefs>,
}
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
pub struct PhysicsMeshId(u32);
@@ -149,41 +144,39 @@ pub struct PhysicsMesh{
}
impl PhysicsMesh{
pub fn unit_cube()->Self{
const MESH_DATA_FACES:[Face;6]=[
Face{normal:vec3::raw_xyz( 4294967296, 0, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0, 4294967296, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0, 0, 4294967296),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz(-4294967296, 0, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0,-4294967296, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0, 0,-4294967296),dot:Planar64::raw(4294967296)}
];
const MESH_DATA_VERTS:[Vert;8]=[
Vert(vec3::raw_xyz( 4294967296,-4294967296,-4294967296)),
Vert(vec3::raw_xyz( 4294967296, 4294967296,-4294967296)),
Vert(vec3::raw_xyz( 4294967296, 4294967296, 4294967296)),
Vert(vec3::raw_xyz( 4294967296,-4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296, 4294967296,-4294967296)),
Vert(vec3::raw_xyz(-4294967296, 4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296,-4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296,-4294967296,-4294967296))
];
//go go gadget debug print mesh
let data=PhysicsMeshData{
faces:Cow::Borrowed(&MESH_DATA_FACES),
verts:Cow::Borrowed(&MESH_DATA_VERTS)
faces:vec![
Face{normal:vec3::raw_xyz( 4294967296, 0, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0, 4294967296, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0, 0, 4294967296),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz(-4294967296, 0, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0,-4294967296, 0),dot:Planar64::raw(4294967296)},
Face{normal:vec3::raw_xyz( 0, 0,-4294967296),dot:Planar64::raw(4294967296)}
],
verts:vec![
Vert(vec3::raw_xyz( 4294967296,-4294967296,-4294967296)),
Vert(vec3::raw_xyz( 4294967296, 4294967296,-4294967296)),
Vert(vec3::raw_xyz( 4294967296, 4294967296, 4294967296)),
Vert(vec3::raw_xyz( 4294967296,-4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296, 4294967296,-4294967296)),
Vert(vec3::raw_xyz(-4294967296, 4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296,-4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296,-4294967296,-4294967296))
]
};
let mesh_topology=PhysicsMeshTopology{
faces:(0..data.faces.len() as u32).map(MeshFaceId::new).collect(),
verts:(0..data.verts.len() as u32).map(MeshVertId::new).collect(),
face_topology:Cow::Borrowed(&[
FaceRefs{edges:Cow::Borrowed(&[SubmeshDirectedEdgeId((9223372036854775808u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775809u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775810u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(3)])},
FaceRefs{edges:Cow::Borrowed(&[SubmeshDirectedEdgeId((9223372036854775812u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775813u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId(1)])},
FaceRefs{edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId((9223372036854775814u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775816u64-(1<<63)+(1<<31)) as u32)])},
FaceRefs{edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId((9223372036854775817u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(10)])},
FaceRefs{edges:Cow::Borrowed(&[SubmeshDirectedEdgeId((9223372036854775815u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775818u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId((9223372036854775811u64-(1<<63)+(1<<31)) as u32)])},
FaceRefs{edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId((9223372036854775819u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(9)])},
]),
edge_topology:Cow::Borrowed(&[
face_topology:vec![
FaceRefs{edges:vec![SubmeshDirectedEdgeId((9223372036854775808u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775809u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775810u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(3)]},
FaceRefs{edges:vec![SubmeshDirectedEdgeId((9223372036854775812u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775813u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId(1)]},
FaceRefs{edges:vec![SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId((9223372036854775814u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775816u64-(1<<63)+(1<<31)) as u32)]},
FaceRefs{edges:vec![SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId((9223372036854775817u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(10)]},
FaceRefs{edges:vec![SubmeshDirectedEdgeId((9223372036854775815u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775818u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId((9223372036854775811u64-(1<<63)+(1<<31)) as u32)]},
FaceRefs{edges:vec![SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId((9223372036854775819u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(9)]}
],
edge_topology:vec![
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(5)],verts:[SubmeshVertId(0),SubmeshVertId(1)]},
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(1)],verts:[SubmeshVertId(1),SubmeshVertId(2)]},
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(2)],verts:[SubmeshVertId(2),SubmeshVertId(3)]},
@@ -196,17 +189,17 @@ impl PhysicsMesh{
EdgeRefs{faces:[SubmeshFaceId(3),SubmeshFaceId(5)],verts:[SubmeshVertId(4),SubmeshVertId(7)]},
EdgeRefs{faces:[SubmeshFaceId(4),SubmeshFaceId(3)],verts:[SubmeshVertId(6),SubmeshVertId(7)]},
EdgeRefs{faces:[SubmeshFaceId(5),SubmeshFaceId(4)],verts:[SubmeshVertId(0),SubmeshVertId(7)]}
]),
vert_topology:Cow::Borrowed(&[
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(0),SubmeshFaceId(4),SubmeshFaceId(5)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId((9223372036854775811u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775819u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775808u64-(1<<63)+(1<<31)) as u32)])},
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(0),SubmeshFaceId(5),SubmeshFaceId(1)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId((9223372036854775812u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId((9223372036854775809u64-(1<<63)+(1<<31)) as u32)])},
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(1)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(1),SubmeshDirectedEdgeId((9223372036854775810u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775814u64-(1<<63)+(1<<31)) as u32)])},
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(4)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId(3),SubmeshDirectedEdgeId((9223372036854775815u64-(1<<63)+(1<<31)) as u32)])},
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(3),SubmeshFaceId(5),SubmeshFaceId(1)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId((9223372036854775817u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775813u64-(1<<63)+(1<<31)) as u32)])},
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(1)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId((9223372036854775816u64-(1<<63)+(1<<31)) as u32)])},
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(4)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId((9223372036854775818u64-(1<<63)+(1<<31)) as u32)])},
VertRefs{faces:Cow::Borrowed(&[SubmeshFaceId(4),SubmeshFaceId(3),SubmeshFaceId(5)]),edges:Cow::Borrowed(&[SubmeshDirectedEdgeId(10),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId(9)])},
])
],
vert_topology:vec![
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(4),SubmeshFaceId(5)],edges:vec![SubmeshDirectedEdgeId((9223372036854775811u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775819u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775808u64-(1<<63)+(1<<31)) as u32)]},
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(5),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId((9223372036854775812u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId((9223372036854775809u64-(1<<63)+(1<<31)) as u32)]},
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(1),SubmeshDirectedEdgeId((9223372036854775810u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775814u64-(1<<63)+(1<<31)) as u32)]},
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(4)],edges:vec![SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId(3),SubmeshDirectedEdgeId((9223372036854775815u64-(1<<63)+(1<<31)) as u32)]},
VertRefs{faces:vec![SubmeshFaceId(3),SubmeshFaceId(5),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId((9223372036854775817u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775813u64-(1<<63)+(1<<31)) as u32)]},
VertRefs{faces:vec![SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId((9223372036854775816u64-(1<<63)+(1<<31)) as u32)]},
VertRefs{faces:vec![SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(4)],edges:vec![SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId((9223372036854775818u64-(1<<63)+(1<<31)) as u32)]},
VertRefs{faces:vec![SubmeshFaceId(4),SubmeshFaceId(3),SubmeshFaceId(5)],edges:vec![SubmeshDirectedEdgeId(10),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId(9)]}
]
};
Self{
data,
@@ -286,12 +279,15 @@ struct EdgePool{
}
impl EdgePool{
fn push(&mut self,edge_ref_verts:EdgeRefVerts)->(&mut EdgeRefFaces,SubmeshEdgeId){
let edge_id=*self.edge_id_from_guy.entry(edge_ref_verts.clone()).or_insert_with(||{
let edge_id=SubmeshEdgeId::new(self.edge_guys.len() as u32);
self.edge_guys.push((edge_ref_verts,EdgeRefFaces::new()));
let edge_id=if let Some(&edge_id)=self.edge_id_from_guy.get(&edge_ref_verts){
edge_id
});
(&mut self.edge_guys[edge_id.get() as usize].1,edge_id)
}else{
let edge_id=SubmeshEdgeId::new(self.edge_guys.len() as u32);
self.edge_guys.push((edge_ref_verts.clone(),EdgeRefFaces::new()));
self.edge_id_from_guy.insert(edge_ref_verts,edge_id);
edge_id
};
(&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id.get() as usize)}.1,edge_id)
}
}
@@ -326,11 +322,16 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
let mut submesh_verts=Vec::new();
let mut submesh_vert_id_from_mesh_vert_id=HashMap::<MeshVertId,SubmeshVertId>::new();
//lazy closure
let mut get_submesh_vert_id=|vert_id:MeshVertId|*submesh_vert_id_from_mesh_vert_id.entry(vert_id).or_insert_with(||{
let submesh_vert_id=SubmeshVertId::new(submesh_verts.len() as u32);
submesh_verts.push(vert_id);
submesh_vert_id
});
let mut get_submesh_vert_id=|vert_id:MeshVertId|{
if let Some(&submesh_vert_id)=submesh_vert_id_from_mesh_vert_id.get(&vert_id){
submesh_vert_id
}else{
let submesh_vert_id=SubmeshVertId::new(submesh_verts.len() as u32);
submesh_verts.push(vert_id);
submesh_vert_id_from_mesh_vert_id.insert(vert_id,submesh_vert_id);
submesh_vert_id
}
};
let mut edge_pool=EdgePool::default();
let mut vert_ref_guys=vec![VertRefGuy::default();mesh.unique_pos.len()];
let mut face_ref_guys=Vec::new();
@@ -363,10 +364,10 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
edge_ref_faces.push(!is_sorted as usize,submesh_face_id);
//index edges & face into vertices
{
let vert_ref_guy=&mut vert_ref_guys[submesh_vert0_id.get() as usize];
let vert_ref_guy=unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert0_id.get() as usize)};
vert_ref_guy.edges.insert(edge_id.as_directed(is_sorted));
vert_ref_guy.faces.insert(submesh_face_id);
vert_ref_guys[submesh_vert1_id.get() as usize].edges.insert(edge_id.as_directed(!is_sorted));
unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert1_id.get() as usize)}.edges.insert(edge_id.as_directed(!is_sorted));
}
//return directed_edge_id
edge_id.as_directed(is_sorted)
@@ -395,10 +396,10 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
}
}
PhysicsMeshTopology{
faces:submesh_faces.into(),
verts:submesh_verts.into(),
faces:submesh_faces,
verts:submesh_verts,
face_topology:face_ref_guys.into_iter().map(|face_ref_guy|{
FaceRefs{edges:face_ref_guy.0.into()}
FaceRefs{edges:face_ref_guy.0}
}).collect(),
edge_topology:edge_pool.edge_guys.into_iter().map(|(edge_ref_verts,edge_ref_faces)|
EdgeRefs{faces:edge_ref_faces.0,verts:edge_ref_verts.0}
@@ -413,7 +414,7 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
}).collect();
Ok(Self{
data:PhysicsMeshData{
faces:faces.into(),
faces,
verts,
},
complete_mesh:mesh_topologies.pop().ok_or(PhysicsMeshError::NoPhysicsGroups)?,
@@ -441,7 +442,7 @@ impl MeshQuery for PhysicsMeshView<'_>{
let vert_idx=self.topology.verts[vert_id.get() as usize].get() as usize;
self.data.verts[vert_idx].0
}
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<[SubmeshDirectedEdgeId]>{
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<Vec<SubmeshDirectedEdgeId>>{
Cow::Borrowed(&self.topology.face_topology[face_id.get() as usize].edges)
}
fn edge_faces(&self,edge_id:SubmeshEdgeId)->Cow<[SubmeshFaceId;2]>{
@@ -450,10 +451,10 @@ impl MeshQuery for PhysicsMeshView<'_>{
fn edge_verts(&self,edge_id:SubmeshEdgeId)->Cow<[SubmeshVertId;2]>{
Cow::Borrowed(&self.topology.edge_topology[edge_id.get() as usize].verts)
}
fn vert_edges(&self,vert_id:SubmeshVertId)->Cow<[SubmeshDirectedEdgeId]>{
fn vert_edges(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshDirectedEdgeId>>{
Cow::Borrowed(&self.topology.vert_topology[vert_id.get() as usize].edges)
}
fn vert_faces(&self,vert_id:SubmeshVertId)->Cow<[SubmeshFaceId]>{
fn vert_faces(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshFaceId>>{
Cow::Borrowed(&self.topology.vert_topology[vert_id.get() as usize].faces)
}
}
@@ -519,7 +520,7 @@ impl MeshQuery for TransformedMesh<'_>{
self.transform.vertex.transform_point3(self.view.vert(vert_id)).fix_1()
}
#[inline]
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<[SubmeshDirectedEdgeId]>{
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<Vec<SubmeshDirectedEdgeId>>{
self.view.face_edges(face_id)
}
#[inline]
@@ -531,11 +532,11 @@ impl MeshQuery for TransformedMesh<'_>{
self.view.edge_verts(edge_id)
}
#[inline]
fn vert_edges(&self,vert_id:SubmeshVertId)->Cow<[SubmeshDirectedEdgeId]>{
fn vert_edges(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshDirectedEdgeId>>{
self.view.vert_edges(vert_id)
}
#[inline]
fn vert_faces(&self,vert_id:SubmeshVertId)->Cow<[SubmeshFaceId]>{
fn vert_faces(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshFaceId>>{
self.view.vert_faces(vert_id)
}
}
@@ -711,20 +712,6 @@ impl MinkowskiMesh<'_>{
},
}
}
// TODO: fundamentally improve this algorithm.
// All it needs to do is find the closest point on the mesh
// and return the FEV which the point resides on.
//
// What it actually does is use the above functions to trace a ray in from infinity,
// crawling the closest point along the mesh surface until the ray reaches
// the starting point to discover the final FEV.
//
// The actual collision prediction probably does a single test
// and then immediately returns with 0 FEV transitions on average,
// because of the strict time_limit constraint.
//
// Most of the calculation time is just calculating the starting point
// for the "actual" crawling algorithm below (predict_collision_{in|out}).
fn closest_fev_not_inside(&self,mut infinity_body:Body)->Option<FEV<MinkowskiMesh>>{
infinity_body.infinity_dir().map_or(None,|dir|{
let infinity_fev=self.infinity_fev(-dir,infinity_body.position);
@@ -845,7 +832,7 @@ impl MeshQuery for MinkowskiMesh<'_>{
},
}
}
fn face_edges(&self,face_id:MinkowskiFace)->Cow<[MinkowskiDirectedEdge]>{
fn face_edges(&self,face_id:MinkowskiFace)->Cow<Vec<MinkowskiDirectedEdge>>{
match face_id{
MinkowskiFace::VertFace(v0,f1)=>{
Cow::Owned(self.mesh1.face_edges(f1).iter().map(|&edge_id1|{
@@ -946,7 +933,7 @@ impl MeshQuery for MinkowskiMesh<'_>{
},
}
}
fn vert_edges(&self,vert_id:MinkowskiVert)->Cow<[MinkowskiDirectedEdge]>{
fn vert_edges(&self,vert_id:MinkowskiVert)->Cow<Vec<MinkowskiDirectedEdge>>{
match vert_id{
MinkowskiVert::VertVert(v0,v1)=>{
let mut edges=Vec::new();
@@ -988,7 +975,7 @@ impl MeshQuery for MinkowskiMesh<'_>{
},
}
}
fn vert_faces(&self,_vert_id:MinkowskiVert)->Cow<[MinkowskiFace]>{
fn vert_faces(&self,_vert_id:MinkowskiVert)->Cow<Vec<MinkowskiFace>>{
unimplemented!()
}
}

View File

@@ -1,74 +1,28 @@
use strafesnet_common::mouse::MouseState;
use strafesnet_common::physics::{
MouseInstruction,SetControlInstruction,ModeInstruction,MiscInstruction,
Instruction as PhysicsInstruction,
Instruction as PhysicsInputInstruction,
TimeInner as PhysicsTimeInner,
Time as PhysicsTime,
MouseInstruction,
OtherInstruction,
};
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,TimedInstruction};
type TimedSelfInstruction=TimedInstruction<Instruction,PhysicsTimeInner>;
type DoubleTimedSelfInstruction=TimedInstruction<TimedSelfInstruction,SessionTimeInner>;
type TimedPhysicsInstruction=TimedInstruction<PhysicsInstruction,PhysicsTimeInner>;
type TimedPhysicsInstruction=TimedInstruction<PhysicsInputInstruction,PhysicsTimeInner>;
type TimedUnbufferedInstruction=TimedInstruction<Instruction,PhysicsTimeInner>;
type DoubleTimedUnbufferedInstruction=TimedInstruction<TimedUnbufferedInstruction,SessionTimeInner>;
const MOUSE_TIMEOUT:SessionTime=SessionTime::from_millis(10);
/// To be fed into MouseInterpolator
#[derive(Clone,Debug)]
pub(crate) enum Instruction{
pub enum Instruction{
MoveMouse(glam::IVec2),
SetControl(SetControlInstruction),
Mode(ModeInstruction),
Misc(MiscInstruction),
Idle,
}
#[derive(Clone,Debug)]
enum UnbufferedInstruction{
MoveMouse(glam::IVec2),
NonMouse(NonMouseInstruction),
}
#[derive(Clone,Debug)]
enum BufferedInstruction{
Mouse(MouseInstruction),
NonMouse(NonMouseInstruction),
}
#[derive(Clone,Debug)]
pub(crate) enum NonMouseInstruction{
SetControl(SetControlInstruction),
Mode(ModeInstruction),
Misc(MiscInstruction),
Idle,
}
impl From<Instruction> for UnbufferedInstruction{
#[inline]
fn from(value:Instruction)->Self{
match value{
Instruction::MoveMouse(mouse_instruction)=>UnbufferedInstruction::MoveMouse(mouse_instruction),
Instruction::SetControl(set_control_instruction)=>UnbufferedInstruction::NonMouse(NonMouseInstruction::SetControl(set_control_instruction)),
Instruction::Mode(mode_instruction)=>UnbufferedInstruction::NonMouse(NonMouseInstruction::Mode(mode_instruction)),
Instruction::Misc(misc_instruction)=>UnbufferedInstruction::NonMouse(NonMouseInstruction::Misc(misc_instruction)),
Instruction::Idle=>UnbufferedInstruction::NonMouse(NonMouseInstruction::Idle),
}
}
}
impl From<BufferedInstruction> for PhysicsInstruction{
#[inline]
fn from(value:BufferedInstruction)->Self{
match value{
BufferedInstruction::Mouse(mouse_instruction)=>PhysicsInstruction::Mouse(mouse_instruction),
BufferedInstruction::NonMouse(non_mouse_instruction)=>match non_mouse_instruction{
NonMouseInstruction::SetControl(set_control_instruction)=>PhysicsInstruction::SetControl(set_control_instruction),
NonMouseInstruction::Mode(mode_instruction)=>PhysicsInstruction::Mode(mode_instruction),
NonMouseInstruction::Misc(misc_instruction)=>PhysicsInstruction::Misc(misc_instruction),
NonMouseInstruction::Idle=>PhysicsInstruction::Idle,
},
}
}
Other(OtherInstruction),
}
pub(crate) enum StepInstruction{
pub enum StepInstruction{
Pop,
Timeout,
}
@@ -88,10 +42,10 @@ pub struct MouseInterpolator{
}
// Maybe MouseInterpolator manipulation is better expressed using impls
// and called from Instruction trait impls in session
impl InstructionConsumer<TimedSelfInstruction> for MouseInterpolator{
impl InstructionConsumer<TimedUnbufferedInstruction> for MouseInterpolator{
type TimeInner=SessionTimeInner;
fn process_instruction(&mut self,ins:DoubleTimedSelfInstruction){
self.push_unbuffered_input(ins.time,ins.instruction.time,ins.instruction.instruction.into())
fn process_instruction(&mut self,ins:DoubleTimedUnbufferedInstruction){
self.push_unbuffered_input(ins)
}
}
impl InstructionEmitter<StepInstruction> for MouseInterpolator{
@@ -111,7 +65,7 @@ impl MouseInterpolator{
fn push_mouse_and_flush_buffer(&mut self,ins:TimedInstruction<MouseInstruction,PhysicsTimeInner>){
self.buffer.push_front(TimedInstruction{
time:ins.time,
instruction:BufferedInstruction::Mouse(ins.instruction).into(),
instruction:PhysicsInputInstruction::Mouse(ins.instruction),
});
// flush buffer to output
if self.output.len()==0{
@@ -132,8 +86,7 @@ impl MouseInterpolator{
}
}
}
fn timeout_mouse(&mut self,timeout_time:PhysicsTime){
// the state always changes to unbuffered
fn timeout_mouse(&mut self,time:PhysicsTime){
let buffer_state=core::mem::replace(&mut self.buffer_state,BufferState::Unbuffered);
match buffer_state{
BufferState::Unbuffered=>(),
@@ -142,21 +95,28 @@ impl MouseInterpolator{
self.push_mouse_and_flush_buffer(TimedInstruction{
time:mouse_state.time,
instruction:MouseInstruction::ReplaceMouse{
m1:MouseState{pos:mouse_state.pos,time:timeout_time},
m1:MouseState{pos:mouse_state.pos,time},
m0:mouse_state,
},
});
}
BufferState::Buffered(_time,mouse_state)=>{
// duplicate the currently buffered mouse state but at a later (future, from the physics perspective) time
// convert to BufferState::Unbuffered
// use the first instruction which should be a mouse instruction
// to push a ReplaceMouse instruction
// duplicate the current mouse
self.push_mouse_and_flush_buffer(TimedInstruction{
// This should be simulation_timer.time(timeout)
// but the timer is not accessible from this scope
// and it's just here to say that the mouse isn't moving anyways.
// I think this is a divide by zero bug, two identical mouse_states will occupy the interpolation state
time:mouse_state.time,
instruction:MouseInstruction::SetNextMouse(MouseState{pos:mouse_state.pos,time:timeout_time}),
instruction:MouseInstruction::SetNextMouse(MouseState{pos:mouse_state.pos,time}),
});
},
}
}
fn push_unbuffered_input(&mut self,session_time:SessionTime,physics_time:PhysicsTime,ins:UnbufferedInstruction){
pub fn push_unbuffered_input(&mut self,ins:DoubleTimedUnbufferedInstruction){
// new input
// if there is zero instruction buffered, it means the mouse is not moving
// case 1: unbuffered
@@ -168,16 +128,18 @@ impl MouseInterpolator{
// case 3: stop
// a mouse event is buffered, but no mouse events have transpired within 10ms
// replace_with allows the enum variant to safely be replaced
// from behind a mutable reference, but a panic in the closure means that
// the entire program terminates rather than completing an unwind.
// push buffered mouse instruction and flush buffer to output
if self.get_mouse_timedout_at(ins.time).is_some(){
self.timeout_mouse(ins.instruction.time);
}
// replace_with allows the enum variant to safely be replaced from behind a mutable reference
let (ins_mouse,ins_other)=replace_with::replace_with_or_abort_and_return(&mut self.buffer_state,|buffer_state|{
match ins{
UnbufferedInstruction::MoveMouse(pos)=>{
let next_mouse_state=MouseState{pos,time:physics_time};
match ins.instruction.instruction{
Instruction::MoveMouse(pos)=>{
let next_mouse_state=MouseState{pos,time:ins.instruction.time};
match buffer_state{
BufferState::Unbuffered=>{
((None,None),BufferState::Initializing(session_time,next_mouse_state))
((None,None),BufferState::Initializing(ins.time,next_mouse_state))
},
BufferState::Initializing(_time,mouse_state)=>{
let ins_mouse=TimedInstruction{
@@ -187,19 +149,19 @@ impl MouseInterpolator{
m1:next_mouse_state.clone(),
},
};
((Some(ins_mouse),None),BufferState::Buffered(session_time,next_mouse_state))
((Some(ins_mouse),None),BufferState::Buffered(ins.time,next_mouse_state))
},
BufferState::Buffered(_time,mouse_state)=>{
let ins_mouse=TimedInstruction{
time:mouse_state.time,
instruction:MouseInstruction::SetNextMouse(next_mouse_state.clone()),
};
((Some(ins_mouse),None),BufferState::Buffered(session_time,next_mouse_state))
((Some(ins_mouse),None),BufferState::Buffered(ins.time,next_mouse_state))
},
}
},
UnbufferedInstruction::NonMouse(other_instruction)=>((None,Some(TimedInstruction{
time:physics_time,
Instruction::Other(other_instruction)=>((None,Some(TimedInstruction{
time:ins.instruction.time,
instruction:other_instruction,
})),buffer_state),
}
@@ -210,7 +172,7 @@ impl MouseInterpolator{
if let Some(ins)=ins_other{
let instruction=TimedInstruction{
time:ins.time,
instruction:BufferedInstruction::NonMouse(ins.instruction).into(),
instruction:PhysicsInputInstruction::Other(ins.instruction),
};
if matches!(self.buffer_state,BufferState::Unbuffered){
self.output.push_back(instruction);
@@ -219,7 +181,7 @@ impl MouseInterpolator{
}
}
}
fn buffered_instruction_with_timeout(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,SessionTimeInner>>{
pub fn buffered_instruction_with_timeout(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,SessionTimeInner>>{
match self.get_mouse_timedout_at(time_limit){
Some(timeout)=>Some(TimedInstruction{
time:timeout,
@@ -232,7 +194,7 @@ impl MouseInterpolator{
}),
}
}
pub fn pop_buffered_instruction(&mut self,ins:TimedInstruction<StepInstruction,PhysicsTimeInner>)->Option<TimedPhysicsInstruction>{
pub fn pop_buffered_instruction(&mut self,ins:TimedInstruction<StepInstruction,PhysicsTimeInner>)->Option<TimedInstruction<PhysicsInputInstruction,PhysicsTimeInner>>{
match ins.instruction{
StepInstruction::Pop=>(),
StepInstruction::Timeout=>self.timeout_mouse(ins.time),
@@ -253,11 +215,13 @@ mod test{
macro_rules! push{
($time:expr,$ins:expr)=>{
println!("in={:?}",$ins);
interpolator.push_unbuffered_input(
$time,
timer.time($time),
$ins,
);
interpolator.push_unbuffered_input(TimedInstruction{
time:$time,
instruction:TimedInstruction{
time:timer.time($time),
instruction:$ins,
}
});
while let Some(ins)=interpolator.buffered_instruction_with_timeout($time){
let ins_retimed=TimedInstruction{
time:timer.time(ins.time),
@@ -271,11 +235,11 @@ mod test{
// test each buffer_state transition
let mut t=SessionTime::ZERO;
push!(t,UnbufferedInstruction::MoveMouse(glam::ivec2(0,0)));
push!(t,Instruction::MoveMouse(glam::ivec2(0,0)));
t+=SessionTime::from_millis(5);
push!(t,UnbufferedInstruction::MoveMouse(glam::ivec2(0,0)));
push!(t,Instruction::MoveMouse(glam::ivec2(0,0)));
t+=SessionTime::from_millis(5);
push!(t,UnbufferedInstruction::MoveMouse(glam::ivec2(0,0)));
push!(t,Instruction::MoveMouse(glam::ivec2(0,0)));
t+=SessionTime::from_millis(1);
}
}

View File

@@ -19,7 +19,7 @@ type MouseState=strafesnet_common::mouse::MouseState<TimeInner>;
//external influence
//this is how you influence the physics from outside
use strafesnet_common::physics::{Instruction,MouseInstruction,ModeInstruction,MiscInstruction,SetControlInstruction};
use strafesnet_common::physics::{Instruction,OtherInstruction,MouseInstruction,ModeInstruction,OtherOtherInstruction,SetControlInstruction};
//internal influence
//when the physics asks itself what happens next, this is how it's represented
@@ -39,6 +39,9 @@ pub struct InputState{
controls:strafesnet_common::controls_bitflag::Controls,
}
impl InputState{
pub const fn get_next_mouse(&self)->&MouseState{
&self.next_mouse
}
fn set_next_mouse(&mut self,next_mouse:MouseState){
//I like your functions magic language
self.mouse=std::mem::replace(&mut self.next_mouse,next_mouse);
@@ -690,18 +693,18 @@ struct IntersectModel{
}
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
pub struct ContactCollision{
struct ContactCollision{
face_id:model_physics::MinkowskiFace,
model_id:ContactModelId,
submesh_id:PhysicsSubmeshId,
}
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
pub struct IntersectCollision{
struct IntersectCollision{
model_id:IntersectModelId,
submesh_id:PhysicsSubmeshId,
}
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
pub enum Collision{
enum Collision{
Contact(ContactCollision),
Intersect(IntersectCollision),
}
@@ -829,7 +832,17 @@ pub struct PhysicsState{
//a start zone. If you change mode, a new run is created.
run:run::Run,
}
//random collection of contextual data that doesn't belong in PhysicsState
pub struct PhysicsData{
//permanent map data
bvh:bvh::BvhNode<ConvexMeshId>,
//transient map/environment data (open world loads/unloads parts of this data)
models:PhysicsModels,
//semi-transient data
modes:gameplay_modes::Modes,
//cached calculations
hitbox_mesh:HitboxMesh,
}
impl Default for PhysicsState{
fn default()->Self{
Self{
@@ -846,18 +859,19 @@ impl Default for PhysicsState{
}
}
}
impl PhysicsState{
pub fn camera_body(&self)->Body{
Body{
position:self.body.position+self.style.camera_offset,
..self.body
impl Default for PhysicsData{
fn default()->Self{
Self{
bvh:bvh::BvhNode::default(),
models:Default::default(),
modes:Default::default(),
hitbox_mesh:StyleModifiers::default().calculate_mesh(),
}
}
pub const fn camera(&self)->PhysicsCamera{
self.camera
}
pub fn clear(&mut self){
}
impl PhysicsState{
fn clear(&mut self){
self.touching.clear();
}
fn reset_to_default(&mut self){
@@ -906,67 +920,49 @@ impl PhysicsState{
// });
// }
}
// shared geometry for simulations
pub struct PhysicsData{
//permanent map data
bvh:bvh::BvhNode<ConvexMeshId>,
//transient map/environment data (open world loads/unloads parts of this data)
models:PhysicsModels,
//semi-transient data
modes:gameplay_modes::Modes,
//cached calculations
hitbox_mesh:HitboxMesh,
}
impl Default for PhysicsData{
fn default()->Self{
Self{
bvh:bvh::BvhNode::default(),
models:Default::default(),
modes:Default::default(),
hitbox_mesh:StyleModifiers::default().calculate_mesh(),
}
}
}
// the collection of information required to run physics
pub struct PhysicsContext<'a>{
state:&'a mut PhysicsState,//this captures the entire state of the physics.
data:&'a PhysicsData,//data currently loaded into memory which is needded for physics to run, but is not part of the state.
#[derive(Default)]
pub struct PhysicsContext{
state:PhysicsState,//this captures the entire state of the physics.
data:PhysicsData,//data currently loaded into memory which is needded for physics to run, but is not part of the state.
}
// the physics consumes both Instruction and PhysicsInternalInstruction,
// but can only emit PhysicsInternalInstruction
impl InstructionConsumer<InternalInstruction> for PhysicsContext<'_>{
impl InstructionConsumer<InternalInstruction> for PhysicsContext{
type TimeInner=TimeInner;
fn process_instruction(&mut self,ins:TimedInstruction<InternalInstruction,TimeInner>){
atomic_internal_instruction(&mut self.state,&self.data,ins)
}
}
impl InstructionConsumer<Instruction> for PhysicsContext<'_>{
impl InstructionConsumer<Instruction> for PhysicsContext{
type TimeInner=TimeInner;
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,TimeInner>){
atomic_input_instruction(&mut self.state,&self.data,ins)
}
}
impl InstructionEmitter<InternalInstruction> for PhysicsContext<'_>{
impl InstructionEmitter<InternalInstruction> for PhysicsContext{
type TimeInner=TimeInner;
//this little next instruction function could cache its return value and invalidate the cached value by watching the State.
fn next_instruction(&self,time_limit:Time)->Option<TimedInstruction<InternalInstruction,TimeInner>>{
next_instruction_internal(&self.state,&self.data,time_limit)
}
}
impl PhysicsContext<'_>{
pub fn run_input_instruction(
state:&mut PhysicsState,
data:&PhysicsData,
instruction:TimedInstruction<Instruction,TimeInner>
){
let mut context=PhysicsContext{state,data};
context.process_exhaustive(instruction.time);
context.process_instruction(instruction);
impl PhysicsContext{
pub fn camera_body(&self)->Body{
Body{
position:self.state.body.position+self.state.style.camera_offset,
..self.state.body
}
}
pub const fn camera(&self)->PhysicsCamera{
self.state.camera
}
pub const fn get_next_mouse(&self)->&MouseState{
self.state.input_state.get_next_mouse()
}
}
impl PhysicsData{
/// use with caution, this is the only non-instruction way to mess with physics
pub fn generate_models(&mut self,map:&map::CompleteMap){
self.state.clear();
let mut modes=map.modes.clone();
for mode in &mut modes.modes{
mode.denormalize_data();
@@ -1097,12 +1093,17 @@ impl PhysicsData{
(IntersectAttributesId::new(attr_id as u32),attr)
).collect(),
};
self.bvh=bvh;
self.models=models;
self.modes=modes;
self.data.bvh=bvh;
self.data.models=models;
self.data.modes=modes;
//hitbox_mesh is unchanged
println!("Physics Objects: {}",model_count);
}
pub fn run_input_instruction(&mut self,instruction:TimedInstruction<Instruction,TimeInner>){
self.process_exhaustive(instruction.time);
self.process_instruction(instruction);
}
}
//this is the one who asks
@@ -1741,13 +1742,13 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
let should_advance_body=match ins.instruction{
//the body may as well be a quantum wave function
//as far as these instruction are concerned (they don't care where it is)
Instruction::Misc(MiscInstruction::SetSensitivity(..))
|Instruction::Mode(_)
|Instruction::SetControl(SetControlInstruction::SetZoom(..))
|Instruction::Idle=>false,
Instruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(..)))
|Instruction::Other(OtherInstruction::Mode(_))
|Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetZoom(..)))
|Instruction::Other(OtherInstruction::Other(OtherOtherInstruction::Idle))=>false,
//these controls only update the body if you are on the ground
Instruction::Mouse(_)
|Instruction::SetControl(_)=>{
|Instruction::Other(OtherInstruction::SetControl(_))=>{
match &state.move_state{
MoveState::Fly
|MoveState::Water
@@ -1757,7 +1758,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
}
},
//the body must be updated unconditionally
Instruction::Misc(MiscInstruction::PracticeFly)=>true,
Instruction::Other(OtherInstruction::Other(OtherOtherInstruction::PracticeFly))=>true,
};
if should_advance_body{
state.body.advance_time(state.time);
@@ -1773,14 +1774,14 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
state.camera.move_mouse(m0.pos-state.input_state.mouse.pos);
state.input_state.replace_mouse(m0,m1);
},
Instruction::Misc(MiscInstruction::SetSensitivity(sensitivity))=>state.camera.sensitivity=sensitivity,
Instruction::SetControl(SetControlInstruction::SetMoveForward(s))=>state.input_state.set_control(Controls::MoveForward,s),
Instruction::SetControl(SetControlInstruction::SetMoveLeft(s))=>state.input_state.set_control(Controls::MoveLeft,s),
Instruction::SetControl(SetControlInstruction::SetMoveBack(s))=>state.input_state.set_control(Controls::MoveBackward,s),
Instruction::SetControl(SetControlInstruction::SetMoveRight(s))=>state.input_state.set_control(Controls::MoveRight,s),
Instruction::SetControl(SetControlInstruction::SetMoveUp(s))=>state.input_state.set_control(Controls::MoveUp,s),
Instruction::SetControl(SetControlInstruction::SetMoveDown(s))=>state.input_state.set_control(Controls::MoveDown,s),
Instruction::SetControl(SetControlInstruction::SetJump(s))=>{
Instruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(sensitivity)))=>state.camera.sensitivity=sensitivity,
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetMoveForward(s)))=>state.input_state.set_control(Controls::MoveForward,s),
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetMoveLeft(s)))=>state.input_state.set_control(Controls::MoveLeft,s),
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetMoveBack(s)))=>state.input_state.set_control(Controls::MoveBackward,s),
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetMoveRight(s)))=>state.input_state.set_control(Controls::MoveRight,s),
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetMoveUp(s)))=>state.input_state.set_control(Controls::MoveUp,s),
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetMoveDown(s)))=>state.input_state.set_control(Controls::MoveDown,s),
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetJump(s)))=>{
state.input_state.set_control(Controls::Jump,s);
if let Some(walk_state)=state.move_state.get_walk_state(){
if let Some(jump_settings)=&state.style.jump{
@@ -1792,16 +1793,16 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
}
b_refresh_walk_target=false;
},
Instruction::SetControl(SetControlInstruction::SetZoom(s))=>{
Instruction::Other(OtherInstruction::SetControl(SetControlInstruction::SetZoom(s)))=>{
state.input_state.set_control(Controls::Zoom,s);
b_refresh_walk_target=false;
},
Instruction::Mode(ModeInstruction::Reset)=>{
Instruction::Other(OtherInstruction::Mode(ModeInstruction::Reset))=>{
//totally reset physics state
state.reset_to_default();
b_refresh_walk_target=false;
},
Instruction::Mode(ModeInstruction::Restart)=>{
Instruction::Other(OtherInstruction::Mode(ModeInstruction::Restart))=>{
//teleport to start zone
let mode=data.modes.get_mode(state.mode_state.get_mode_id());
let spawn_point=mode.and_then(|mode|
@@ -1817,7 +1818,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
b_refresh_walk_target=false;
}
// Spawn does not necessarily imply reset
Instruction::Mode(ModeInstruction::Spawn(mode_id,stage_id))=>{
Instruction::Other(OtherInstruction::Mode(ModeInstruction::Spawn(mode_id,stage_id)))=>{
//spawn at a particular stage
if let Some(mode)=data.modes.get_mode(mode_id){
if let Some(stage)=mode.get_stage(stage_id){
@@ -1831,7 +1832,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
}
b_refresh_walk_target=false;
},
Instruction::Misc(MiscInstruction::PracticeFly)=>{
Instruction::Other(OtherInstruction::Other(OtherOtherInstruction::PracticeFly))=>{
match &state.move_state{
MoveState::Fly=>{
state.set_move_state(data,MoveState::Air);
@@ -1842,7 +1843,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
}
b_refresh_walk_target=false;
},
Instruction::Idle=>{
Instruction::Other(OtherInstruction::Other(OtherOtherInstruction::Idle))=>{
//literally idle!
b_refresh_walk_target=false;
},

View File

@@ -1,27 +1,25 @@
use crate::graphics_worker::Instruction as GraphicsInstruction;
use crate::session::{
Session,Simulation,SessionInputInstruction,SessionControlInstruction,SessionPlaybackInstruction,
Instruction as SessionInstruction,
};
use crate::session::{SessionInputInstruction,Instruction as SessionInstruction,Session,Simulation};
use strafesnet_common::instruction::{TimedInstruction,InstructionConsumer};
use strafesnet_common::physics::Time as PhysicsTime;
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
use strafesnet_common::timer::Timer;
pub enum Instruction{
SessionInput(SessionInputInstruction),
SessionControl(SessionControlInstruction),
SessionPlayback(SessionPlaybackInstruction),
Input(SessionInputInstruction),
SetPaused(bool),
Render,
Resize(winit::dpi::PhysicalSize<u32>),
ChangeMap(strafesnet_common::map::CompleteMap),
}
const SESSION_INSTRUCTION_IDLE:SessionInstruction=SessionInstruction::Input(SessionInputInstruction::Other(strafesnet_common::physics::OtherOtherInstruction::Idle));
pub fn new<'a>(
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,
user_settings:crate::settings::UserSettings,
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTimeInner>>{
let physics=crate::physics::PhysicsState::default();
let physics=crate::physics::PhysicsContext::default();
let timer=Timer::unpaused(SessionTime::ZERO,PhysicsTime::ZERO);
let simulation=Simulation::new(timer,physics);
let mut session=Session::new(
@@ -44,29 +42,24 @@ pub fn new<'a>(
};
}
match ins.instruction{
Instruction::SessionInput(unbuffered_instruction)=>{
Instruction::Input(unbuffered_instruction)=>{
run_session_instruction!(ins.time,SessionInstruction::Input(unbuffered_instruction));
},
Instruction::SessionControl(unbuffered_instruction)=>{
run_session_instruction!(ins.time,SessionInstruction::Control(unbuffered_instruction));
},
Instruction::SessionPlayback(unbuffered_instruction)=>{
run_session_instruction!(ins.time,SessionInstruction::Playback(unbuffered_instruction));
Instruction::SetPaused(paused)=>{
run_session_instruction!(ins.time,SessionInstruction::SetPaused(paused));
},
Instruction::Render=>{
run_session_instruction!(ins.time,SessionInstruction::Idle);
if let Some(frame_state)=session.get_frame_state(ins.time){
run_graphics_worker_instruction!(GraphicsInstruction::Render(frame_state));
}
run_session_instruction!(ins.time,SESSION_INSTRUCTION_IDLE);
let frame_state=session.get_frame_state(ins.time);
run_graphics_worker_instruction!(GraphicsInstruction::Render(frame_state));
},
Instruction::Resize(physical_size)=>{
run_session_instruction!(ins.time,SessionInstruction::Idle);
run_session_instruction!(ins.time,SESSION_INSTRUCTION_IDLE);
let user_settings=session.user_settings().clone();
run_graphics_worker_instruction!(GraphicsInstruction::Resize(physical_size,user_settings));
},
Instruction::ChangeMap(complete_map)=>{
run_session_instruction!(ins.time,SessionInstruction::ChangeMap(&complete_map));
run_session_instruction!(ins.time,SessionInstruction::Input(SessionInputInstruction::Mode(crate::session::ImplicitModeInstruction::ResetAndSpawn(strafesnet_common::gameplay_modes::ModeId::MAIN,strafesnet_common::gameplay_modes::StageId::FIRST))));
run_graphics_worker_instruction!(GraphicsInstruction::ChangeMap(complete_map));
},
}

View File

@@ -1,11 +1,9 @@
use std::collections::HashMap;
use strafesnet_common::gameplay_modes::{ModeId,StageId};
use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,InstructionFeedback,TimedInstruction};
// session represents the non-hardware state of the client.
// Ideally it is a deterministic state which is atomically updated by instructions, same as the simulation state.
use strafesnet_common::physics::{
ModeInstruction,MiscInstruction,
ModeInstruction,OtherInstruction,OtherOtherInstruction,
Instruction as PhysicsInputInstruction,
TimeInner as PhysicsTimeInner,
Time as PhysicsTime
@@ -14,22 +12,20 @@ use strafesnet_common::timer::{Scaled,Timer};
use strafesnet_common::session::{TimeInner as SessionTimeInner,Time as SessionTime};
use crate::mouse_interpolator::{MouseInterpolator,StepInstruction,Instruction as MouseInterpolatorInstruction};
use crate::physics::{PhysicsContext,PhysicsData};
use crate::settings::UserSettings;
pub enum Instruction<'a>{
Input(SessionInputInstruction),
Control(SessionControlInstruction),
Playback(SessionPlaybackInstruction),
SetPaused(bool),
ChangeMap(&'a strafesnet_common::map::CompleteMap),
Idle,
//Graphics(crate::graphics_worker::Instruction),
}
pub enum SessionInputInstruction{
Mouse(glam::IVec2),
SetControl(strafesnet_common::physics::SetControlInstruction),
Mode(ImplicitModeInstruction),
Misc(strafesnet_common::physics::MiscInstruction),
Other(strafesnet_common::physics::OtherOtherInstruction),
}
/// Implicit mode instruction are fed separately to session.
/// Session generates the explicit mode instructions interlaced with a SetSensitivity instruction
@@ -39,20 +35,6 @@ pub enum ImplicitModeInstruction{
ResetAndSpawn(strafesnet_common::gameplay_modes::ModeId,strafesnet_common::gameplay_modes::StageId),
}
pub enum SessionControlInstruction{
SetPaused(bool),
// copy the current session simulation recording into a replay and view it
CopyRecordingIntoReplayAndSpectate,
StopSpectate,
}
pub enum SessionPlaybackInstruction{
SkipForward,
SkipBack,
TogglePaused,
DecreaseTimescale,
IncreaseTimescale,
}
pub struct FrameState{
pub body:crate::physics::Body,
pub camera:crate::physics::PhysicsCamera,
@@ -61,12 +43,12 @@ pub struct FrameState{
pub struct Simulation{
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
physics:crate::physics::PhysicsState,
physics:crate::physics::PhysicsContext,
}
impl Simulation{
pub const fn new(
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
physics:crate::physics::PhysicsState,
physics:crate::physics::PhysicsContext,
)->Self{
Self{
timer,
@@ -82,75 +64,30 @@ impl Simulation{
}
}
#[derive(Default)]
pub struct Recording{
instructions:Vec<TimedInstruction<PhysicsInputInstruction,PhysicsTimeInner>>,
}
impl Recording{
fn clear(&mut self){
self.instructions.clear();
}
}
pub struct Replay{
last_instruction_id:usize,
recording:Recording,
instructions:Vec<PhysicsInputInstruction>,
simulation:Simulation,
}
impl Replay{
pub const fn new(
recording:Recording,
instructions:Vec<PhysicsInputInstruction>,
simulation:Simulation,
)->Self{
Self{
last_instruction_id:0,
recording,
instructions,
simulation,
}
}
pub fn advance(&mut self,physics_data:&PhysicsData,time_limit:SessionTime){
let mut time=self.simulation.timer.time(time_limit);
loop{
if let Some(ins)=self.recording.instructions.get(self.last_instruction_id){
if ins.time<time{
PhysicsContext::run_input_instruction(&mut self.simulation.physics,physics_data,ins.clone());
self.last_instruction_id+=1;
}else{
break;
}
}else{
// loop playback
self.last_instruction_id=0;
// No need to reset physics because the very first instruction is 'Reset'
let new_time=self.recording.instructions.first().map_or(PhysicsTime::ZERO,|ins|ins.time);
self.simulation.timer.set_time(time_limit,new_time);
time=new_time;
}
}
}
}
#[derive(Clone,Copy,Hash,PartialEq,Eq)]
struct BotId(u32);
//#[derive(Clone,Copy,Hash,PartialEq,Eq)]
//struct PlayerId(u32);
enum ViewState{
Play,
//Spectate(PlayerId),
Replay(BotId),
}
pub struct Session{
user_settings:UserSettings,
mouse_interpolator:crate::mouse_interpolator::MouseInterpolator,
view_state:ViewState,
//gui:GuiState
geometry_shared:crate::physics::PhysicsData,
simulation:Simulation,
// below fields not included in lite session
recording:Recording,
//players:HashMap<PlayerId,Simulation>,
replays:HashMap<BotId,Replay>,
replays:Vec<Replay>,
}
impl Session{
pub fn new(
@@ -160,27 +97,15 @@ impl Session{
Self{
user_settings,
mouse_interpolator:MouseInterpolator::new(),
geometry_shared:Default::default(),
simulation,
view_state:ViewState::Play,
recording:Default::default(),
replays:HashMap::new(),
replays:Vec::new(),
}
}
fn clear_recording(&mut self){
self.recording.clear();
}
fn change_map(&mut self,map:&strafesnet_common::map::CompleteMap){
self.simulation.physics.clear();
self.geometry_shared.generate_models(map);
self.simulation.physics.generate_models(map);
}
pub fn get_frame_state(&self,time:SessionTime)->Option<FrameState>{
match &self.view_state{
ViewState::Play=>Some(self.simulation.get_frame_state(time)),
ViewState::Replay(bot_id)=>self.replays.get(bot_id).map(|replay|
replay.simulation.get_frame_state(time)
),
}
pub fn get_frame_state(&self,time:SessionTime)->FrameState{
self.simulation.get_frame_state(time)
}
pub fn user_settings(&self)->&UserSettings{
&self.user_settings
@@ -197,7 +122,6 @@ impl Session{
impl InstructionConsumer<Instruction<'_>> for Session{
type TimeInner=SessionTimeInner;
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,Self::TimeInner>){
// repetitive procedure macro
macro_rules! run_mouse_interpolator_instruction{
($instruction:expr)=>{
self.mouse_interpolator.process_instruction(TimedInstruction{
@@ -209,157 +133,55 @@ impl InstructionConsumer<Instruction<'_>> for Session{
});
};
}
// process any timeouts that occured since the last instruction
self.process_exhaustive(ins.time);
match ins.instruction{
// send it down to MouseInterpolator with two timestamps, SessionTime and PhysicsTime
Instruction::Input(SessionInputInstruction::Mouse(pos))=>{
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::MoveMouse(pos));
},
Instruction::Input(SessionInputInstruction::SetControl(set_control_instruction))=>{
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::SetControl(set_control_instruction));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::SetControl(set_control_instruction)));
},
Instruction::Input(SessionInputInstruction::Mode(ImplicitModeInstruction::ResetAndRestart))=>{
self.clear_recording();
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Mode(ModeInstruction::Reset));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Misc(MiscInstruction::SetSensitivity(self.user_settings().calculate_sensitivity())));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Mode(ModeInstruction::Restart));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Restart)));
},
Instruction::Input(SessionInputInstruction::Mode(ImplicitModeInstruction::ResetAndSpawn(mode_id,spawn_id)))=>{
self.clear_recording();
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Mode(ModeInstruction::Reset));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Misc(MiscInstruction::SetSensitivity(self.user_settings().calculate_sensitivity())));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Mode(ModeInstruction::Spawn(mode_id,spawn_id)));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Spawn(mode_id,spawn_id))));
},
Instruction::Input(SessionInputInstruction::Misc(misc_instruction))=>{
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Misc(misc_instruction));
Instruction::Input(SessionInputInstruction::Other(other_other_instruction))=>{
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(other_other_instruction)));
},
Instruction::Control(SessionControlInstruction::SetPaused(paused))=>{
Instruction::SetPaused(paused)=>{
// don't flush the buffered instructions in the mouse interpolator
// until the mouse is confirmed to be not moving at a later time
// what if they pause for 5ms lmao
_=self.simulation.timer.set_paused(ins.time,paused);
},
Instruction::Control(SessionControlInstruction::CopyRecordingIntoReplayAndSpectate)=>{
// Bind: B
// pause simulation
_=self.simulation.timer.set_paused(ins.time,true);
// create recording
let mut recording=Recording::default();
recording.instructions.extend(self.recording.instructions.iter().cloned());
// create timer starting at first instruction (or zero if the list is empty)
let new_time=recording.instructions.first().map_or(PhysicsTime::ZERO,|ins|ins.time);
let timer=Timer::unpaused(ins.time,new_time);
// create default physics state
let simulation=Simulation::new(timer,Default::default());
// invent a new bot id and insert the replay
let bot_id=BotId(self.replays.len() as u32);
self.replays.insert(bot_id,Replay::new(
recording,
simulation,
));
// begin spectate
self.view_state=ViewState::Replay(bot_id);
},
Instruction::Control(SessionControlInstruction::StopSpectate)=>{
let view_state=core::mem::replace(&mut self.view_state,ViewState::Play);
// delete the bot, otherwise it's inaccessible and wastes CPU
match view_state{
ViewState::Play=>(),
ViewState::Replay(bot_id)=>{
self.replays.remove(&bot_id);
},
}
_=self.simulation.timer.set_paused(ins.time,false);
},
Instruction::Playback(SessionPlaybackInstruction::IncreaseTimescale)=>{
match &self.view_state{
ViewState::Play=>{
// allow simulation timescale for fun
let scale=self.simulation.timer.get_scale();
self.simulation.timer.set_scale(ins.time,scale*5/4);
},
ViewState::Replay(bot_id)=>if let Some(replay)=self.replays.get_mut(bot_id){
let scale=replay.simulation.timer.get_scale();
replay.simulation.timer.set_scale(ins.time,scale*5/4);
},
}
},
Instruction::Playback(SessionPlaybackInstruction::DecreaseTimescale)=>{
match &self.view_state{
ViewState::Play=>{
// allow simulation timescale for fun
let scale=self.simulation.timer.get_scale();
self.simulation.timer.set_scale(ins.time,scale*4/5);
},
ViewState::Replay(bot_id)=>if let Some(replay)=self.replays.get_mut(bot_id){
let scale=replay.simulation.timer.get_scale();
replay.simulation.timer.set_scale(ins.time,scale*4/5);
},
}
},
Instruction::Playback(SessionPlaybackInstruction::SkipForward)=>{
match &self.view_state{
ViewState::Play=>(),
ViewState::Replay(bot_id)=>if let Some(replay)=self.replays.get_mut(bot_id){
let time=replay.simulation.timer.time(ins.time+SessionTime::from_secs(5));
replay.simulation.timer.set_time(ins.time,time);
},
}
},
Instruction::Playback(SessionPlaybackInstruction::SkipBack)=>{
match &self.view_state{
ViewState::Play=>(),
ViewState::Replay(bot_id)=>if let Some(replay)=self.replays.get_mut(bot_id){
let time=replay.simulation.timer.time(ins.time+SessionTime::from_secs(5));
replay.simulation.timer.set_time(ins.time,time);
// resimulate the entire playback lol
replay.last_instruction_id=0;
},
}
},
Instruction::Playback(SessionPlaybackInstruction::TogglePaused)=>{
match &self.view_state{
ViewState::Play=>(),
ViewState::Replay(bot_id)=>if let Some(replay)=self.replays.get_mut(bot_id){
_=replay.simulation.timer.set_paused(ins.time,!replay.simulation.timer.is_paused());
},
}
}
Instruction::ChangeMap(complete_map)=>{
self.clear_recording();
self.change_map(complete_map);
// ResetAndSpawn
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Reset)));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Other(OtherOtherInstruction::SetSensitivity(self.user_settings().calculate_sensitivity()))));
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Other(OtherInstruction::Mode(ModeInstruction::Spawn(ModeId::MAIN,StageId::FIRST))));
},
Instruction::Idle=>{
run_mouse_interpolator_instruction!(MouseInterpolatorInstruction::Idle);
// this just refreshes the replays
for replay in self.replays.values_mut(){
// TODO: filter idles from recording, inject new idles in real time
replay.advance(&self.geometry_shared,ins.time);
}
}
};
// process all emitted output instructions
// run all buffered instruction produced
self.process_exhaustive(ins.time);
}
}
impl InstructionConsumer<StepInstruction> for Session{
type TimeInner=SessionTimeInner;
fn process_instruction(&mut self,ins:TimedInstruction<StepInstruction,Self::TimeInner>){
let time=self.simulation.timer.time(ins.time);
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins.set_time(time)){
//record
self.recording.instructions.push(instruction.clone());
PhysicsContext::run_input_instruction(&mut self.simulation.physics,&self.geometry_shared,instruction);
// ins.time ignored???
let ins_retimed=TimedInstruction{
time:self.simulation.timer.time(ins.time),
instruction:ins.instruction,
};
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins_retimed){
self.simulation.physics.run_input_instruction(instruction);
}
}
}

View File

@@ -1,8 +1,8 @@
use strafesnet_common::instruction::TimedInstruction;
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
use strafesnet_common::physics::{MiscInstruction,SetControlInstruction};
use strafesnet_common::physics::{OtherInstruction,OtherOtherInstruction,SetControlInstruction};
use crate::physics_worker::Instruction as PhysicsWorkerInstruction;
use crate::session::{SessionInputInstruction,SessionControlInstruction,SessionPlaybackInstruction};
use crate::session::SessionInputInstruction;
pub enum Instruction{
Resize(winit::dpi::PhysicalSize<u32>),
@@ -37,7 +37,7 @@ impl WindowContext<'_>{
//pause unpause
self.physics_thread.send(TimedInstruction{
time,
instruction:PhysicsWorkerInstruction::SessionControl(SessionControlInstruction::SetPaused(!state)),
instruction:PhysicsWorkerInstruction::SetPaused(!state),
}).unwrap();
//recalculate pressed keys on focus
},
@@ -92,74 +92,29 @@ impl WindowContext<'_>{
},
(keycode,state)=>{
let s=state.is_pressed();
// internal variants for this scope
enum SessionInstructionSubset{
Input(SessionInputInstruction),
Control(SessionControlInstruction),
Playback(SessionPlaybackInstruction),
}
macro_rules! input_ctrl{
($variant:ident,$state:expr)=>{
Some(SessionInstructionSubset::Input(SessionInputInstruction::SetControl(SetControlInstruction::$variant($state))))
};
}
macro_rules! input_misc{
($variant:ident,$state:expr)=>{
s.then_some(SessionInstructionSubset::Input(SessionInputInstruction::Misc(MiscInstruction::$variant)))
};
}
macro_rules! session_ctrl{
($variant:ident,$state:expr)=>{
s.then_some(SessionInstructionSubset::Control(SessionControlInstruction::$variant))
};
}
macro_rules! session_playback{
($variant:ident,$state:expr)=>{
s.then_some(SessionInstructionSubset::Playback(SessionPlaybackInstruction::$variant))
};
}
impl From<SessionInstructionSubset> for PhysicsWorkerInstruction{
fn from(value:SessionInstructionSubset)->Self{
match value{
SessionInstructionSubset::Input(session_input_instruction)=>PhysicsWorkerInstruction::SessionInput(session_input_instruction),
SessionInstructionSubset::Control(session_control_instruction)=>PhysicsWorkerInstruction::SessionControl(session_control_instruction),
SessionInstructionSubset::Playback(session_playback_instruction)=>PhysicsWorkerInstruction::SessionPlayback(session_playback_instruction),
}
}
}
if let Some(session_instruction)=match keycode{
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space)=>input_ctrl!(SetJump,s),
// TODO: bind system so playback pausing can use spacebar
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Enter)=>session_playback!(TogglePaused,s),
winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowUp)=>session_playback!(IncreaseTimescale,s),
winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowDown)=>session_playback!(DecreaseTimescale,s),
winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowLeft)=>session_playback!(SkipBack,s),
winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowRight)=>session_playback!(SkipForward,s),
if let Some(session_input_instruction)=match keycode{
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space)=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetJump(s))),
winit::keyboard::Key::Character(key)=>match key.as_str(){
"W"|"w"=>input_ctrl!(SetMoveForward,s),
"A"|"a"=>input_ctrl!(SetMoveLeft,s),
"S"|"s"=>input_ctrl!(SetMoveBack,s),
"D"|"d"=>input_ctrl!(SetMoveRight,s),
"E"|"e"=>input_ctrl!(SetMoveUp,s),
"Q"|"q"=>input_ctrl!(SetMoveDown,s),
"Z"|"z"=>input_ctrl!(SetZoom,s),
"W"|"w"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveForward(s))),
"A"|"a"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveLeft(s))),
"S"|"s"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveBack(s))),
"D"|"d"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveRight(s))),
"E"|"e"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveUp(s))),
"Q"|"q"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetMoveDown(s))),
"Z"|"z"=>Some(SessionInputInstruction::SetControl(SetControlInstruction::SetZoom(s))),
"R"|"r"=>s.then(||{
//mouse needs to be reset since the position is absolute
self.mouse_pos=glam::DVec2::ZERO;
SessionInstructionSubset::Input(SessionInputInstruction::Mode(crate::session::ImplicitModeInstruction::ResetAndRestart))
SessionInputInstruction::Mode(crate::session::ImplicitModeInstruction::ResetAndRestart)
}),
"F"|"f"=>input_misc!(PracticeFly,s),
"B"|"b"=>session_ctrl!(CopyRecordingIntoReplayAndSpectate,s),
"X"|"x"=>session_ctrl!(StopSpectate,s),
"F"|"f"=>s.then_some(SessionInputInstruction::Other(OtherOtherInstruction::PracticeFly)),
_=>None,
},
_=>None,
}{
self.physics_thread.send(TimedInstruction{
time,
instruction:session_instruction.into(),
instruction:PhysicsWorkerInstruction::Input(session_input_instruction),
}).unwrap();
}
},
@@ -183,7 +138,7 @@ impl WindowContext<'_>{
self.mouse_pos+=glam::dvec2(delta.0,delta.1);
self.physics_thread.send(TimedInstruction{
time,
instruction:PhysicsWorkerInstruction::SessionInput(SessionInputInstruction::Mouse(self.mouse_pos.as_ivec2())),
instruction:PhysicsWorkerInstruction::Input(SessionInputInstruction::Mouse(self.mouse_pos.as_ivec2())),
}).unwrap();
},
winit::event::DeviceEvent::MouseWheel {
@@ -193,7 +148,7 @@ impl WindowContext<'_>{
if false{//self.physics.style.use_scroll{
self.physics_thread.send(TimedInstruction{
time,
instruction:PhysicsWorkerInstruction::SessionInput(SessionInputInstruction::SetControl(SetControlInstruction::SetJump(true))),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
instruction:PhysicsWorkerInstruction::Input(SessionInputInstruction::SetControl(SetControlInstruction::SetJump(true))),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
}).unwrap();
}
},