Compare commits

..

1 Commits

Author SHA1 Message Date
b4e1678b48 introduce lifetime of body 2026-01-27 10:35:32 -08:00
8 changed files with 80 additions and 96 deletions

4
Cargo.lock generated
View File

@@ -813,10 +813,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
[[package]]
name = "dag"
version = "0.1.0"
[[package]]
name = "ddsfile"
version = "0.5.2"

View File

@@ -7,7 +7,6 @@ members = [
"integration-testing",
"lib/bsp_loader",
"lib/common",
"lib/dag",
"lib/deferred_loader",
"lib/fixed_wide",
"lib/linear_ops",

View File

@@ -7,13 +7,14 @@ pub struct Body<T>{
pub time:Time<T>,
}
#[derive(Clone,Copy,Debug,Hash)]
pub struct Trajectory<T>{
pub struct Trajectory<'a,T>{
pub position:Planar64Vec3,
pub velocity:Planar64Vec3,
pub acceleration:Planar64Vec3,
pub time:Time<T>,
lifetime:core::marker::PhantomData<&'a Body<T>>,
}
impl<T> std::ops::Neg for Trajectory<T>{
impl<T> std::ops::Neg for Trajectory<'_,T>{
type Output=Self;
fn neg(self)->Self::Output{
Self{
@@ -21,17 +22,19 @@ impl<T> std::ops::Neg for Trajectory<T>{
velocity:-self.velocity,
acceleration:self.acceleration,
time:-self.time,
lifetime:core::marker::PhantomData,
}
}
}
impl<T:Copy> std::ops::Neg for &Trajectory<T>{
type Output=Trajectory<T>;
impl<'a,T:Copy> std::ops::Neg for &Trajectory<'a,T>{
type Output=Trajectory<'a,T>;
fn neg(self)->Self::Output{
Trajectory{
position:self.position,
velocity:-self.velocity,
acceleration:self.acceleration,
time:-self.time,
lifetime:core::marker::PhantomData,
}
}
}
@@ -47,22 +50,23 @@ impl<T> Body<T>
time,
}
}
pub const fn with_acceleration(self,acceleration:Planar64Vec3)->Trajectory<T>{
pub const fn with_acceleration<'a>(&'a self,acceleration:Planar64Vec3)->Trajectory<'a,T>{
let Body{
position,
velocity,
time,
}=self;
}=*self;
Trajectory{
position,
velocity,
acceleration,
time,
lifetime:core::marker::PhantomData,
}
}
}
impl<T> Trajectory<T>
impl<T> Trajectory<'_,T>
where Time<T>:Copy,
{
pub const ZERO:Self=Self::new(vec3::zero(),vec3::zero(),vec3::zero(),Time::ZERO);
@@ -72,6 +76,7 @@ impl<T> Trajectory<T>
velocity,
acceleration,
time,
lifetime:core::marker::PhantomData,
}
}
pub fn relative_to(&self,trj0:&Self,time:Time<T>)->Self{
@@ -185,7 +190,7 @@ impl<T> std::fmt::Display for Body<T>{
write!(f,"p({}) v({}) t({})",self.position,self.velocity,self.time)
}
}
impl<T> std::fmt::Display for Trajectory<T>{
impl<T> std::fmt::Display for Trajectory<'_,T>{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"p({}) v({}) a({}) t({})",self.position,self.velocity,self.acceleration,self.time)
}

View File

