refactor physics to use shared context for multiple simulations
This commit is contained in:
parent
28499800cb
commit
2faa61225f
@ -829,17 +829,7 @@ pub struct PhysicsState{
|
|||||||
//a start zone. If you change mode, a new run is created.
|
//a start zone. If you change mode, a new run is created.
|
||||||
run:run::Run,
|
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{
|
impl Default for PhysicsState{
|
||||||
fn default()->Self{
|
fn default()->Self{
|
||||||
Self{
|
Self{
|
||||||
@ -856,19 +846,18 @@ impl Default for PhysicsState{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for PhysicsData{
|
|
||||||
fn default()->Self{
|
|
||||||
Self{
|
|
||||||
bvh:bvh::BvhNode::default(),
|
|
||||||
models:Default::default(),
|
|
||||||
modes:Default::default(),
|
|
||||||
hitbox_mesh:StyleModifiers::default().calculate_mesh(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PhysicsState{
|
impl PhysicsState{
|
||||||
fn clear(&mut self){
|
pub fn camera_body(&self)->Body{
|
||||||
|
Body{
|
||||||
|
position:self.body.position+self.style.camera_offset,
|
||||||
|
..self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn camera(&self)->PhysicsCamera{
|
||||||
|
self.camera
|
||||||
|
}
|
||||||
|
pub fn clear(&mut self){
|
||||||
self.touching.clear();
|
self.touching.clear();
|
||||||
}
|
}
|
||||||
fn reset_to_default(&mut self){
|
fn reset_to_default(&mut self){
|
||||||
@ -917,46 +906,67 @@ impl PhysicsState{
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
// shared geometry for simulations
|
||||||
#[derive(Default)]
|
pub struct PhysicsData{
|
||||||
pub struct PhysicsContext{
|
//permanent map data
|
||||||
state:PhysicsState,//this captures the entire state of the physics.
|
bvh:bvh::BvhNode<ConvexMeshId>,
|
||||||
data:PhysicsData,//data currently loaded into memory which is needded for physics to run, but is not part of the state.
|
//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.
|
||||||
}
|
}
|
||||||
// the physics consumes both Instruction and PhysicsInternalInstruction,
|
// the physics consumes both Instruction and PhysicsInternalInstruction,
|
||||||
// but can only emit PhysicsInternalInstruction
|
// but can only emit PhysicsInternalInstruction
|
||||||
impl InstructionConsumer<InternalInstruction> for PhysicsContext{
|
impl InstructionConsumer<InternalInstruction> for PhysicsContext<'_>{
|
||||||
type TimeInner=TimeInner;
|
type TimeInner=TimeInner;
|
||||||
fn process_instruction(&mut self,ins:TimedInstruction<InternalInstruction,TimeInner>){
|
fn process_instruction(&mut self,ins:TimedInstruction<InternalInstruction,TimeInner>){
|
||||||
atomic_internal_instruction(&mut self.state,&self.data,ins)
|
atomic_internal_instruction(&mut self.state,&self.data,ins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InstructionConsumer<Instruction> for PhysicsContext{
|
impl InstructionConsumer<Instruction> for PhysicsContext<'_>{
|
||||||
type TimeInner=TimeInner;
|
type TimeInner=TimeInner;
|
||||||
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,TimeInner>){
|
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,TimeInner>){
|
||||||
atomic_input_instruction(&mut self.state,&self.data,ins)
|
atomic_input_instruction(&mut self.state,&self.data,ins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InstructionEmitter<InternalInstruction> for PhysicsContext{
|
impl InstructionEmitter<InternalInstruction> for PhysicsContext<'_>{
|
||||||
type TimeInner=TimeInner;
|
type TimeInner=TimeInner;
|
||||||
//this little next instruction function could cache its return value and invalidate the cached value by watching the State.
|
//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>>{
|
fn next_instruction(&self,time_limit:Time)->Option<TimedInstruction<InternalInstruction,TimeInner>>{
|
||||||
next_instruction_internal(&self.state,&self.data,time_limit)
|
next_instruction_internal(&self.state,&self.data,time_limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PhysicsContext{
|
impl PhysicsContext<'_>{
|
||||||
pub fn camera_body(&self)->Body{
|
pub fn run_input_instruction(
|
||||||
Body{
|
state:&mut PhysicsState,
|
||||||
position:self.state.body.position+self.state.style.camera_offset,
|
data:&PhysicsData,
|
||||||
..self.state.body
|
instruction:TimedInstruction<Instruction,TimeInner>
|
||||||
}
|
){
|
||||||
}
|
let mut context=PhysicsContext{state,data};
|
||||||
pub const fn camera(&self)->PhysicsCamera{
|
context.process_exhaustive(instruction.time);
|
||||||
self.state.camera
|
context.process_instruction(instruction);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
impl PhysicsData{
|
||||||
/// use with caution, this is the only non-instruction way to mess with physics
|
/// use with caution, this is the only non-instruction way to mess with physics
|
||||||
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
||||||
self.state.clear();
|
|
||||||
let mut modes=map.modes.clone();
|
let mut modes=map.modes.clone();
|
||||||
for mode in &mut modes.modes{
|
for mode in &mut modes.modes{
|
||||||
mode.denormalize_data();
|
mode.denormalize_data();
|
||||||
@ -1087,17 +1097,12 @@ impl PhysicsContext{
|
|||||||
(IntersectAttributesId::new(attr_id as u32),attr)
|
(IntersectAttributesId::new(attr_id as u32),attr)
|
||||||
).collect(),
|
).collect(),
|
||||||
};
|
};
|
||||||
self.data.bvh=bvh;
|
self.bvh=bvh;
|
||||||
self.data.models=models;
|
self.models=models;
|
||||||
self.data.modes=modes;
|
self.modes=modes;
|
||||||
//hitbox_mesh is unchanged
|
//hitbox_mesh is unchanged
|
||||||
println!("Physics Objects: {}",model_count);
|
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
|
//this is the one who asks
|
||||||
|
@ -21,7 +21,7 @@ pub fn new<'a>(
|
|||||||
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,
|
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,
|
||||||
user_settings:crate::settings::UserSettings,
|
user_settings:crate::settings::UserSettings,
|
||||||
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTimeInner>>{
|
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTimeInner>>{
|
||||||
let physics=crate::physics::PhysicsContext::default();
|
let physics=crate::physics::PhysicsState::default();
|
||||||
let timer=Timer::unpaused(SessionTime::ZERO,PhysicsTime::ZERO);
|
let timer=Timer::unpaused(SessionTime::ZERO,PhysicsTime::ZERO);
|
||||||
let simulation=Simulation::new(timer,physics);
|
let simulation=Simulation::new(timer,physics);
|
||||||
let mut session=Session::new(
|
let mut session=Session::new(
|
||||||
|
@ -14,6 +14,7 @@ use strafesnet_common::timer::{Scaled,Timer};
|
|||||||
use strafesnet_common::session::{TimeInner as SessionTimeInner,Time as SessionTime};
|
use strafesnet_common::session::{TimeInner as SessionTimeInner,Time as SessionTime};
|
||||||
|
|
||||||
use crate::mouse_interpolator::{MouseInterpolator,StepInstruction,Instruction as MouseInterpolatorInstruction};
|
use crate::mouse_interpolator::{MouseInterpolator,StepInstruction,Instruction as MouseInterpolatorInstruction};
|
||||||
|
use crate::physics::{PhysicsContext,PhysicsData};
|
||||||
use crate::settings::UserSettings;
|
use crate::settings::UserSettings;
|
||||||
|
|
||||||
pub enum Instruction<'a>{
|
pub enum Instruction<'a>{
|
||||||
@ -60,12 +61,12 @@ pub struct FrameState{
|
|||||||
|
|
||||||
pub struct Simulation{
|
pub struct Simulation{
|
||||||
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
||||||
physics:crate::physics::PhysicsContext,
|
physics:crate::physics::PhysicsState,
|
||||||
}
|
}
|
||||||
impl Simulation{
|
impl Simulation{
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
||||||
physics:crate::physics::PhysicsContext,
|
physics:crate::physics::PhysicsState,
|
||||||
)->Self{
|
)->Self{
|
||||||
Self{
|
Self{
|
||||||
timer,
|
timer,
|
||||||
@ -106,12 +107,12 @@ impl Replay{
|
|||||||
simulation,
|
simulation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn advance(&mut self,time_limit:SessionTime){
|
pub fn advance(&mut self,physics_data:&PhysicsData,time_limit:SessionTime){
|
||||||
let mut time=self.simulation.timer.time(time_limit);
|
let mut time=self.simulation.timer.time(time_limit);
|
||||||
loop{
|
loop{
|
||||||
if let Some(ins)=self.recording.instructions.get(self.last_instruction_id){
|
if let Some(ins)=self.recording.instructions.get(self.last_instruction_id){
|
||||||
if ins.time<time{
|
if ins.time<time{
|
||||||
self.simulation.physics.run_input_instruction(ins.clone());
|
PhysicsContext::run_input_instruction(&mut self.simulation.physics,physics_data,ins.clone());
|
||||||
self.last_instruction_id+=1;
|
self.last_instruction_id+=1;
|
||||||
}else{
|
}else{
|
||||||
break;
|
break;
|
||||||
@ -144,6 +145,7 @@ pub struct Session{
|
|||||||
mouse_interpolator:crate::mouse_interpolator::MouseInterpolator,
|
mouse_interpolator:crate::mouse_interpolator::MouseInterpolator,
|
||||||
view_state:ViewState,
|
view_state:ViewState,
|
||||||
//gui:GuiState
|
//gui:GuiState
|
||||||
|
geometry_shared:crate::physics::PhysicsData,
|
||||||
simulation:Simulation,
|
simulation:Simulation,
|
||||||
// below fields not included in lite session
|
// below fields not included in lite session
|
||||||
recording:Recording,
|
recording:Recording,
|
||||||
@ -158,6 +160,7 @@ impl Session{
|
|||||||
Self{
|
Self{
|
||||||
user_settings,
|
user_settings,
|
||||||
mouse_interpolator:MouseInterpolator::new(),
|
mouse_interpolator:MouseInterpolator::new(),
|
||||||
|
geometry_shared:Default::default(),
|
||||||
simulation,
|
simulation,
|
||||||
view_state:ViewState::Play,
|
view_state:ViewState::Play,
|
||||||
recording:Default::default(),
|
recording:Default::default(),
|
||||||
@ -168,7 +171,8 @@ impl Session{
|
|||||||
self.recording.clear();
|
self.recording.clear();
|
||||||
}
|
}
|
||||||
fn change_map(&mut self,map:&strafesnet_common::map::CompleteMap){
|
fn change_map(&mut self,map:&strafesnet_common::map::CompleteMap){
|
||||||
self.simulation.physics.generate_models(map);
|
self.simulation.physics.clear();
|
||||||
|
self.geometry_shared.generate_models(map);
|
||||||
}
|
}
|
||||||
pub fn get_frame_state(&self,time:SessionTime)->Option<FrameState>{
|
pub fn get_frame_state(&self,time:SessionTime)->Option<FrameState>{
|
||||||
match &self.view_state{
|
match &self.view_state{
|
||||||
@ -339,7 +343,7 @@ impl InstructionConsumer<Instruction<'_>> for Session{
|
|||||||
// this just refreshes the replays
|
// this just refreshes the replays
|
||||||
for replay in self.replays.values_mut(){
|
for replay in self.replays.values_mut(){
|
||||||
// TODO: filter idles from recording, inject new idles in real time
|
// TODO: filter idles from recording, inject new idles in real time
|
||||||
replay.advance(ins.time);
|
replay.advance(&self.geometry_shared,ins.time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -355,7 +359,7 @@ impl InstructionConsumer<StepInstruction> for Session{
|
|||||||
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins.set_time(time)){
|
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins.set_time(time)){
|
||||||
//record
|
//record
|
||||||
self.recording.instructions.push(instruction.clone());
|
self.recording.instructions.push(instruction.clone());
|
||||||
self.simulation.physics.run_input_instruction(instruction);
|
PhysicsContext::run_input_instruction(&mut self.simulation.physics,&self.geometry_shared,instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user