refactor type safety for modes data normalization

This commit is contained in:
Quaternions 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/src
common/src
rbx_loader/src
snf/src

@ -982,10 +982,7 @@ impl PhysicsContext<'_>{
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){
let mut modes=map.modes.clone();
for mode in &mut modes.modes{
mode.denormalize_data();
}
let mut modes=map.modes.clone().denormalize();
let mut used_contact_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::mesh::Meshes;
use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
use strafesnet_common::gameplay_modes::{NormalizedMode,NormalizedModes,Mode,Stage};
use crate::valve_transform;
@ -268,15 +269,15 @@ pub fn convert<'a>(
color:glam::Vec4::W,
});
let first_stage=strafesnet_common::gameplay_modes::Stage::empty(model_id);
let main_mode=strafesnet_common::gameplay_modes::Mode::new(
let first_stage=Stage::empty(model_id);
let main_mode=Mode::new(
strafesnet_common::gameplay_style::StyleModifiers::source_bhop(),
model_id,
std::collections::HashMap::new(),
vec![first_stage],
std::collections::HashMap::new(),
);
modes_list.push(main_mode);
modes_list.push(NormalizedMode::new(main_mode));
}
PartialMap1{
@ -284,7 +285,7 @@ pub fn convert<'a>(
world_meshes,
prop_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>,
world_meshes:Vec<model::Mesh>,
world_models:Vec<model::Model>,
modes:strafesnet_common::gameplay_modes::Modes,
modes:NormalizedModes,
}
impl PartialMap1{
pub fn add_prop_meshes<'a>(
@ -317,7 +318,7 @@ pub struct PartialMap2{
prop_models:Vec<model::Model>,
world_meshes:Vec<model::Mesh>,
world_models:Vec<model::Model>,
modes:strafesnet_common::gameplay_modes::Modes,
modes:NormalizedModes,
}
impl PartialMap2{
pub fn add_render_configs_and_textures(

@ -214,19 +214,32 @@ impl Mode{
pub fn get_element(&self,model_id:ModelId)->Option<&StageElement>{
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
pub fn denormalize_data(&mut self){
pub fn denormalize(self)->Mode{
let NormalizedMode(mut mode)=self;
//expand and index normalized data
self.zones.insert(self.start,Zone::Start);
for (stage_id,stage) in self.stages.iter().enumerate(){
self.elements.insert(stage.spawn,StageElement{
mode.zones.insert(mode.start,Zone::Start);
for (stage_id,stage) in mode.stages.iter().enumerate(){
mode.elements.insert(stage.spawn,StageElement{
stage_id:StageId(stage_id as u32),
force:false,
behaviour:StageElementBehaviour::SpawnAt,
jump_limit:None,
});
for (_,&model) in &stage.ordered_checkpoints{
self.elements.insert(model,StageElement{
mode.elements.insert(model,StageElement{
stage_id:StageId(stage_id as u32),
force:false,
behaviour:StageElementBehaviour::Checkpoint,
@ -234,7 +247,7 @@ impl Mode{
});
}
for &model in &stage.unordered_checkpoints{
self.elements.insert(model,StageElement{
mode.elements.insert(model,StageElement{
stage_id:StageId(stage_id as u32),
force:false,
behaviour:StageElementBehaviour::Checkpoint,
@ -242,12 +255,13 @@ impl Mode{
});
}
}
mode
}
}
#[derive(Default,Clone)]
pub struct Modes{
pub modes:Vec<Mode>,
modes:Vec<Mode>,
}
impl Modes{
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)]
pub struct StageUpdate{
@ -352,7 +391,7 @@ pub struct ModesBuilder{
stage_updates:Vec<(ModeId,StageId,StageUpdate)>,
}
impl ModesBuilder{
pub fn build(mut self)->Modes{
pub fn build_normalized(mut self)->NormalizedModes{
//collect modes and stages into contiguous arrays
let mut unique_modes:Vec<(ModeId,Mode)>
=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){
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
//TODO: use snf::map::Region to update the data in physics and graphics instead of this
pub struct CompleteMap{
pub modes:gameplay_modes::Modes,
pub modes:gameplay_modes::NormalizedModes,
pub attributes:Vec<gameplay_attributes::CollisionAttributes>,
pub meshes:Vec<model::Mesh>,
pub models:Vec<model::Model>,

@ -4,7 +4,7 @@ use crate::primitives;
use strafesnet_common::aabb::Aabb;
use strafesnet_common::map;
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_attributes as attr;
use strafesnet_common::integer::{self,vec3,Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3};
@ -922,7 +922,7 @@ impl PartialMap1<'_>{
PartialMap2{
meshes:self.primitive_meshes,
models,
modes:modes_builder.build(),
modes:modes_builder.build_normalized(),
attributes:unique_attributes,
}
}
@ -931,7 +931,7 @@ impl PartialMap1<'_>{
pub struct PartialMap2{
meshes:Vec<model::Mesh>,
models:Vec<model::Model>,
modes:Modes,
modes:NormalizedModes,
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
}
impl PartialMap2{

@ -138,7 +138,7 @@ struct MapHeader{
//#[br(count=num_resources_external)]
//external_resources:Vec<ResourceExternalHeader>,
#[br(count=num_modes)]
modes:Vec<newtypes::gameplay_modes::Mode>,
modes:Vec<newtypes::gameplay_modes::NormalizedMode>,
#[br(count=num_attributes)]
attributes:Vec<newtypes::gameplay_attributes::CollisionAttributes>,
#[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>{
file:crate::file::File<R>,
//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
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
//this is every possible render configuration... shaders and such... need streaming
@ -223,7 +223,7 @@ impl<R:BinReaderExt> StreamableMap<R>{
}
Ok(Self{
file,
modes:strafesnet_common::gameplay_modes::Modes::new(modes),
modes:strafesnet_common::gameplay_modes::NormalizedModes::new(modes),
attributes,
render_configs,
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_resource_blocks:resource_blocks.len() as u32,
//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_render_configs:map.render_configs.len() as u32,
spacial_blocks,
resource_blocks,
//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(),
render_configs:map.render_configs.into_iter().map(Into::into).collect(),
};

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