data structure rewrite

This commit is contained in:
Quaternions 2024-02-01 00:04:07 -08:00
parent f38d990a54
commit 47cdea0c8a
11 changed files with 535 additions and 127 deletions

46
Cargo.lock generated
View File

@ -8,9 +8,55 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
[[package]]
name = "id"
version = "0.1.0"
source = "git+https://git.itzana.me/Quaternions/id?rev=1f710976cc786c8853dab73d6e1cee53158deeb0#1f710976cc786c8853dab73d6e1cee53158deeb0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "strafesnet_common" name = "strafesnet_common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"glam", "glam",
"id",
] ]
[[package]]
name = "syn"
version = "2.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

View File

@ -7,3 +7,4 @@ edition = "2021"
[dependencies] [dependencies]
glam = "0.25.0" glam = "0.25.0"
id = { git = "https://git.itzana.me/Quaternions/id", rev = "1f710976cc786c8853dab73d6e1cee53158deeb0" }

View File

@ -9,23 +9,24 @@ use crate::aabb::Aabb;
//start with bisection into octrees because a bad bvh is still 1000x better than no bvh //start with bisection into octrees because a bad bvh is still 1000x better than no bvh
//sort the centerpoints on each axis (3 lists) //sort the centerpoints on each axis (3 lists)
//bv is put into octant based on whether it is upper or lower in each list //bv is put into octant based on whether it is upper or lower in each list
enum BvhNodeContent{
Branch(Vec<BvhNode>), enum BvhNodeContent<T>{
Leaf(usize), Branch(Vec<BvhNode<T>>),
Leaf(T),
} }
impl Default for BvhNodeContent{ impl<T> Default for BvhNodeContent<T>{
fn default()->Self{ fn default()->Self{
Self::Branch(Vec::new()) Self::Branch(Vec::new())
} }
} }
#[derive(Default)] #[derive(Default)]
pub struct BvhNode{ pub struct BvhNode<T>{
content:BvhNodeContent, content:BvhNodeContent<T>,
aabb:Aabb, aabb:Aabb,
} }
impl BvhNode{ impl<T:Copy+Eq+std::hash::Hash> BvhNode<T>{
pub fn the_tester<F:FnMut(usize)>(&self,aabb:&Aabb,f:&mut F){ pub fn the_tester<F:FnMut(T)>(&self,aabb:&Aabb,f:&mut F){
match &self.content{ match &self.content{
&BvhNodeContent::Leaf(model)=>f(model), &BvhNodeContent::Leaf(model)=>f(model),
BvhNodeContent::Branch(children)=>for child in children{ BvhNodeContent::Branch(children)=>for child in children{
@ -41,13 +42,13 @@ impl BvhNode{
} }
} }
pub fn generate_bvh(boxen:Vec<Aabb>)->BvhNode{ pub fn generate_bvh<T:Copy+Eq+std::hash::Hash>(boxen:Vec<(T,Aabb)>)->BvhNode<T>{
generate_bvh_node(boxen.into_iter().enumerate().collect()) generate_bvh_node(boxen,false)
} }
fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{ fn generate_bvh_node<T:Copy+Eq+std::hash::Hash>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
let n=boxen.len(); let n=boxen.len();
if n<20{ if force||n<20{
let mut aabb=Aabb::default(); let mut aabb=Aabb::default();
let nodes=boxen.into_iter().map(|b|{ let nodes=boxen.into_iter().map(|b|{
aabb.join(&b.1); aabb.join(&b.1);
@ -110,14 +111,19 @@ fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{
list_list[list_id].push((i,aabb)); list_list[list_id].push((i,aabb));
} }
let mut aabb=Aabb::default(); let mut aabb=Aabb::default();
let children=list_list.into_iter().map(|b|{ if list_list.len()==1{
let node=generate_bvh_node(b); generate_bvh_node(list_list.remove(0),true)
}else{
BvhNode{
content:BvhNodeContent::Branch(
list_list.into_iter().map(|b|{
let node=generate_bvh_node(b,false);
aabb.join(&node.aabb); aabb.join(&node.aabb);
node node
}).collect(); }).collect()
BvhNode{ ),
content:BvhNodeContent::Branch(children),
aabb, aabb,
} }
} }
} }
}

View File

@ -1,3 +1,4 @@
use crate::model;
use crate::integer::{Time,Planar64,Planar64Vec3}; use crate::integer::{Time,Planar64,Planar64Vec3};
//you have this effect while in contact //you have this effect while in contact
@ -8,8 +9,9 @@ pub struct ContactingLadder{
#[derive(Clone,Hash,Eq,PartialEq)] #[derive(Clone,Hash,Eq,PartialEq)]
pub enum ContactingBehaviour{ pub enum ContactingBehaviour{
Surf, Surf,
Cling,//usable as a zipline, or other weird and wonderful things
Ladder(ContactingLadder), Ladder(ContactingLadder),
NoJump,
Cling,//usable as a zipline, or other weird and wonderful things
Elastic(u32),//[1/2^32,1] 0=None (elasticity+1)/2^32 Elastic(u32),//[1/2^32,1] 0=None (elasticity+1)/2^32
} }
//you have this effect while intersecting //you have this effect while intersecting
@ -54,7 +56,7 @@ pub enum SetTrajectory{
Velocity(Planar64Vec3),//SetVelocity Velocity(Planar64Vec3),//SetVelocity
} }
impl SetTrajectory{ impl SetTrajectory{
fn is_velocity(&self)->bool{ pub const fn is_absolute(&self)->bool{
match self{ match self{
SetTrajectory::AirTime(_) SetTrajectory::AirTime(_)
|SetTrajectory::Height(_) |SetTrajectory::Height(_)
@ -76,7 +78,7 @@ pub struct Wormhole{
//destination does not need to be another wormhole //destination does not need to be another wormhole
//this defines a one way portal to a destination model transform //this defines a one way portal to a destination model transform
//two of these can create a two way wormhole //two of these can create a two way wormhole
pub destination_model_id:u32, pub destination_model:model::ModelId,
//(position,angles)*=origin.transform.inverse()*destination.transform //(position,angles)*=origin.transform.inverse()*destination.transform
} }
//attributes listed in order of handling //attributes listed in order of handling
@ -88,14 +90,14 @@ pub struct GeneralAttributes{
pub accelerator:Option<Accelerator>, pub accelerator:Option<Accelerator>,
} }
impl GeneralAttributes{ impl GeneralAttributes{
pub fn any(&self)->bool{ pub const fn any(&self)->bool{
self.booster.is_some() self.booster.is_some()
||self.trajectory.is_some() ||self.trajectory.is_some()
||self.wormhole.is_some() ||self.wormhole.is_some()
||self.accelerator.is_some() ||self.accelerator.is_some()
} }
pub fn is_wrcp(&self)->bool{ pub fn is_wrcp(&self)->bool{
self.trajectory.as_ref().map_or(false,|t|t.is_velocity()) self.trajectory.as_ref().map_or(false,|t|t.is_absolute())
/* /*
&&match &self.teleport_behaviour{ &&match &self.teleport_behaviour{
Some(TeleportBehaviour::StageElement( Some(TeleportBehaviour::StageElement(
@ -117,7 +119,7 @@ pub struct ContactingAttributes{
pub contact_behaviour:Option<ContactingBehaviour>, pub contact_behaviour:Option<ContactingBehaviour>,
} }
impl ContactingAttributes{ impl ContactingAttributes{
pub fn any(&self)->bool{ pub const fn any(&self)->bool{
self.contact_behaviour.is_some() self.contact_behaviour.is_some()
} }
} }
@ -126,11 +128,13 @@ pub struct IntersectingAttributes{
pub water:Option<IntersectingWater>, pub water:Option<IntersectingWater>,
} }
impl IntersectingAttributes{ impl IntersectingAttributes{
pub fn any(&self)->bool{ pub const fn any(&self)->bool{
self.water.is_some() self.water.is_some()
} }
} }
#[derive(Clone,Copy,id::Id,Hash,Eq,PartialEq)]
pub struct CollisionAttributesId(u32); pub struct CollisionAttributesId(u32);
#[derive(Clone,Hash,Eq,PartialEq)]
pub enum CollisionAttributes{ pub enum CollisionAttributes{
Decoration,//visual only Decoration,//visual only
Contact{//track whether you are contacting the object Contact{//track whether you are contacting the object

View File

@ -1,14 +1,38 @@
use std::collections::{HashSet,HashMap}; use std::collections::{HashSet,HashMap};
use crate::model::ModelId; use crate::model::ModelId;
use crate::gameplay_style; use crate::gameplay_style;
use crate::updatable::Updatable;
#[derive(Clone)]
pub struct StageElement{ pub struct StageElement{
stage:StageId,//which stage spawn to send to stage_id:StageId,//which stage spawn to send to
force:bool,//allow setting to lower spawn id i.e. 7->3 force:bool,//allow setting to lower spawn id i.e. 7->3
behaviour:StageElementBehaviour behaviour:StageElementBehaviour
} }
impl StageElement{
#[inline]
pub const fn new(stage_id:StageId,force:bool,behaviour:StageElementBehaviour)->Self{
Self{
stage_id,
force,
behaviour,
}
}
#[inline]
pub const fn stage_id(&self)->StageId{
self.stage_id
}
#[inline]
pub const fn force(&self)->bool{
self.force
}
#[inline]
pub const fn behaviour(&self)->StageElementBehaviour{
self.behaviour
}
}
#[derive(Clone,Hash,Eq,PartialEq)] #[derive(Clone,Copy,Hash,Eq,PartialEq)]
pub enum StageElementBehaviour{ pub enum StageElementBehaviour{
SpawnAt,//must be standing on top to get effect. except cancollide false SpawnAt,//must be standing on top to get effect. except cancollide false
Trigger, Trigger,
@ -20,51 +44,150 @@ pub enum StageElementBehaviour{
Checkpoint,//this is a combined behaviour for Ordered & Unordered in case a model is used multiple times or for both. Checkpoint,//this is a combined behaviour for Ordered & Unordered in case a model is used multiple times or for both.
} }
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
pub struct CheckpointId(u32);
impl CheckpointId{
pub const FIRST:Self=Self(0);
}
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
pub struct StageId(u32); pub struct StageId(u32);
impl StageId{
pub const FIRST:Self=Self(0);
}
#[derive(Clone)]
pub struct Stage{ pub struct Stage{
spawn:ModelId, spawn:ModelId,
//other behaviour models of this stage can have //open world support lol
ordered_checkpoints:Vec<ModelId>, ordered_checkpoints_count:u32,
unordered_checkpoints_count:u32,
//currently loaded checkpoint models
ordered_checkpoints:HashMap<CheckpointId,ModelId>,
unordered_checkpoints:HashSet<ModelId>, unordered_checkpoints:HashSet<ModelId>,
} }
impl Stage{
#[derive(Clone,Hash,Eq,PartialEq)] pub fn new(spawn:ModelId)->Self{
pub enum ZoneBehaviour{ Self{
Finish, spawn,
Anitcheat, ordered_checkpoints_count:0,
unordered_checkpoints_count:0,
ordered_checkpoints:HashMap::new(),
unordered_checkpoints:HashSet::new(),
} }
}
#[inline]
pub const fn spawn(&self)->ModelId{
self.spawn
}
#[inline]
pub const fn is_empty(&self)->bool{
self.is_complete(0,0)
}
#[inline]
pub const fn is_complete(&self,ordered_checkpoints_count:u32,unordered_checkpoints_count:u32)->bool{
self.ordered_checkpoints_count==ordered_checkpoints_count&&self.unordered_checkpoints_count==unordered_checkpoints_count
}
#[inline]
pub fn is_next_ordered_checkpoint(&self,next_ordered_checkpoint_id:CheckpointId,model_id:ModelId)->bool{
self.ordered_checkpoints.get(&next_ordered_checkpoint_id).is_some_and(|&next_checkpoint|model_id==next_checkpoint)
}
#[inline]
pub fn is_unordered_checkpoint(&self,model_id:ModelId)->bool{
self.unordered_checkpoints.contains(&model_id)
}
}
#[derive(Default)]
pub struct StageUpdate{
//other behaviour models of this stage can have
ordered_checkpoints:HashMap<CheckpointId,ModelId>,
unordered_checkpoints:HashSet<ModelId>,
}
impl Updatable<StageUpdate> for Stage{
fn update(&mut self,update:StageUpdate){
self.ordered_checkpoints.extend(update.ordered_checkpoints);
self.unordered_checkpoints.extend(update.unordered_checkpoints);
}
}
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
pub enum Zone{
Start,
Finish,
Anticheat,
}
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
pub struct ModeId(u32); pub struct ModeId(u32);
impl ModeId{
pub const MAIN:Self=Self(0);
pub const BONUS:Self=Self(1);
}
#[derive(Clone)]
pub struct Mode{ pub struct Mode{
style:gameplay_style::StyleModifiers, style:gameplay_style::StyleModifiers,
start:ModelId, start:ModelId,//when you press reset you go here
zones:HashMap<ModelId,ZoneBehaviour>, zones:HashMap<ModelId,Zone>,
stages:Vec<Stage>, stages:Vec<Stage>,//when you load the map you go to stages[0].spawn
//mutually exlusive stage element behaviour //mutually exlusive stage element behaviour
elements:HashMap<ModelId,StageElement>, elements:HashMap<ModelId,StageElement>,
jump_limit:HashMap<ModelId,u32>, jump_limit:HashMap<ModelId,u32>,
} }
impl Mode{ impl Mode{
pub fn new(style:gameplay_style::StyleModifiers,start:ModelId)->Self{
Self{
style,
start,
zones:HashMap::new(),
stages:Vec::new(),
elements:HashMap::new(),
jump_limit:HashMap::new(),
}
}
pub const fn get_start(&self)->ModelId{
self.start
}
pub const fn get_style(&self)->&gameplay_style::StyleModifiers{
&self.style
}
pub fn push_stage(&mut self,stage:Stage){
self.stages.push(stage)
}
pub fn get_stage_mut(&mut self,stage:StageId)->Option<&mut Stage>{
self.stages.get_mut(stage.0 as usize)
}
pub fn get_spawn_model_id(&self,stage:StageId)->Option<ModelId>{ pub fn get_spawn_model_id(&self,stage:StageId)->Option<ModelId>{
self.stages.get(stage.0 as usize).map(|s|s.spawn) self.stages.get(stage.0 as usize).map(|s|s.spawn)
} }
pub fn get_zone(&self,model_id:ModelId)->Option<&Zone>{
self.zones.get(&model_id)
}
pub fn get_stage(&self,stage_id:StageId)->Option<&Stage>{
self.stages.get(stage_id.0 as usize)
}
pub fn get_element(&self,model_id:ModelId)->Option<&StageElement>{
self.elements.get(&model_id)
}
pub fn get_jump_limit(&self,model_id:ModelId)->Option<u32>{
self.jump_limit.get(&model_id).copied()
}
//TODO: put this in the SNF
pub fn denormalize_data(&mut self){ pub fn denormalize_data(&mut self){
//expand and index normalized data //expand and index normalized data
self.zones.insert(self.start,Zone::Start);
for (stage_id,stage) in self.stages.iter().enumerate(){ for (stage_id,stage) in self.stages.iter().enumerate(){
self.elements.insert(stage.spawn,StageElement{ self.elements.insert(stage.spawn,StageElement{
stage:StageId(stage_id as u32), stage_id:StageId(stage_id as u32),
force:false, force:false,
behaviour:StageElementBehaviour::SpawnAt, behaviour:StageElementBehaviour::SpawnAt,
}); });
for &model_id in &stage.ordered_checkpoints{ for (_,&model) in &stage.ordered_checkpoints{
self.elements.insert(model_id,StageElement{ self.elements.insert(model,StageElement{
stage:StageId(stage_id as u32), stage_id:StageId(stage_id as u32),
force:false, force:false,
behaviour:StageElementBehaviour::Checkpoint, behaviour:StageElementBehaviour::Checkpoint,
}); });
} }
for &model_id in &stage.unordered_checkpoints{ for &model in &stage.unordered_checkpoints{
self.elements.insert(model_id,StageElement{ self.elements.insert(model,StageElement{
stage:StageId(stage_id as u32), stage_id:StageId(stage_id as u32),
force:false, force:false,
behaviour:StageElementBehaviour::Checkpoint, behaviour:StageElementBehaviour::Checkpoint,
}); });
@ -72,19 +195,81 @@ impl Mode{
} }
} }
} }
//this would be nice as a macro
#[derive(Default)]
pub struct ModeUpdate{
zones:HashMap<ModelId,Zone>,
stages:HashMap<StageId,StageUpdate>,
//mutually exlusive stage element behaviour
elements:HashMap<ModelId,StageElement>,
jump_limit:HashMap<ModelId,u32>,
}
impl Updatable<ModeUpdate> for Mode{
fn update(&mut self,update:ModeUpdate){
self.zones.extend(update.zones);
for (stage,stage_update) in update.stages{
if let Some(stage)=self.stages.get_mut(stage.0 as usize){
stage.update(stage_update);
}
}
self.elements.extend(update.elements);
self.jump_limit.extend(update.jump_limit);
}
}
impl ModeUpdate{
pub fn zone(model_id:ModelId,zone:Zone)->Self{
let mut mu=Self::default();
mu.zones.insert(model_id,zone);
mu
}
pub fn stage(stage_id:StageId,stage_update:StageUpdate)->Self{
let mut mu=Self::default();
mu.stages.insert(stage_id,stage_update);
mu
}
pub fn element(model_id:ModelId,element:StageElement)->Self{
let mut mu=Self::default();
mu.elements.insert(model_id,element);
mu
}
pub fn jump_limit(model_id:ModelId,jump_limit:u32)->Self{
let mut mu=Self::default();
mu.jump_limit.insert(model_id,jump_limit);
mu
}
pub fn map_stage_element_ids<F:Fn(StageId)->StageId>(&mut self,f:F){
for (_,stage_element) in self.elements.iter_mut(){
stage_element.stage_id=f(stage_element.stage_id);
}
}
}
#[derive(Default)] #[derive(Default,Clone)]
pub struct Modes{ pub struct Modes{
modes:Vec<Mode>, modes:Vec<Mode>,
} }
impl Modes{ impl Modes{
pub fn clear(&mut self){ pub fn new(modes:Vec<Mode>)->Self{
self.modes.clear(); Self{
modes,
}
}
pub fn push_mode(&mut self,mode:Mode){
self.modes.push(mode)
} }
pub fn get_mode(&self,mode:ModeId)->Option<&Mode>{ pub fn get_mode(&self,mode:ModeId)->Option<&Mode>{
self.modes.get(mode.0 as usize) self.modes.get(mode.0 as usize)
} }
pub fn insert(&mut self,mode:Mode){ }
self.modes.push(mode); pub struct ModesUpdate{
modes:HashMap<ModeId,ModeUpdate>,
}
impl Updatable<ModesUpdate> for Modes{
fn update(&mut self,update:ModesUpdate){
for (mode,mode_update) in update.modes{
if let Some(mode)=self.modes.get_mut(mode.0 as usize){
mode.update(mode_update);
}
}
} }
} }

View File

@ -1,28 +1,29 @@
const VALVE_SCALE:i64=16; const VALVE_SCALE:Planar64=Planar64::raw(1<<28);// 1/16
use crate::integer::{Time,Ratio64,Planar64,Planar64Vec3}; use crate::integer::{Time,Ratio64,Planar64,Planar64Vec3};
#[derive(Clone)]
pub struct StyleModifiers{ pub struct StyleModifiers{
controls_used:u32,//controls which are allowed to pass into gameplay pub controls_used:u32,//controls which are allowed to pass into gameplay
controls_mask:u32,//controls which are masked from control state (e.g. jump in scroll style) pub controls_mask:u32,//controls which are masked from control state (e.g. jump in scroll style)
strafe:Option<StrafeSettings>, pub strafe:Option<StrafeSettings>,
jump_impulse:JumpImpulse, pub jump_impulse:JumpImpulse,
jump_calculation:JumpCalculation, pub jump_calculation:JumpCalculation,
static_friction:Planar64, pub static_friction:Planar64,
kinetic_friction:Planar64, pub kinetic_friction:Planar64,
walk_speed:Planar64, pub walk_speed:Planar64,
walk_accel:Planar64, pub walk_accel:Planar64,
ladder_speed:Planar64, pub ladder_speed:Planar64,
ladder_accel:Planar64, pub ladder_accel:Planar64,
ladder_dot:Planar64, pub ladder_dot:Planar64,
swim_speed:Planar64, pub swim_speed:Planar64,
mass:Planar64, pub mass:Planar64,
mv:Planar64, pub mv:Planar64,
surf_slope:Option<Planar64>, pub surf_slope:Option<Planar64>,
rocket_force:Option<Planar64>, pub rocket_force:Option<Planar64>,
gravity:Planar64Vec3, pub gravity:Planar64Vec3,
hitbox:Hitbox, pub hitbox:Hitbox,
camera_offset:Planar64Vec3, pub camera_offset:Planar64Vec3,
} }
impl std::default::Default for StyleModifiers{ impl std::default::Default for StyleModifiers{
fn default()->Self{ fn default()->Self{
@ -30,18 +31,18 @@ impl std::default::Default for StyleModifiers{
} }
} }
impl StyleModifiers{ impl StyleModifiers{
const CONTROL_MOVEFORWARD:u32=0b00000001; pub const CONTROL_MOVEFORWARD:u32=0b00000001;
const CONTROL_MOVEBACK:u32=0b00000010; pub const CONTROL_MOVEBACK:u32=0b00000010;
const CONTROL_MOVERIGHT:u32=0b00000100; pub const CONTROL_MOVERIGHT:u32=0b00000100;
const CONTROL_MOVELEFT:u32=0b00001000; pub const CONTROL_MOVELEFT:u32=0b00001000;
const CONTROL_MOVEUP:u32=0b00010000; pub const CONTROL_MOVEUP:u32=0b00010000;
const CONTROL_MOVEDOWN:u32=0b00100000; pub const CONTROL_MOVEDOWN:u32=0b00100000;
const CONTROL_JUMP:u32=0b01000000; pub const CONTROL_JUMP:u32=0b01000000;
const CONTROL_ZOOM:u32=0b10000000; pub const CONTROL_ZOOM:u32=0b10000000;
const RIGHT_DIR:Planar64Vec3=Planar64Vec3::X; pub const RIGHT_DIR:Planar64Vec3=Planar64Vec3::X;
const UP_DIR:Planar64Vec3=Planar64Vec3::Y; pub const UP_DIR:Planar64Vec3=Planar64Vec3::Y;
const FORWARD_DIR:Planar64Vec3=Planar64Vec3::NEG_Z; pub const FORWARD_DIR:Planar64Vec3=Planar64Vec3::NEG_Z;
fn neo()->Self{ fn neo()->Self{
Self{ Self{
@ -72,7 +73,7 @@ impl StyleModifiers{
} }
} }
fn roblox_bhop()->Self{ pub fn roblox_bhop()->Self{
Self{ Self{
controls_used:!0, controls_used:!0,
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN), controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
@ -138,13 +139,13 @@ impl StyleModifiers{
air_accel_limit:Some(Planar64::raw(150<<28)*100), air_accel_limit:Some(Planar64::raw(150<<28)*100),
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(), tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
}), }),
jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)/VALVE_SCALE), jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
jump_calculation:JumpCalculation::Linear, jump_calculation:JumpCalculation::Linear,
gravity:Planar64Vec3::int(0,-800,0)/VALVE_SCALE, gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
static_friction:Planar64::int(2),//? static_friction:Planar64::int(2),//?
kinetic_friction:Planar64::int(3),//? kinetic_friction:Planar64::int(3),//?
mass:Planar64::int(1), mass:Planar64::int(1),
mv:Planar64::raw(30)/VALVE_SCALE, mv:Planar64::raw(30)*VALVE_SCALE,
rocket_force:None, rocket_force:None,
walk_speed:Planar64::int(18),//? walk_speed:Planar64::int(18),//?
walk_accel:Planar64::int(90),//? walk_accel:Planar64::int(90),//?
@ -154,7 +155,7 @@ impl StyleModifiers{
swim_speed:Planar64::int(12),//? swim_speed:Planar64::int(12),//?
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75 surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
hitbox:Hitbox::source(), hitbox:Hitbox::source(),
camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)/VALVE_SCALE, camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
} }
} }
fn source_surf()->Self{ fn source_surf()->Self{
@ -163,16 +164,16 @@ impl StyleModifiers{
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN), controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
strafe:Some(StrafeSettings{ strafe:Some(StrafeSettings{
enable:EnableStrafe::Always, enable:EnableStrafe::Always,
air_accel_limit:Some(Planar64::int(150)*66/VALVE_SCALE), air_accel_limit:Some(Planar64::int(150)*66*VALVE_SCALE),
tick_rate:Ratio64::new(66,Time::ONE_SECOND.nanos() as u64).unwrap(), tick_rate:Ratio64::new(66,Time::ONE_SECOND.nanos() as u64).unwrap(),
}), }),
jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)/VALVE_SCALE), jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
jump_calculation:JumpCalculation::Linear, jump_calculation:JumpCalculation::Linear,
gravity:Planar64Vec3::int(0,-800,0)/VALVE_SCALE, gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
static_friction:Planar64::int(2),//? static_friction:Planar64::int(2),//?
kinetic_friction:Planar64::int(3),//? kinetic_friction:Planar64::int(3),//?
mass:Planar64::int(1), mass:Planar64::int(1),
mv:Planar64::int(30)/VALVE_SCALE, mv:Planar64::int(30)*VALVE_SCALE,
rocket_force:None, rocket_force:None,
walk_speed:Planar64::int(18),//? walk_speed:Planar64::int(18),//?
walk_accel:Planar64::int(90),//? walk_accel:Planar64::int(90),//?
@ -182,7 +183,7 @@ impl StyleModifiers{
swim_speed:Planar64::int(12),//? swim_speed:Planar64::int(12),//?
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75 surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
hitbox:Hitbox::source(), hitbox:Hitbox::source(),
camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)/VALVE_SCALE, camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
} }
} }
fn roblox_rocket()->Self{ fn roblox_rocket()->Self{
@ -211,13 +212,15 @@ impl StyleModifiers{
} }
} }
enum JumpCalculation{ #[derive(Clone)]
pub enum JumpCalculation{
Capped,//roblox Capped,//roblox
Energy,//new Energy,//new
Linear,//source Linear,//source
} }
enum JumpImpulse{ #[derive(Clone)]
pub enum JumpImpulse{
FromTime(Time),//jump time is invariant across mass and gravity changes FromTime(Time),//jump time is invariant across mass and gravity changes
FromHeight(Planar64),//jump height is invariant across mass and gravity changes FromHeight(Planar64),//jump height is invariant across mass and gravity changes
FromDeltaV(Planar64),//jump velocity is invariant across mass and gravity changes FromDeltaV(Planar64),//jump velocity is invariant across mass and gravity changes
@ -228,20 +231,35 @@ enum JumpImpulse{
//Energy means it adds energy //Energy means it adds energy
//Linear means it linearly adds on //Linear means it linearly adds on
enum EnableStrafe{ #[derive(Clone)]
pub enum EnableStrafe{
Always, Always,
MaskAny(u32),//hsw, shsw MaskAny(u32),//hsw, shsw
MaskAll(u32), MaskAll(u32),
//Function(Box<dyn Fn(u32)->bool>), //Function(Box<dyn Fn(u32)->bool>),
} }
struct StrafeSettings{ #[derive(Clone)]
pub struct StrafeSettings{
enable:EnableStrafe, enable:EnableStrafe,
air_accel_limit:Option<Planar64>, air_accel_limit:Option<Planar64>,
tick_rate:Ratio64, tick_rate:Ratio64,
} }
impl StrafeSettings{
pub fn next_tick(&self,time:Time)->Time{
Time::from_nanos(self.tick_rate.rhs_div_int(self.tick_rate.mul_int(time.nanos())+1))
}
pub fn mask(&self,controls:u32)->bool{
match self.enable{
EnableStrafe::Always=>true,
EnableStrafe::MaskAny(mask)=>mask&controls!=0,
EnableStrafe::MaskAll(mask)=>mask&controls==mask,
}
}
}
enum HitboxMesh{ #[derive(Clone)]
pub enum HitboxMesh{
Box,//source Box,//source
Cylinder,//roblox Cylinder,//roblox
//Sphere,//roblox old physics //Sphere,//roblox old physics
@ -250,9 +268,10 @@ enum HitboxMesh{
//DualCone, //DualCone,
} }
struct Hitbox{ #[derive(Clone)]
halfsize:Planar64Vec3, pub struct Hitbox{
mesh:HitboxMesh, pub halfsize:Planar64Vec3,
pub mesh:HitboxMesh,
} }
impl Hitbox{ impl Hitbox{
fn roblox()->Self{ fn roblox()->Self{
@ -263,7 +282,7 @@ impl Hitbox{
} }
fn source()->Self{ fn source()->Self{
Self{ Self{
halfsize:Planar64Vec3::raw(33,73,33)/2/VALVE_SCALE, halfsize:Planar64Vec3::raw(33,73,33)/2*VALVE_SCALE,
mesh:HitboxMesh::Box, mesh:HitboxMesh::Box,
} }
} }

View File

@ -294,9 +294,10 @@ impl std::ops::Mul<i64> for Ratio64Vec2{
pub struct Angle32(i32); pub struct Angle32(i32);
impl Angle32{ impl Angle32{
pub const FRAC_PI_2:Self=Self(1<<30); pub const FRAC_PI_2:Self=Self(1<<30);
pub const NEG_FRAC_PI_2:Self=Self(-1<<30);
pub const PI:Self=Self(-1<<31); pub const PI:Self=Self(-1<<31);
#[inline] #[inline]
pub fn wrap_from_i64(theta:i64)->Self{ pub const fn wrap_from_i64(theta:i64)->Self{
//take lower bits //take lower bits
//note: this was checked on compiler explorer and compiles to 1 instruction! //note: this was checked on compiler explorer and compiles to 1 instruction!
Self(i32::from_ne_bytes(((theta&((1<<32)-1)) as u32).to_ne_bytes())) Self(i32::from_ne_bytes(((theta&((1<<32)-1)) as u32).to_ne_bytes()))
@ -308,7 +309,7 @@ impl Angle32{
Self(theta.clamp(i32::MIN as i64,i32::MAX as i64) as i32) Self(theta.clamp(i32::MIN as i64,i32::MAX as i64) as i32)
} }
#[inline] #[inline]
pub fn get(&self)->i32{ pub const fn get(&self)->i32{
self.0 self.0
} }
/// Clamps the value towards the midpoint of the range. /// Clamps the value towards the midpoint of the range.
@ -411,7 +412,7 @@ impl TryFrom<[f32;3]> for Unit32Vec3{
*/ */
///[-1.0,1.0] = [-2^32,2^32] ///[-1.0,1.0] = [-2^32,2^32]
#[derive(Clone,Copy,Hash,Eq,Ord,PartialEq,PartialOrd)] #[derive(Clone,Copy,Debug,Hash,Eq,Ord,PartialEq,PartialOrd)]
pub struct Planar64(i64); pub struct Planar64(i64);
impl Planar64{ impl Planar64{
pub const ZERO:Self=Self(0); pub const ZERO:Self=Self(0);
@ -579,7 +580,7 @@ impl std::ops::Div<Planar64> for Planar64{
///[-1.0,1.0] = [-2^32,2^32] ///[-1.0,1.0] = [-2^32,2^32]
#[derive(Clone,Copy,Default,Hash,Eq,PartialEq)] #[derive(Clone,Copy,Debug,Default,Hash,Eq,PartialEq)]
pub struct Planar64Vec3(glam::I64Vec3); pub struct Planar64Vec3(glam::I64Vec3);
impl Planar64Vec3{ impl Planar64Vec3{
pub const ZERO:Self=Planar64Vec3(glam::I64Vec3::ZERO); pub const ZERO:Self=Planar64Vec3(glam::I64Vec3::ZERO);

View File

@ -1,8 +1,10 @@
pub mod bvh; pub mod bvh;
pub mod map;
pub mod aabb; pub mod aabb;
pub mod model; pub mod model;
pub mod zeroes; pub mod zeroes;
pub mod integer; pub mod integer;
pub mod updatable;
pub mod instruction; pub mod instruction;
pub mod gameplay_modes; pub mod gameplay_modes;
pub mod gameplay_style; pub mod gameplay_style;

13
src/map.rs Normal file
View File

@ -0,0 +1,13 @@
use crate::model;
use crate::gameplay_modes;
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 attributes:Vec<gameplay_attributes::CollisionAttributes>,
pub meshes:Vec<model::Mesh>,
pub models:Vec<model::Model>,
//RenderPattern
pub render_configs:Vec<model::RenderConfig>,
}

View File

@ -3,51 +3,126 @@ use crate::gameplay_attributes;
pub type TextureCoordinate=glam::Vec2; pub type TextureCoordinate=glam::Vec2;
pub type Color4=glam::Vec4; pub type Color4=glam::Vec4;
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct PositionId(u32);
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct TextureCoordinateId(u32);
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct NormalId(u32);
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct ColorId(u32);
#[derive(Clone,Hash,PartialEq,Eq)] #[derive(Clone,Hash,PartialEq,Eq)]
pub struct IndexedVertex{ pub struct IndexedVertex{
pub pos:u32, pub pos:PositionId,
pub tex:u32, pub tex:TextureCoordinateId,
pub normal:u32, pub normal:NormalId,
pub color:u32, pub color:ColorId,
} }
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct VertexId(u32); pub struct VertexId(u32);
pub struct IndexedVertexList{ pub type IndexedVertexList=Vec<VertexId>;
pub vertices:Vec<VertexId>, pub trait PolygonIter{
fn polys(&self)->impl Iterator<Item=&[VertexId]>;
}
pub trait MapVertexId{
fn map_vertex_id<F:Fn(VertexId)->VertexId>(self,f:F)->Self;
}
pub struct PolygonList(Vec<IndexedVertexList>);
impl PolygonList{
pub const fn new(list:Vec<IndexedVertexList>)->Self{
Self(list)
}
pub fn extend<T:IntoIterator<Item=IndexedVertexList>>(&mut self,iter:T){
self.0.extend(iter);
}
}
impl PolygonIter for PolygonList{
fn polys(&self)->impl Iterator<Item=&[VertexId]>{
self.0.iter().map(|poly|poly.as_slice())
}
}
impl MapVertexId for PolygonList{
fn map_vertex_id<F:Fn(VertexId)->VertexId>(self,f:F)->Self{
Self(self.0.into_iter().map(|ivl|ivl.into_iter().map(&f).collect()).collect())
}
}
// pub struct TriangleStrip(IndexedVertexList);
// impl PolygonIter for TriangleStrip{
// fn polys(&self)->impl Iterator<Item=&[VertexId]>{
// self.0.vertices.windows(3).enumerate().map(|(i,s)|if i&0!=0{return s.iter().rev()}else{return s.iter()})
// }
// }
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct PolygonGroupId(u32);
pub enum PolygonGroup{
PolygonList(PolygonList),
//TriangleStrip(TriangleStrip),
}
impl PolygonIter for PolygonGroup{
fn polys(&self)->impl Iterator<Item=&[VertexId]>{
match self{
PolygonGroup::PolygonList(list)=>list.polys(),
//PolygonGroup::TriangleStrip(strip)=>strip.polys(),
}
}
}
impl MapVertexId for PolygonGroup{
fn map_vertex_id<F:Fn(VertexId)->VertexId>(self,f:F)->Self{
match self{
PolygonGroup::PolygonList(polys)=>Self::PolygonList(polys.map_vertex_id(f)),
}
}
}
/// Ah yes, a group of things to render at the same time
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
pub struct TextureId(u32);
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
pub struct RenderConfigId(u32);
#[derive(Default)]
pub struct RenderConfig{
pub texture:Option<TextureId>,
}
impl RenderConfig{
pub const fn texture(texture:TextureId)->Self{
Self{
texture:Some(texture),
}
} }
pub struct GroupId(u32);
pub enum IndexedGroup{
PolygonList(Vec<IndexedVertexList>),
//TriangleStrip(Vec<IndexedVertexList>),
} }
pub struct RenderId(u32);
pub struct IndexedGraphicsGroup{ pub struct IndexedGraphicsGroup{
//Render pattern material/texture/shader/flat color //Render pattern material/texture/shader/flat color
pub render:RenderId, pub render:RenderConfigId,
pub groups:Vec<GroupId>, pub groups:Vec<PolygonGroupId>,
} }
#[derive(Default)]
pub struct IndexedPhysicsGroup{ pub struct IndexedPhysicsGroup{
//the polygons in this group are guaranteed to make a closed convex shape //the polygons in this group are guaranteed to make a closed convex shape
pub groups:Vec<GroupId>, pub groups:Vec<PolygonGroupId>,
} }
//This is a superset of PhysicsModel and GraphicsModel //This is a superset of PhysicsModel and GraphicsModel
pub struct IndexedModel{ #[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
pub struct MeshId(u32);
pub struct Mesh{
pub unique_pos:Vec<Planar64Vec3>,//Unit32Vec3 pub unique_pos:Vec<Planar64Vec3>,//Unit32Vec3
pub unique_normal:Vec<Planar64Vec3>,//Unit32Vec3 pub unique_normal:Vec<Planar64Vec3>,//Unit32Vec3
pub unique_tex:Vec<TextureCoordinate>, pub unique_tex:Vec<TextureCoordinate>,
pub unique_color:Vec<Color4>, pub unique_color:Vec<Color4>,
pub unique_vertices:Vec<IndexedVertex>, pub unique_vertices:Vec<IndexedVertex>,
//groups are constant texture AND convexity slices //polygon groups are constant texture AND convexity slices
pub groups:Vec<IndexedGroup>, //note that this may need to be changed to be a list of individual faces
//for submeshes to work since face ids need to be consistent across submeshes
//so face == polygon_groups[face_id]
pub polygon_groups:Vec<PolygonGroup>,
//graphics indexed (by texture) //graphics indexed (by texture)
pub graphics_sets:Vec<IndexedGraphicsGroup>, pub graphics_groups:Vec<IndexedGraphicsGroup>,
//physics indexed (by convexity) //physics indexed (by convexity)
pub physics_sets:Vec<IndexedPhysicsGroup>, pub physics_groups:Vec<IndexedPhysicsGroup>,
} }
#[derive(Clone,Copy,Hash,Eq,PartialEq)] #[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
pub struct ModelId(u32); pub struct ModelId(u32);
pub struct Model{ pub struct Model{
pub model:ModelId, pub mesh:MeshId,
pub attributes:gameplay_attributes::CollisionAttributesId, pub attributes:gameplay_attributes::CollisionAttributesId,
pub color:Color4,//transparency is in here pub color:Color4,//transparency is in here
pub transform:Planar64Affine3, pub transform:Planar64Affine3,

56
src/updatable.rs Normal file
View File

@ -0,0 +1,56 @@
pub trait Updatable<Updater>{
fn update(&mut self,update:Updater);
}
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
struct InnerId(u32);
#[derive(Clone)]
struct Inner{
id:InnerId,
enabled:bool,
}
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
struct OuterId(u32);
struct Outer{
id:OuterId,
inners:std::collections::HashMap<InnerId,Inner>,
}
enum Update<I,U>{
Insert(I),
Update(U),
Remove
}
struct InnerUpdate{
//#[updatable(Update)]
enabled:Option<bool>,
}
struct OuterUpdate{
//#[updatable(Insert,Update,Remove)]
inners:std::collections::HashMap<InnerId,Update<Inner,InnerUpdate>>,
//#[updatable(Update)]
//inners:std::collections::HashMap<InnerId,InnerUpdate>,
}
impl Updatable<InnerUpdate> for Inner{
fn update(&mut self,update:InnerUpdate){
if let Some(enabled)=update.enabled{
self.enabled=enabled;
}
}
}
impl Updatable<OuterUpdate> for Outer{
fn update(&mut self,update:OuterUpdate){
for (id,up) in update.inners{
match up{
Update::Insert(new_inner)=>self.inners.insert(id,new_inner),
Update::Update(inner_update)=>self.inners.get_mut(&id).map(|inner|{
let old=inner.clone();
inner.update(inner_update);
old
}),
Update::Remove=>self.inners.remove(&id),
};
}
}
}
//*/