@@ -5,7 +5,7 @@ use strafesnet_common::model::{self,MeshId,PolygonIter};
use strafesnet_common::integer::{self,vec3,Fixed,Planar64,Planar64Vec3,Ratio};
use strafesnet_common::physics::Time;
type Trajectory=crate::body::Trajectory<strafesnet_common::physics::TimeInner>;
type Trajectory<'a>=crate::body::Trajectory<'a,strafesnet_common::physics::TimeInner>;
struct AsRefHelper<T>(T);
impl<T> AsRef<T> for AsRefHelper<T>{

View File

@@ -15,7 +15,7 @@ pub use strafesnet_common::physics::{Time,TimeInner};
use gameplay::ModeState;
pub type Body=crate::body::Body<TimeInner>;
pub type Trajectory=crate::body::Trajectory<TimeInner>;
pub type Trajectory<'a>=crate::body::Trajectory<'a,TimeInner>;
type MouseState=strafesnet_common::mouse::MouseState<TimeInner>;
//external influence
@@ -517,7 +517,7 @@ impl MoveState{
}
}
//function to coerce &mut self into &self
fn update_fly_velocity(&self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
fn apply_to_body(&self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
match self{
MoveState::Air=>(),
MoveState::Water=>(),
@@ -533,7 +533,7 @@ impl MoveState{
}
}
/// changes the move state
fn update_walk_target(&mut self,body:&Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
fn apply_input(&mut self,body:&Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
match self{
MoveState::Fly
|MoveState::Air
@@ -590,11 +590,22 @@ impl MoveState{
MoveState::Fly=>None,
}
}
//lmao idk this is convenient
fn apply_enum_and_input_and_body(&mut self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
self.apply_input(body,touching,models,hitbox_mesh,style,camera,input_state);
self.apply_to_body(body,touching,models,hitbox_mesh,style,camera,input_state);
}
fn apply_enum_and_body(&mut self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
self.apply_to_body(body,touching,models,hitbox_mesh,style,camera,input_state);
}
fn apply_input_and_body(&mut self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
self.apply_input(body,touching,models,hitbox_mesh,style,camera,input_state);
self.apply_to_body(body,touching,models,hitbox_mesh,style,camera,input_state);
}
fn set_move_state(&mut self,move_state:MoveState,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
*self=move_state;
//this function call reads the above state that was just set
self.update_walk_target(body,touching,models,hitbox_mesh,style,camera,input_state);
self.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state);
self.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
}
fn cull_velocity(&mut self,velocity:Planar64Vec3,body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
//TODO: be more precise about contacts
@@ -607,11 +618,10 @@ impl MoveState{
self.set_move_state(MoveState::Air,body,touching,models,hitbox_mesh,style,camera,input_state);
}else{
// stopped touching something else while walking
self.update_walk_target(body,touching,models,hitbox_mesh,style,camera,input_state);
self.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state);
self.apply_enum_and_input_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
},
// not walking, but stopped touching something
None=>self.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state),
None=>self.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state),
}
}
}
@@ -899,7 +909,7 @@ impl PhysicsState{
pub const fn body(&self)->&Body{
&self.body
}
pub fn camera_trajectory(&self,data:&PhysicsData)->Trajectory{
pub fn camera_trajectory(&self,data:&PhysicsData)->Trajectory<'static>{
let acceleration=self.acceleration(data);
Trajectory::new(
self.body.position+self.style.camera_offset,
@@ -935,6 +945,9 @@ impl PhysicsState{
fn set_move_state(&mut self,data:&PhysicsData,move_state:MoveState){
self.move_state.set_move_state(move_state,&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state);
}
fn apply_input_and_body(&mut self,data:&PhysicsData){
self.move_state.apply_input_and_body(&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state);
}
fn acceleration(&self,data:&PhysicsData)->Planar64Vec3{
self.move_state.acceleration(&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state)
}
@@ -1183,43 +1196,43 @@ impl<'a> PhysicsContext<'a>{
}
}
//this is the one who asks
fn next_instruction_internal(state:&PhysicsState,data:&PhysicsData,time_limit:Time)->Option<TimedInstruction<InternalInstruction,Time>>{
//JUST POLLING!!! NO MUTATION
let mut collector=instruction::InstructionCollector::new(time_limit);
//this is the one who asks
fn next_instruction_internal(state:&PhysicsState,data:&PhysicsData,time_limit:Time)->Option<TimedInstruction<InternalInstruction,Time>>{
//JUST POLLING!!! NO MUTATION
let mut collector=instruction::InstructionCollector::new(time_limit);
collector.collect(state.next_move_instruction());
collector.collect(state.next_move_instruction());
let trajectory=state.body.with_acceleration(state.acceleration(data));
//check for collision ends
state.touching.predict_collision_end(&mut collector,&data.models,&data.hitbox_mesh,&trajectory,state.time);
//check for collision starts
let mut aabb=aabb::Aabb::default();
trajectory.grow_aabb(&mut aabb,state.time,collector.time());
aabb.inflate(data.hitbox_mesh.halfsize);
//relative to moving platforms
//let relative_body=state.body.relative_to(&Body::ZERO);
data.bvh.sample_aabb(&aabb,&mut |convex_mesh_id|{
if state.touching.contains(convex_mesh_id){
return;
}
//no checks are needed because of the time limits.
let model_mesh=data.models.mesh(*convex_mesh_id);
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
collector.collect(minkowski.predict_collision_in(&trajectory,state.time..collector.time())
.map(|(face,dt)|
TimedInstruction{
time:trajectory.time+dt.into(),
instruction:InternalInstruction::CollisionStart(
Collision::new(*convex_mesh_id,face),
dt
)
}
)
);
});
collector.take()
}
let trajectory=state.body.with_acceleration(state.acceleration(data));
//check for collision ends
state.touching.predict_collision_end(&mut collector,&data.models,&data.hitbox_mesh,&trajectory,state.time);
//check for collision starts
let mut aabb=aabb::Aabb::default();
trajectory.grow_aabb(&mut aabb,state.time,collector.time());
aabb.inflate(data.hitbox_mesh.halfsize);
//relative to moving platforms
//let relative_body=state.body.relative_to(&Body::ZERO);
data.bvh.sample_aabb(&aabb,&mut |convex_mesh_id|{
if state.touching.contains(convex_mesh_id){
return;
}
//no checks are needed because of the time limits.
let model_mesh=data.models.mesh(*convex_mesh_id);
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
collector.collect(minkowski.predict_collision_in(&trajectory,state.time..collector.time())
.map(|(face,dt)|
TimedInstruction{
time:trajectory.time+dt.into(),
instruction:InternalInstruction::CollisionStart(
Collision::new(*convex_mesh_id,face),
dt
)
}
)
);
});
collector.take()
}
fn contact_normal(
@@ -1607,8 +1620,7 @@ fn collision_start_contact(
}
//doing enum to set the acceleration when surfing
//doing input_and_body to refresh the walk state if you hit a wall while accelerating
move_state.update_walk_target(body,touching,models,hitbox_mesh,style,camera,input_state);
move_state.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state);
move_state.apply_enum_and_input_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
}
fn collision_start_intersect(
@@ -1664,7 +1676,7 @@ fn collision_start_intersect(
None=>(),
}
}
move_state.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state);
move_state.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
run_teleport_behaviour(intersect.convex_mesh_id.model_id.into(),attr.general.wormhole.as_ref(),mode,move_state,body,touching,run,mode_state,models,hitbox_mesh,bvh,style,camera,input_state,time);
}
@@ -1692,11 +1704,10 @@ fn collision_end_contact(
move_state.set_move_state(MoveState::Air,body,touching,models,hitbox_mesh,style,camera,input_state);
}else{
// stopped touching something else while walking
move_state.update_walk_target(body,touching,models,hitbox_mesh,style,camera,input_state);
move_state.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state);
move_state.apply_enum_and_input_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
},
// not walking, but stopped touching something
None=>move_state.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state),
None=>move_state.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state),
}
}
fn collision_end_intersect(
@@ -1715,7 +1726,7 @@ fn collision_end_intersect(
time:Time,
){
touching.remove_intersect(convex_mesh_id);
move_state.update_fly_velocity(body,touching,models,hitbox_mesh,style,camera,input_state);
move_state.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
if let Some(mode)=mode{
let zone=mode.get_zone(convex_mesh_id.model_id.into());
match zone{
@@ -1788,10 +1799,9 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
let control_dir=state.style.get_control_dir(masked_controls);
if control_dir!=vec3::zero(){
// manually advance time
let extrapolated_body=state.body.with_acceleration(state.acceleration(data)).extrapolated_body(state.time);
state.body=state.body.with_acceleration(state.acceleration(data)).extrapolated_body(state.time);
let camera_mat=state.camera.simulate_move_rotation_y(state.input_state.lerp_delta(state.time).x);
if let Some(ticked_velocity)=strafe_settings.tick_velocity(extrapolated_body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE).divide().wrap_1()){
state.body=extrapolated_body;
if let Some(ticked_velocity)=strafe_settings.tick_velocity(state.body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE).divide().wrap_1()){
//this is wrong but will work ig
//need to note which push planes activate in push solve and keep those
state.cull_velocity(data,ticked_velocity);
@@ -1948,8 +1958,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
},
}
if b_refresh_walk_target{
state.move_state.update_walk_target(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,&state.style,&state.camera,&state.input_state);
state.move_state.update_fly_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,&state.style,&state.camera,&state.input_state);
state.apply_input_and_body(data);
state.cull_velocity(data,state.body.velocity);
//also check if accelerating away from surface
}

View File

@@ -57,7 +57,7 @@ pub enum SessionPlaybackInstruction{
}
pub struct FrameState{
pub trajectory:physics::Trajectory,
pub trajectory:physics::Trajectory<'static>,
pub camera:physics::PhysicsCamera,
pub time:PhysicsTime,
}

View File

@@ -1,9 +0,0 @@
[package]
name = "dag"
version = "0.1.0"
edition = "2024"
[dependencies]
[lints]
workspace = true

View File

@@ -1,16 +0,0 @@
// typestate dag with lazy just-in-time execution
struct States<S1,S2>(S1,S2);
struct Known<T>(T);
struct NeedsRecalculate;
fn a(){
// Construct a DAG such that S2 depends on S1
// let dag=Dag:new();
// Initial state
let state=States(Known(1),Known(1));
// set_state1 changes S2 to NeedsRecalculate
state.set_state1(2);
// get_state2 calculates S2
let s2=state.get_state2();
}