refactor type safety for modes data normalization

This commit is contained in:
2025-02-28 12:38:00 -08:00
parent 2c87cb71df
commit 82840fa6cb
7 changed files with 73 additions and 36 deletions
engine/physics/src
lib
bsp_loader
common
rbx_loader
snf

@ -982,10 +982,7 @@ impl PhysicsContext<'_>{
impl PhysicsData{ 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){
let mut modes=map.modes.clone(); let mut modes=map.modes.clone().denormalize();
for mode in &mut modes.modes{
mode.denormalize_data();
}
let mut used_contact_attributes=Vec::new(); let mut used_contact_attributes=Vec::new();
let mut used_intersect_attributes=Vec::new(); let mut used_intersect_attributes=Vec::new();

@ -6,6 +6,7 @@ use strafesnet_common::{map,model,integer,gameplay_attributes};
use strafesnet_deferred_loader::deferred_loader::{MeshDeferredLoader,RenderConfigDeferredLoader}; use strafesnet_deferred_loader::deferred_loader::{MeshDeferredLoader,RenderConfigDeferredLoader};
use strafesnet_deferred_loader::mesh::Meshes; use strafesnet_deferred_loader::mesh::Meshes;
use strafesnet_deferred_loader::texture::{RenderConfigs,Texture}; use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
use strafesnet_common::gameplay_modes::{NormalizedMode,NormalizedModes,Mode,Stage};
use crate::valve_transform; use crate::valve_transform;
@ -268,15 +269,15 @@ pub fn convert<'a>(
color:glam::Vec4::W, color:glam::Vec4::W,
}); });
let first_stage=strafesnet_common::gameplay_modes::Stage::empty(model_id); let first_stage=Stage::empty(model_id);
let main_mode=strafesnet_common::gameplay_modes::Mode::new( let main_mode=Mode::new(
strafesnet_common::gameplay_style::StyleModifiers::source_bhop(), strafesnet_common::gameplay_style::StyleModifiers::source_bhop(),
model_id, model_id,
std::collections::HashMap::new(), std::collections::HashMap::new(),
vec![first_stage], vec![first_stage],
std::collections::HashMap::new(), std::collections::HashMap::new(),
); );
modes_list.push(main_mode); modes_list.push(NormalizedMode::new(main_mode));
} }
PartialMap1{ PartialMap1{
@ -284,7 +285,7 @@ pub fn convert<'a>(
world_meshes, world_meshes,
prop_models, prop_models,
world_models, world_models,
modes:strafesnet_common::gameplay_modes::Modes::new(modes_list), modes:NormalizedModes::new(modes_list),
} }
} }
@ -294,7 +295,7 @@ pub struct PartialMap1{
prop_models:Vec<model::Model>, prop_models:Vec<model::Model>,
world_meshes:Vec<model::Mesh>, world_meshes:Vec<model::Mesh>,
world_models:Vec<model::Model>, world_models:Vec<model::Model>,
modes:strafesnet_common::gameplay_modes::Modes, modes:NormalizedModes,
} }
impl PartialMap1{ impl PartialMap1{
pub fn add_prop_meshes<'a>( pub fn add_prop_meshes<'a>(
@ -317,7 +318,7 @@ pub struct PartialMap2{
prop_models:Vec<model::Model>, prop_models:Vec<model::Model>,
world_meshes:Vec<model::Mesh>, world_meshes:Vec<model::Mesh>,
world_models:Vec<model::Model>, world_models:Vec<model::Model>,
modes:strafesnet_common::gameplay_modes::Modes, modes:NormalizedModes,
} }
impl PartialMap2{ impl PartialMap2{
pub fn add_render_configs_and_textures( pub fn add_render_configs_and_textures(

@ -214,19 +214,32 @@ impl Mode{
pub fn get_element(&self,model_id:ModelId)->Option<&StageElement>{ pub fn get_element(&self,model_id:ModelId)->Option<&StageElement>{
self.elements.get(&model_id) self.elements.get(&model_id)
} }
}
#[derive(Clone)]
pub struct NormalizedMode(Mode);
impl NormalizedMode{
pub fn new(mode:Mode)->Self{
Self(mode)
}
pub fn into_inner(self)->Mode{
let Self(mode)=self;
mode
}
//TODO: put this in the SNF //TODO: put this in the SNF
pub fn denormalize_data(&mut self){ pub fn denormalize(self)->Mode{
let NormalizedMode(mut mode)=self;
//expand and index normalized data //expand and index normalized data
self.zones.insert(self.start,Zone::Start); mode.zones.insert(mode.start,Zone::Start);
for (stage_id,stage) in self.stages.iter().enumerate(){ for (stage_id,stage) in mode.stages.iter().enumerate(){
self.elements.insert(stage.spawn,StageElement{ mode.elements.insert(stage.spawn,StageElement{
stage_id:StageId(stage_id as u32), stage_id:StageId(stage_id as u32),
force:false, force:false,
behaviour:StageElementBehaviour::SpawnAt, behaviour:StageElementBehaviour::SpawnAt,
jump_limit:None, jump_limit:None,
}); });
for (_,&model) in &stage.ordered_checkpoints{ for (_,&model) in &stage.ordered_checkpoints{
self.elements.insert(model,StageElement{ mode.elements.insert(model,StageElement{
stage_id:StageId(stage_id as u32), stage_id:StageId(stage_id as u32),
force:false, force:false,
behaviour:StageElementBehaviour::Checkpoint, behaviour:StageElementBehaviour::Checkpoint,
@ -234,7 +247,7 @@ impl Mode{
}); });
} }
for &model in &stage.unordered_checkpoints{ for &model in &stage.unordered_checkpoints{
self.elements.insert(model,StageElement{ mode.elements.insert(model,StageElement{
stage_id:StageId(stage_id as u32), stage_id:StageId(stage_id as u32),
force:false, force:false,
behaviour:StageElementBehaviour::Checkpoint, behaviour:StageElementBehaviour::Checkpoint,
@ -242,12 +255,13 @@ impl Mode{
}); });
} }
} }
mode
} }
} }
#[derive(Default,Clone)] #[derive(Default,Clone)]
pub struct Modes{ pub struct Modes{
pub modes:Vec<Mode>, modes:Vec<Mode>,
} }
impl Modes{ impl Modes{
pub const fn new(modes:Vec<Mode>)->Self{ pub const fn new(modes:Vec<Mode>)->Self{
@ -266,6 +280,31 @@ impl Modes{
} }
} }
#[derive(Clone)]
pub struct NormalizedModes{
modes:Vec<NormalizedMode>,
}
impl NormalizedModes{
pub fn new(modes:Vec<NormalizedMode>)->Self{
Self{modes}
}
pub fn len(&self)->usize{
self.modes.len()
}
pub fn denormalize(self)->Modes{
Modes{
modes:self.modes.into_iter().map(NormalizedMode::denormalize).collect(),
}
}
}
impl IntoIterator for NormalizedModes{
type Item=<Vec<NormalizedMode> as IntoIterator>::Item;
type IntoIter=<Vec<NormalizedMode> as IntoIterator>::IntoIter;
fn into_iter(self)->Self::IntoIter{
self.modes.into_iter()
}
}
#[derive(Default)] #[derive(Default)]
pub struct StageUpdate{ pub struct StageUpdate{
@ -352,7 +391,7 @@ pub struct ModesBuilder{
stage_updates:Vec<(ModeId,StageId,StageUpdate)>, stage_updates:Vec<(ModeId,StageId,StageUpdate)>,
} }
impl ModesBuilder{ impl ModesBuilder{
pub fn build(mut self)->Modes{ pub fn build_normalized(mut self)->NormalizedModes{
//collect modes and stages into contiguous arrays //collect modes and stages into contiguous arrays
let mut unique_modes:Vec<(ModeId,Mode)> let mut unique_modes:Vec<(ModeId,Mode)>
=self.modes.into_iter().collect(); =self.modes.into_iter().collect();
@ -412,7 +451,7 @@ impl ModesBuilder{
} }
} }
} }
Modes::new(modes.into_iter().map(|mode_builder|mode_builder.mode).collect()) NormalizedModes::new(modes.into_iter().map(|mode_builder|NormalizedMode(mode_builder.mode)).collect())
} }
pub fn insert_mode(&mut self,mode_id:ModeId,mode:Mode){ pub fn insert_mode(&mut self,mode_id:ModeId,mode:Mode){
assert!(self.modes.insert(mode_id,mode).is_none(),"Cannot replace existing mode"); assert!(self.modes.insert(mode_id,mode).is_none(),"Cannot replace existing mode");

@ -4,7 +4,7 @@ use crate::gameplay_attributes;
//this is a temporary struct to try to get the code running again //this is a temporary struct to try to get the code running again
//TODO: use snf::map::Region to update the data in physics and graphics instead of this //TODO: use snf::map::Region to update the data in physics and graphics instead of this
pub struct CompleteMap{ pub struct CompleteMap{
pub modes:gameplay_modes::Modes, pub modes:gameplay_modes::NormalizedModes,
pub attributes:Vec<gameplay_attributes::CollisionAttributes>, pub attributes:Vec<gameplay_attributes::CollisionAttributes>,
pub meshes:Vec<model::Mesh>, pub meshes:Vec<model::Mesh>,
pub models:Vec<model::Model>, pub models:Vec<model::Model>,

@ -4,7 +4,7 @@ use crate::primitives;
use strafesnet_common::aabb::Aabb; use strafesnet_common::aabb::Aabb;
use strafesnet_common::map; use strafesnet_common::map;
use strafesnet_common::model; use strafesnet_common::model;
use strafesnet_common::gameplay_modes::{Mode,ModeId,ModeUpdate,Modes,ModesBuilder,Stage,StageElement,StageElementBehaviour,StageId,Zone}; use strafesnet_common::gameplay_modes::{NormalizedModes,Mode,ModeId,ModeUpdate,ModesBuilder,Stage,StageElement,StageElementBehaviour,StageId,Zone};
use strafesnet_common::gameplay_style; use strafesnet_common::gameplay_style;
use strafesnet_common::gameplay_attributes as attr; use strafesnet_common::gameplay_attributes as attr;
use strafesnet_common::integer::{self,vec3,Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3}; use strafesnet_common::integer::{self,vec3,Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3};
@ -922,7 +922,7 @@ impl PartialMap1<'_>{
PartialMap2{ PartialMap2{
meshes:self.primitive_meshes, meshes:self.primitive_meshes,
models, models,
modes:modes_builder.build(), modes:modes_builder.build_normalized(),
attributes:unique_attributes, attributes:unique_attributes,
} }
} }
@ -931,7 +931,7 @@ impl PartialMap1<'_>{
pub struct PartialMap2{ pub struct PartialMap2{
meshes:Vec<model::Mesh>, meshes:Vec<model::Mesh>,
models:Vec<model::Model>, models:Vec<model::Model>,
modes:Modes, modes:NormalizedModes,
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>, attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
} }
impl PartialMap2{ impl PartialMap2{

@ -138,7 +138,7 @@ struct MapHeader{
//#[br(count=num_resources_external)] //#[br(count=num_resources_external)]
//external_resources:Vec<ResourceExternalHeader>, //external_resources:Vec<ResourceExternalHeader>,
#[br(count=num_modes)] #[br(count=num_modes)]
modes:Vec<newtypes::gameplay_modes::Mode>, modes:Vec<newtypes::gameplay_modes::NormalizedMode>,
#[br(count=num_attributes)] #[br(count=num_attributes)]
attributes:Vec<newtypes::gameplay_attributes::CollisionAttributes>, attributes:Vec<newtypes::gameplay_attributes::CollisionAttributes>,
#[br(count=num_render_configs)] #[br(count=num_render_configs)]
@ -181,7 +181,7 @@ fn read_texture<R:BinReaderExt>(file:&mut crate::file::File<R>,block_id:BlockId)
pub struct StreamableMap<R:BinReaderExt>{ pub struct StreamableMap<R:BinReaderExt>{
file:crate::file::File<R>, file:crate::file::File<R>,
//this includes every platform... move the unconstrained datas to their appropriate data block? //this includes every platform... move the unconstrained datas to their appropriate data block?
modes:gameplay_modes::Modes, modes:gameplay_modes::NormalizedModes,
//this is every possible attribute... need some sort of streaming system //this is every possible attribute... need some sort of streaming system
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>, attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
//this is every possible render configuration... shaders and such... need streaming //this is every possible render configuration... shaders and such... need streaming
@ -223,7 +223,7 @@ impl<R:BinReaderExt> StreamableMap<R>{
} }
Ok(Self{ Ok(Self{
file, file,
modes:strafesnet_common::gameplay_modes::Modes::new(modes), modes:strafesnet_common::gameplay_modes::NormalizedModes::new(modes),
attributes, attributes,
render_configs, render_configs,
bvh:strafesnet_common::bvh::generate_bvh(bvh), bvh:strafesnet_common::bvh::generate_bvh(bvh),
@ -430,13 +430,13 @@ pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::Comple
num_spacial_blocks:spacial_blocks.len() as u32, num_spacial_blocks:spacial_blocks.len() as u32,
num_resource_blocks:resource_blocks.len() as u32, num_resource_blocks:resource_blocks.len() as u32,
//num_resources_external:0, //num_resources_external:0,
num_modes:map.modes.modes.len() as u32, num_modes:map.modes.len() as u32,
num_attributes:map.attributes.len() as u32, num_attributes:map.attributes.len() as u32,
num_render_configs:map.render_configs.len() as u32, num_render_configs:map.render_configs.len() as u32,
spacial_blocks, spacial_blocks,
resource_blocks, resource_blocks,
//external_resources:Vec::new(), //external_resources:Vec::new(),
modes:map.modes.modes.into_iter().map(Into::into).collect(), modes:map.modes.into_iter().map(Into::into).collect(),
attributes:map.attributes.into_iter().map(Into::into).collect(), attributes:map.attributes.into_iter().map(Into::into).collect(),
render_configs:map.render_configs.into_iter().map(Into::into).collect(), render_configs:map.render_configs.into_iter().map(Into::into).collect(),
}; };

@ -157,7 +157,7 @@ pub struct ModeHeader{
} }
#[binrw::binrw] #[binrw::binrw]
#[brw(little)] #[brw(little)]
pub struct Mode{ pub struct NormalizedMode{
pub header:ModeHeader, pub header:ModeHeader,
pub style:super::gameplay_style::StyleModifiers, pub style:super::gameplay_style::StyleModifiers,
pub start:u32, pub start:u32,
@ -179,10 +179,10 @@ impl std::fmt::Display for ModeError{
} }
} }
impl std::error::Error for ModeError{} impl std::error::Error for ModeError{}
impl TryInto<strafesnet_common::gameplay_modes::Mode> for Mode{ impl TryInto<strafesnet_common::gameplay_modes::NormalizedMode> for NormalizedMode{
type Error=ModeError; type Error=ModeError;
fn try_into(self)->Result<strafesnet_common::gameplay_modes::Mode,Self::Error>{ fn try_into(self)->Result<strafesnet_common::gameplay_modes::NormalizedMode,Self::Error>{
Ok(strafesnet_common::gameplay_modes::Mode::new( Ok(strafesnet_common::gameplay_modes::NormalizedMode::new(strafesnet_common::gameplay_modes::Mode::new(
self.style.try_into().map_err(ModeError::StyleModifier)?, self.style.try_into().map_err(ModeError::StyleModifier)?,
strafesnet_common::model::ModelId::new(self.start), strafesnet_common::model::ModelId::new(self.start),
self.zones.into_iter().map(|(model_id,zone)| self.zones.into_iter().map(|(model_id,zone)|
@ -192,12 +192,12 @@ impl TryInto<strafesnet_common::gameplay_modes::Mode> for Mode{
self.elements.into_iter().map(|(model_id,stage_element)| self.elements.into_iter().map(|(model_id,stage_element)|
Ok((strafesnet_common::model::ModelId::new(model_id),stage_element.try_into()?)) Ok((strafesnet_common::model::ModelId::new(model_id),stage_element.try_into()?))
).collect::<Result<_,_>>().map_err(ModeError::StageElement)?, ).collect::<Result<_,_>>().map_err(ModeError::StageElement)?,
)) )))
} }
} }
impl From<strafesnet_common::gameplay_modes::Mode> for Mode{ impl From<strafesnet_common::gameplay_modes::NormalizedMode> for NormalizedMode{
fn from(value:strafesnet_common::gameplay_modes::Mode)->Self{ fn from(value:strafesnet_common::gameplay_modes::NormalizedMode)->Self{
let (style,start,zones,stages,elements)=value.into_inner(); let (style,start,zones,stages,elements)=value.into_inner().into_inner();
Self{ Self{
header:ModeHeader{ header:ModeHeader{
zones:zones.len() as u32, zones:zones.len() as u32,