Compare commits
27 Commits
timers2
...
data-struc
Author | SHA1 | Date | |
---|---|---|---|
fccb13bc60 | |||
43f771fb0f | |||
d31dcd0b19 | |||
f155dd6a50 | |||
43aa079d89 | |||
2ddb546f73 | |||
41d1904f08 | |||
03868552c2 | |||
a1fa2c2781 | |||
2ee041ff66 | |||
f8be75a3fc | |||
ec59d251d2 | |||
05d91c3221 | |||
cfbc486e12 | |||
fc1e6581ec | |||
7512c8676e | |||
75a1829f53 | |||
6f0c579601 | |||
cbee156c2f | |||
995ad255bc | |||
78686b449d | |||
f7b774c050 | |||
5efdd3654a | |||
37fb390465 | |||
96d813a3a6 | |||
9291b77679 | |||
fa97ab8c6d |
@ -1,2 +0,0 @@
|
||||
[registries.strafesnet]
|
||||
index = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -2,23 +2,16 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "glam"
|
||||
version = "0.28.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94"
|
||||
checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
|
||||
|
||||
[[package]]
|
||||
name = "id"
|
||||
version = "0.1.0"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "2337e7a6c273082b672e377e159d7a168fb51438461b7c4033c79a515dd7a25a"
|
||||
source = "git+https://git.itzana.me/Quaternions/id?rev=1f710976cc786c8853dab73d6e1cee53158deeb0#1f710976cc786c8853dab73d6e1cee53158deeb0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -45,18 +38,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strafesnet_common"
|
||||
version = "0.2.0"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"glam",
|
||||
"id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.52"
|
||||
version = "2.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -1,15 +1,10 @@
|
||||
[package]
|
||||
name = "strafesnet_common"
|
||||
version = "0.2.0"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
repository = "https://git.itzana.me/StrafesNET/common"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Common types and helpers for Strafe Client associated projects."
|
||||
authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.6.0"
|
||||
glam = "0.28.0"
|
||||
id = { version = "0.1.0", registry = "strafesnet" }
|
||||
glam = "0.25.0"
|
||||
id = { git = "https://git.itzana.me/Quaternions/id", rev = "1f710976cc786c8853dab73d6e1cee53158deeb0" }
|
||||
|
15
src/aabb.rs
15
src/aabb.rs
@ -6,22 +6,13 @@ pub struct Aabb{
|
||||
max:Planar64Vec3,
|
||||
}
|
||||
|
||||
impl Default for Aabb{
|
||||
fn default()->Self{
|
||||
impl Default for Aabb {
|
||||
fn default()->Self {
|
||||
Self{min:Planar64Vec3::MAX,max:Planar64Vec3::MIN}
|
||||
}
|
||||
}
|
||||
|
||||
impl Aabb{
|
||||
pub const fn new(min:Planar64Vec3,max:Planar64Vec3)->Self{
|
||||
Self{min,max}
|
||||
}
|
||||
pub const fn max(&self)->Planar64Vec3{
|
||||
self.max
|
||||
}
|
||||
pub const fn min(&self)->Planar64Vec3{
|
||||
self.min
|
||||
}
|
||||
pub fn grow(&mut self,point:Planar64Vec3){
|
||||
self.min=self.min.min(point);
|
||||
self.max=self.max.max(point);
|
||||
@ -52,4 +43,4 @@ impl Aabb{
|
||||
// let d=self.max-self.min;
|
||||
// d.x*d.y*d.z
|
||||
// }
|
||||
}
|
||||
}
|
92
src/bvh.rs
92
src/bvh.rs
@ -10,31 +10,26 @@ use crate::aabb::Aabb;
|
||||
//sort the centerpoints on each axis (3 lists)
|
||||
//bv is put into octant based on whether it is upper or lower in each list
|
||||
|
||||
pub enum RecursiveContent<R,T>{
|
||||
Branch(Vec<R>),
|
||||
enum BvhNodeContent<T>{
|
||||
Branch(Vec<BvhNode<T>>),
|
||||
Leaf(T),
|
||||
}
|
||||
impl<R,T> Default for RecursiveContent<R,T>{
|
||||
impl<T> Default for BvhNodeContent<T>{
|
||||
fn default()->Self{
|
||||
Self::Branch(Vec::new())
|
||||
}
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct BvhNode<T>{
|
||||
content:RecursiveContent<BvhNode<T>,T>,
|
||||
aabb:Aabb,
|
||||
}
|
||||
pub struct BvhWeightNode<W,T>{
|
||||
content:RecursiveContent<BvhWeightNode<W,T>,T>,
|
||||
weight:W,
|
||||
content:BvhNodeContent<T>,
|
||||
aabb:Aabb,
|
||||
}
|
||||
|
||||
impl<T> BvhNode<T>{
|
||||
pub fn the_tester<F:FnMut(&T)>(&self,aabb:&Aabb,f:&mut F){
|
||||
impl<T:Copy+Eq+std::hash::Hash> BvhNode<T>{
|
||||
pub fn the_tester<F:FnMut(T)>(&self,aabb:&Aabb,f:&mut F){
|
||||
match &self.content{
|
||||
RecursiveContent::Leaf(model)=>f(model),
|
||||
RecursiveContent::Branch(children)=>for child in children{
|
||||
&BvhNodeContent::Leaf(model)=>f(model),
|
||||
BvhNodeContent::Branch(children)=>for child in children{
|
||||
//this test could be moved outside the match statement
|
||||
//but that would test the root node aabb
|
||||
//you're probably not going to spend a lot of time outside the map,
|
||||
@ -45,72 +40,25 @@ impl<T> BvhNode<T>{
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){
|
||||
match self.content{
|
||||
RecursiveContent::Leaf(model)=>f(model),
|
||||
RecursiveContent::Branch(children)=>for child in children{
|
||||
child.into_visitor(f)
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn weigh_contents<W:Copy+std::iter::Sum<W>,F:Fn(&T)->W>(self,f:&F)->BvhWeightNode<W,T>{
|
||||
match self.content{
|
||||
RecursiveContent::Leaf(model)=>BvhWeightNode{
|
||||
weight:f(&model),
|
||||
content:RecursiveContent::Leaf(model),
|
||||
aabb:self.aabb,
|
||||
},
|
||||
RecursiveContent::Branch(children)=>{
|
||||
let branch:Vec<BvhWeightNode<W,T>>=children.into_iter().map(|child|
|
||||
child.weigh_contents(f)
|
||||
).collect();
|
||||
BvhWeightNode{
|
||||
weight:branch.iter().map(|node|node.weight).sum(),
|
||||
content:RecursiveContent::Branch(branch),
|
||||
aabb:self.aabb,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <W,T> BvhWeightNode<W,T>{
|
||||
pub const fn weight(&self)->&W{
|
||||
&self.weight
|
||||
}
|
||||
pub const fn aabb(&self)->&Aabb{
|
||||
&self.aabb
|
||||
}
|
||||
pub fn into_content(self)->RecursiveContent<BvhWeightNode<W,T>,T>{
|
||||
self.content
|
||||
}
|
||||
pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){
|
||||
match self.content{
|
||||
RecursiveContent::Leaf(model)=>f(model),
|
||||
RecursiveContent::Branch(children)=>for child in children{
|
||||
child.into_visitor(f)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_bvh<T>(boxen:Vec<(T,Aabb)>)->BvhNode<T>{
|
||||
pub fn generate_bvh<T:Copy+Eq+std::hash::Hash>(boxen:Vec<(T,Aabb)>)->BvhNode<T>{
|
||||
generate_bvh_node(boxen,false)
|
||||
}
|
||||
|
||||
fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
|
||||
fn generate_bvh_node<T:Copy+Eq+std::hash::Hash>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
|
||||
let n=boxen.len();
|
||||
if force||n<20{
|
||||
let mut aabb=Aabb::default();
|
||||
let nodes=boxen.into_iter().map(|b|{
|
||||
aabb.join(&b.1);
|
||||
BvhNode{
|
||||
content:RecursiveContent::Leaf(b.0),
|
||||
content:BvhNodeContent::Leaf(b.0),
|
||||
aabb:b.1,
|
||||
}
|
||||
}).collect();
|
||||
BvhNode{
|
||||
content:RecursiveContent::Branch(nodes),
|
||||
content:BvhNodeContent::Branch(nodes),
|
||||
aabb,
|
||||
}
|
||||
}else{
|
||||
@ -118,12 +66,12 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
|
||||
let mut sort_x=Vec::with_capacity(n);
|
||||
let mut sort_y=Vec::with_capacity(n);
|
||||
let mut sort_z=Vec::with_capacity(n);
|
||||
for (i,(_,aabb)) in boxen.iter().enumerate(){
|
||||
for (i,aabb) in boxen.iter(){
|
||||
let center=aabb.center();
|
||||
octant.insert(i,0);
|
||||
sort_x.push((i,center.x()));
|
||||
sort_y.push((i,center.y()));
|
||||
sort_z.push((i,center.z()));
|
||||
octant.insert(*i,0);
|
||||
sort_x.push((*i,center.x()));
|
||||
sort_y.push((*i,center.y()));
|
||||
sort_z.push((*i,center.z()));
|
||||
}
|
||||
sort_x.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
||||
sort_y.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
||||
@ -150,7 +98,7 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
|
||||
//generate lists for unique octant values
|
||||
let mut list_list=Vec::with_capacity(8);
|
||||
let mut octant_list=Vec::with_capacity(8);
|
||||
for (i,(data,aabb)) in boxen.into_iter().enumerate(){
|
||||
for (i,aabb) in boxen.into_iter(){
|
||||
let octant_id=octant[&i];
|
||||
let list_id=if let Some(list_id)=octant_list.iter().position(|&id|id==octant_id){
|
||||
list_id
|
||||
@ -160,14 +108,14 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
|
||||
list_list.push(Vec::new());
|
||||
list_id
|
||||
};
|
||||
list_list[list_id].push((data,aabb));
|
||||
list_list[list_id].push((i,aabb));
|
||||
}
|
||||
let mut aabb=Aabb::default();
|
||||
if list_list.len()==1{
|
||||
generate_bvh_node(list_list.remove(0),true)
|
||||
}else{
|
||||
BvhNode{
|
||||
content:RecursiveContent::Branch(
|
||||
content:BvhNodeContent::Branch(
|
||||
list_list.into_iter().map(|b|{
|
||||
let node=generate_bvh_node(b,false);
|
||||
aabb.join(&node.aabb);
|
||||
|
@ -1,30 +0,0 @@
|
||||
bitflags::bitflags!{
|
||||
#[derive(Clone,Copy,Debug,Default)]
|
||||
pub struct Controls:u32{
|
||||
const MoveForward=1<<0;
|
||||
const MoveLeft=1<<1;
|
||||
const MoveBackward=1<<2;
|
||||
const MoveRight=1<<3;
|
||||
const MoveUp=1<<4;
|
||||
const MoveDown=1<<5;
|
||||
const LookUp=1<<6;
|
||||
const LookLeft=1<<7;
|
||||
const LookDown=1<<8;
|
||||
const LookRight=1<<9;
|
||||
const Jump=1<<10;
|
||||
const Crouch=1<<11;
|
||||
const Sprint=1<<12;
|
||||
const Zoom=1<<13;
|
||||
const Use=1<<14;//Interact with object
|
||||
const PrimaryAction=1<<15;//LBM/Shoot/Melee
|
||||
const SecondaryAction=1<<16;//RMB/ADS/Block
|
||||
}
|
||||
}
|
||||
impl Controls{
|
||||
pub const fn wasd()->Self{
|
||||
Self::MoveForward.union(Self::MoveLeft).union(Self::MoveBackward).union(Self::MoveRight)
|
||||
}
|
||||
pub const fn wasdqe()->Self{
|
||||
Self::MoveForward.union(Self::MoveLeft).union(Self::MoveBackward).union(Self::MoveRight).union(Self::MoveUp).union(Self::MoveDown)
|
||||
}
|
||||
}
|
@ -146,8 +146,8 @@ pub enum CollisionAttributes{
|
||||
general:GeneralAttributes,
|
||||
},
|
||||
}
|
||||
impl CollisionAttributes{
|
||||
pub fn contact_default()->Self{
|
||||
impl std::default::Default for CollisionAttributes{
|
||||
fn default()->Self{
|
||||
Self::Contact{
|
||||
contacting:ContactingAttributes::default(),
|
||||
general:GeneralAttributes::default()
|
||||
|
@ -7,17 +7,15 @@ use crate::updatable::Updatable;
|
||||
pub struct StageElement{
|
||||
stage_id:StageId,//which stage spawn to send to
|
||||
force:bool,//allow setting to lower spawn id i.e. 7->3
|
||||
behaviour:StageElementBehaviour,
|
||||
jump_limit:Option<u8>,
|
||||
behaviour:StageElementBehaviour
|
||||
}
|
||||
impl StageElement{
|
||||
#[inline]
|
||||
pub const fn new(stage_id:StageId,force:bool,behaviour:StageElementBehaviour,jump_limit:Option<u8>)->Self{
|
||||
pub const fn new(stage_id:StageId,force:bool,behaviour:StageElementBehaviour)->Self{
|
||||
Self{
|
||||
stage_id,
|
||||
force,
|
||||
behaviour,
|
||||
jump_limit,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
@ -32,10 +30,6 @@ impl StageElement{
|
||||
pub const fn behaviour(&self)->StageElementBehaviour{
|
||||
self.behaviour
|
||||
}
|
||||
#[inline]
|
||||
pub const fn jump_limit(&self)->Option<u8>{
|
||||
self.jump_limit
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
@ -50,12 +44,12 @@ pub enum StageElementBehaviour{
|
||||
Checkpoint,//this is a combined behaviour for Ordered & Unordered in case a model is used multiple times or for both.
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,id::Id,Eq,PartialEq)]
|
||||
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct CheckpointId(u32);
|
||||
impl CheckpointId{
|
||||
pub const FIRST:Self=Self(0);
|
||||
}
|
||||
#[derive(Clone,Copy,Debug,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
|
||||
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
|
||||
pub struct StageId(u32);
|
||||
impl StageId{
|
||||
pub const FIRST:Self=Self(0);
|
||||
@ -71,22 +65,7 @@ pub struct Stage{
|
||||
unordered_checkpoints:HashSet<ModelId>,
|
||||
}
|
||||
impl Stage{
|
||||
pub fn new(
|
||||
spawn:ModelId,
|
||||
ordered_checkpoints_count:u32,
|
||||
unordered_checkpoints_count:u32,
|
||||
ordered_checkpoints:HashMap<CheckpointId,ModelId>,
|
||||
unordered_checkpoints:HashSet<ModelId>,
|
||||
)->Self{
|
||||
Self{
|
||||
spawn,
|
||||
ordered_checkpoints_count,
|
||||
unordered_checkpoints_count,
|
||||
ordered_checkpoints,
|
||||
unordered_checkpoints,
|
||||
}
|
||||
}
|
||||
pub fn empty(spawn:ModelId)->Self{
|
||||
pub fn new(spawn:ModelId)->Self{
|
||||
Self{
|
||||
spawn,
|
||||
ordered_checkpoints_count:0,
|
||||
@ -100,17 +79,6 @@ impl Stage{
|
||||
self.spawn
|
||||
}
|
||||
#[inline]
|
||||
pub const fn ordered_checkpoints_count(&self)->u32{
|
||||
self.ordered_checkpoints_count
|
||||
}
|
||||
#[inline]
|
||||
pub const fn unordered_checkpoints_count(&self)->u32{
|
||||
self.unordered_checkpoints_count
|
||||
}
|
||||
pub fn into_inner(self)->(HashMap<CheckpointId,ModelId>,HashSet<ModelId>){
|
||||
(self.ordered_checkpoints,self.unordered_checkpoints)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn is_empty(&self)->bool{
|
||||
self.is_complete(0,0)
|
||||
}
|
||||
@ -146,7 +114,7 @@ pub enum Zone{
|
||||
Finish,
|
||||
Anticheat,
|
||||
}
|
||||
#[derive(Clone,Copy,Debug,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
|
||||
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
|
||||
pub struct ModeId(u32);
|
||||
impl ModeId{
|
||||
pub const MAIN:Self=Self(0);
|
||||
@ -160,47 +128,19 @@ pub struct Mode{
|
||||
stages:Vec<Stage>,//when you load the map you go to stages[0].spawn
|
||||
//mutually exlusive stage element behaviour
|
||||
elements:HashMap<ModelId,StageElement>,
|
||||
jump_limit:HashMap<ModelId,u32>,
|
||||
}
|
||||
impl Mode{
|
||||
pub fn new(
|
||||
style:gameplay_style::StyleModifiers,
|
||||
start:ModelId,
|
||||
zones:HashMap<ModelId,Zone>,
|
||||
stages:Vec<Stage>,
|
||||
elements:HashMap<ModelId,StageElement>,
|
||||
)->Self{
|
||||
Self{
|
||||
style,
|
||||
start,
|
||||
zones,
|
||||
stages,
|
||||
elements,
|
||||
}
|
||||
}
|
||||
pub fn empty(style:gameplay_style::StyleModifiers,start:ModelId)->Self{
|
||||
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 fn into_inner(self)->(
|
||||
gameplay_style::StyleModifiers,
|
||||
ModelId,
|
||||
HashMap<ModelId,Zone>,
|
||||
Vec<Stage>,
|
||||
HashMap<ModelId,StageElement>,
|
||||
){
|
||||
(
|
||||
self.style,
|
||||
self.start,
|
||||
self.zones,
|
||||
self.stages,
|
||||
self.elements,
|
||||
)
|
||||
}
|
||||
pub const fn get_start(&self)->ModelId{
|
||||
self.start
|
||||
}
|
||||
@ -225,6 +165,9 @@ impl Mode{
|
||||
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){
|
||||
//expand and index normalized data
|
||||
@ -234,14 +177,12 @@ impl Mode{
|
||||
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{
|
||||
stage_id:StageId(stage_id as u32),
|
||||
force:false,
|
||||
behaviour:StageElementBehaviour::Checkpoint,
|
||||
jump_limit:None,
|
||||
});
|
||||
}
|
||||
for &model in &stage.unordered_checkpoints{
|
||||
@ -249,7 +190,6 @@ impl Mode{
|
||||
stage_id:StageId(stage_id as u32),
|
||||
force:false,
|
||||
behaviour:StageElementBehaviour::Checkpoint,
|
||||
jump_limit:None,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -262,6 +202,7 @@ pub struct ModeUpdate{
|
||||
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){
|
||||
@ -272,6 +213,7 @@ impl Updatable<ModeUpdate> for Mode{
|
||||
}
|
||||
}
|
||||
self.elements.extend(update.elements);
|
||||
self.jump_limit.extend(update.jump_limit);
|
||||
}
|
||||
}
|
||||
impl ModeUpdate{
|
||||
@ -290,6 +232,11 @@ impl ModeUpdate{
|
||||
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);
|
||||
@ -299,17 +246,14 @@ impl ModeUpdate{
|
||||
|
||||
#[derive(Default,Clone)]
|
||||
pub struct Modes{
|
||||
pub modes:Vec<Mode>,
|
||||
modes:Vec<Mode>,
|
||||
}
|
||||
impl Modes{
|
||||
pub const fn new(modes:Vec<Mode>)->Self{
|
||||
pub fn new(modes:Vec<Mode>)->Self{
|
||||
Self{
|
||||
modes,
|
||||
}
|
||||
}
|
||||
pub fn into_inner(self)->Vec<Mode>{
|
||||
self.modes
|
||||
}
|
||||
pub fn push_mode(&mut self,mode:Mode){
|
||||
self.modes.push(mode)
|
||||
}
|
||||
@ -328,4 +272,4 @@ impl Updatable<ModesUpdate> for Modes{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,52 +1,225 @@
|
||||
const VALVE_SCALE:Planar64=Planar64::raw(1<<28);// 1/16
|
||||
|
||||
use crate::integer::{Time,Ratio64,Planar64,Planar64Vec3};
|
||||
use crate::controls_bitflag::Controls;
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct StyleModifiers{
|
||||
//controls which are allowed to pass into gameplay (usually all)
|
||||
pub controls_mask:Controls,
|
||||
//controls which are masked from control state (e.g. !jump in scroll style)
|
||||
pub controls_mask_state:Controls,
|
||||
//strafing
|
||||
pub controls_used:u32,//controls which are allowed to pass into gameplay
|
||||
pub controls_mask:u32,//controls which are masked from control state (e.g. jump in scroll style)
|
||||
pub strafe:Option<StrafeSettings>,
|
||||
//player gets a controllable rocket force
|
||||
pub rocket:Option<PropulsionSettings>,
|
||||
//flying
|
||||
//pub move_type:MoveType::Fly(FlySettings)
|
||||
//MoveType::Physics(PhysicsSettings) -> PhysicsSettings (strafe,rocket,jump,walk,ladder,swim,gravity)
|
||||
//jumping is allowed
|
||||
pub jump:Option<JumpSettings>,
|
||||
//standing & walking is allowed
|
||||
pub walk:Option<WalkSettings>,
|
||||
//laddering is allowed
|
||||
pub ladder:Option<LadderSettings>,
|
||||
//water propulsion
|
||||
pub swim:Option<PropulsionSettings>,
|
||||
//maximum slope before sloped surfaces become frictionless
|
||||
pub gravity:Planar64Vec3,
|
||||
//hitbox
|
||||
pub hitbox:Hitbox,
|
||||
//camera location relative to the center (0,0,0) of the hitbox
|
||||
pub camera_offset:Planar64Vec3,
|
||||
//unused
|
||||
pub jump_impulse:JumpImpulse,
|
||||
pub jump_calculation:JumpCalculation,
|
||||
pub static_friction:Planar64,
|
||||
pub kinetic_friction:Planar64,
|
||||
pub walk_speed:Planar64,
|
||||
pub walk_accel:Planar64,
|
||||
pub ladder_speed:Planar64,
|
||||
pub ladder_accel:Planar64,
|
||||
pub ladder_dot:Planar64,
|
||||
pub swim_speed:Planar64,
|
||||
pub mass:Planar64,
|
||||
pub mv:Planar64,
|
||||
pub surf_slope:Option<Planar64>,
|
||||
pub rocket_force:Option<Planar64>,
|
||||
pub gravity:Planar64Vec3,
|
||||
pub hitbox:Hitbox,
|
||||
pub camera_offset:Planar64Vec3,
|
||||
}
|
||||
impl std::default::Default for StyleModifiers{
|
||||
fn default()->Self{
|
||||
Self::roblox_bhop()
|
||||
}
|
||||
}
|
||||
impl StyleModifiers{
|
||||
pub const CONTROL_MOVEFORWARD:u32=0b00000001;
|
||||
pub const CONTROL_MOVEBACK:u32=0b00000010;
|
||||
pub const CONTROL_MOVERIGHT:u32=0b00000100;
|
||||
pub const CONTROL_MOVELEFT:u32=0b00001000;
|
||||
pub const CONTROL_MOVEUP:u32=0b00010000;
|
||||
pub const CONTROL_MOVEDOWN:u32=0b00100000;
|
||||
pub const CONTROL_JUMP:u32=0b01000000;
|
||||
pub const CONTROL_ZOOM:u32=0b10000000;
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub const RIGHT_DIR:Planar64Vec3=Planar64Vec3::X;
|
||||
pub const UP_DIR:Planar64Vec3=Planar64Vec3::Y;
|
||||
pub const FORWARD_DIR:Planar64Vec3=Planar64Vec3::NEG_Z;
|
||||
|
||||
fn neo()->Self{
|
||||
Self{
|
||||
controls_used:!0,
|
||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:EnableStrafe::Always,
|
||||
air_accel_limit:None,
|
||||
tick_rate:Ratio64::new(64,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump_impulse:JumpImpulse::FromEnergy(Planar64::int(512)),
|
||||
jump_calculation:JumpCalculation::Energy,
|
||||
gravity:Planar64Vec3::int(0,-80,0),
|
||||
static_friction:Planar64::int(2),
|
||||
kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
|
||||
mass:Planar64::int(1),
|
||||
mv:Planar64::int(3),
|
||||
rocket_force:None,
|
||||
walk_speed:Planar64::int(16),
|
||||
walk_accel:Planar64::int(80),
|
||||
ladder_speed:Planar64::int(16),
|
||||
ladder_accel:Planar64::int(160),
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(7)/8),
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn roblox_bhop()->Self{
|
||||
Self{
|
||||
controls_used:!0,
|
||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:EnableStrafe::Always,
|
||||
air_accel_limit:None,
|
||||
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump_impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
|
||||
jump_calculation:JumpCalculation::Capped,
|
||||
gravity:Planar64Vec3::int(0,-100,0),
|
||||
static_friction:Planar64::int(2),
|
||||
kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
|
||||
mass:Planar64::int(1),
|
||||
mv:Planar64::int(27)/10,
|
||||
rocket_force:None,
|
||||
walk_speed:Planar64::int(18),
|
||||
walk_accel:Planar64::int(90),
|
||||
ladder_speed:Planar64::int(18),
|
||||
ladder_accel:Planar64::int(180),
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
fn roblox_surf()->Self{
|
||||
Self{
|
||||
controls_used:!0,
|
||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:EnableStrafe::Always,
|
||||
air_accel_limit:None,
|
||||
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump_impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
|
||||
jump_calculation:JumpCalculation::Capped,
|
||||
gravity:Planar64Vec3::int(0,-50,0),
|
||||
static_friction:Planar64::int(2),
|
||||
kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
|
||||
mass:Planar64::int(1),
|
||||
mv:Planar64::int(27)/10,
|
||||
rocket_force:None,
|
||||
walk_speed:Planar64::int(18),
|
||||
walk_accel:Planar64::int(90),
|
||||
ladder_speed:Planar64::int(18),
|
||||
ladder_accel:Planar64::int(180),
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
|
||||
fn source_bhop()->Self{
|
||||
Self{
|
||||
controls_used:!0,
|
||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:EnableStrafe::Always,
|
||||
air_accel_limit:Some(Planar64::raw(150<<28)*100),
|
||||
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
|
||||
jump_calculation:JumpCalculation::Linear,
|
||||
gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
|
||||
static_friction:Planar64::int(2),//?
|
||||
kinetic_friction:Planar64::int(3),//?
|
||||
mass:Planar64::int(1),
|
||||
mv:Planar64::raw(30)*VALVE_SCALE,
|
||||
rocket_force:None,
|
||||
walk_speed:Planar64::int(18),//?
|
||||
walk_accel:Planar64::int(90),//?
|
||||
ladder_speed:Planar64::int(18),//?
|
||||
ladder_accel:Planar64::int(180),//?
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),//?
|
||||
swim_speed:Planar64::int(12),//?
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox:Hitbox::source(),
|
||||
camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
|
||||
}
|
||||
}
|
||||
fn source_surf()->Self{
|
||||
Self{
|
||||
controls_used:!0,
|
||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:EnableStrafe::Always,
|
||||
air_accel_limit:Some(Planar64::int(150)*66*VALVE_SCALE),
|
||||
tick_rate:Ratio64::new(66,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
|
||||
jump_calculation:JumpCalculation::Linear,
|
||||
gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
|
||||
static_friction:Planar64::int(2),//?
|
||||
kinetic_friction:Planar64::int(3),//?
|
||||
mass:Planar64::int(1),
|
||||
mv:Planar64::int(30)*VALVE_SCALE,
|
||||
rocket_force:None,
|
||||
walk_speed:Planar64::int(18),//?
|
||||
walk_accel:Planar64::int(90),//?
|
||||
ladder_speed:Planar64::int(18),//?
|
||||
ladder_accel:Planar64::int(180),//?
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),//?
|
||||
swim_speed:Planar64::int(12),//?
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox:Hitbox::source(),
|
||||
camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
|
||||
}
|
||||
}
|
||||
fn roblox_rocket()->Self{
|
||||
Self{
|
||||
controls_used:!0,
|
||||
controls_mask:!0,
|
||||
strafe:None,
|
||||
jump_impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
|
||||
jump_calculation:JumpCalculation::Capped,
|
||||
gravity:Planar64Vec3::int(0,-100,0),
|
||||
static_friction:Planar64::int(2),
|
||||
kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
|
||||
mass:Planar64::int(1),
|
||||
mv:Planar64::int(27)/10,
|
||||
rocket_force:Some(Planar64::int(200)),
|
||||
walk_speed:Planar64::int(18),
|
||||
walk_accel:Planar64::int(90),
|
||||
ladder_speed:Planar64::int(18),
|
||||
ladder_accel:Planar64::int(180),
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum JumpCalculation{
|
||||
Capped,//roblox
|
||||
Energy,//new
|
||||
Linear,//source
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
#[derive(Clone)]
|
||||
pub enum JumpImpulse{
|
||||
FromTime(Time),//jump time is invariant across mass and gravity changes
|
||||
FromHeight(Planar64),//jump height is invariant across mass and gravity changes
|
||||
@ -57,329 +230,35 @@ pub enum JumpImpulse{
|
||||
//Capped means it increases the dot to the cap
|
||||
//Energy means it adds energy
|
||||
//Linear means it linearly adds on
|
||||
impl JumpImpulse{
|
||||
//fn get_jump_time(&self)->Planar64
|
||||
//fn get_jump_height(&self)->Planar64
|
||||
//fn get_jump_energy(&self)->Planar64
|
||||
pub fn get_jump_deltav(&self,gravity:&Planar64Vec3,mass:Planar64)->Planar64{
|
||||
//gravity.length() is actually the proper calculation because the jump is always opposite the gravity direction
|
||||
match self{
|
||||
&JumpImpulse::FromTime(time)=>gravity.length()*(time/2),
|
||||
&JumpImpulse::FromHeight(height)=>(gravity.length()*height*2).sqrt(),
|
||||
&JumpImpulse::FromDeltaV(deltav)=>deltav,
|
||||
&JumpImpulse::FromEnergy(energy)=>(energy*2/mass).sqrt(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ControlsActivation{
|
||||
//allowed keys
|
||||
controls_mask:Controls,
|
||||
//allow strafing only if any of the masked controls are held, eg W|S for shsw
|
||||
controls_intersects:Controls,
|
||||
//allow strafing only if all of the masked controls are held, eg W for hsw, w-only
|
||||
controls_contains:Controls,
|
||||
#[derive(Clone)]
|
||||
pub enum EnableStrafe{
|
||||
Always,
|
||||
MaskAny(u32),//hsw, shsw
|
||||
MaskAll(u32),
|
||||
//Function(Box<dyn Fn(u32)->bool>),
|
||||
}
|
||||
impl ControlsActivation{
|
||||
pub const fn new(
|
||||
controls_mask:Controls,
|
||||
controls_intersects:Controls,
|
||||
controls_contains:Controls,
|
||||
)->Self{
|
||||
Self{
|
||||
controls_mask,
|
||||
controls_intersects,
|
||||
controls_contains,
|
||||
}
|
||||
}
|
||||
pub const fn controls_mask(&self)->Controls{
|
||||
self.controls_mask
|
||||
}
|
||||
pub const fn controls_intersects(&self)->Controls{
|
||||
self.controls_intersects
|
||||
}
|
||||
pub const fn controls_contains(&self)->Controls{
|
||||
self.controls_contains
|
||||
}
|
||||
pub const fn mask(&self,controls:Controls)->Controls{
|
||||
controls.intersection(self.controls_mask)
|
||||
}
|
||||
pub const fn activates(&self,controls:Controls)->bool{
|
||||
(self.controls_intersects.is_empty()||controls.intersects(self.controls_intersects))
|
||||
&&controls.contains(self.controls_contains)
|
||||
}
|
||||
pub const fn full_3d()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::wasdqe(),
|
||||
controls_intersects:Controls::wasdqe(),
|
||||
controls_contains:Controls::empty(),
|
||||
}
|
||||
}
|
||||
//classical styles
|
||||
//Normal
|
||||
pub const fn full_2d()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::wasd(),
|
||||
controls_intersects:Controls::wasd(),
|
||||
controls_contains:Controls::empty(),
|
||||
}
|
||||
}
|
||||
//Sideways
|
||||
pub const fn sideways()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::MoveForward.union(Controls::MoveBackward),
|
||||
controls_intersects:Controls::MoveForward.union(Controls::MoveBackward),
|
||||
controls_contains:Controls::empty(),
|
||||
}
|
||||
}
|
||||
//Half-Sideways
|
||||
pub const fn half_sideways()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::MoveForward.union(Controls::MoveLeft).union(Controls::MoveRight),
|
||||
controls_intersects:Controls::MoveLeft.union(Controls::MoveRight),
|
||||
controls_contains:Controls::MoveForward,
|
||||
}
|
||||
}
|
||||
//Surf Half-Sideways
|
||||
pub const fn surf_half_sideways()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::MoveForward.union(Controls::MoveBackward).union(Controls::MoveLeft).union(Controls::MoveRight),
|
||||
controls_intersects:Controls::MoveForward.union(Controls::MoveBackward),
|
||||
controls_contains:Controls::empty(),
|
||||
}
|
||||
}
|
||||
//W-Only
|
||||
pub const fn w_only()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::MoveForward,
|
||||
controls_intersects:Controls::empty(),
|
||||
controls_contains:Controls::MoveForward,
|
||||
}
|
||||
}
|
||||
//A-Only
|
||||
pub const fn a_only()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::MoveLeft,
|
||||
controls_intersects:Controls::empty(),
|
||||
controls_contains:Controls::MoveLeft,
|
||||
}
|
||||
}
|
||||
//Backwards
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct StrafeSettings{
|
||||
enable:ControlsActivation,
|
||||
mv:Planar64,
|
||||
enable:EnableStrafe,
|
||||
air_accel_limit:Option<Planar64>,
|
||||
tick_rate:Ratio64,
|
||||
}
|
||||
impl StrafeSettings{
|
||||
pub const fn new(
|
||||
enable:ControlsActivation,
|
||||
mv:Planar64,
|
||||
air_accel_limit:Option<Planar64>,
|
||||
tick_rate:Ratio64,
|
||||
)->Self{
|
||||
Self{enable,mv,air_accel_limit,tick_rate}
|
||||
}
|
||||
pub fn into_inner(self)->(ControlsActivation,Planar64,Option<Planar64>,Ratio64){
|
||||
(self.enable,self.mv,self.air_accel_limit,self.tick_rate)
|
||||
}
|
||||
pub fn tick_velocity(&self,velocity:Planar64Vec3,control_dir:Planar64Vec3)->Option<Planar64Vec3>{
|
||||
let d=velocity.dot(control_dir);
|
||||
match d<self.mv{
|
||||
true=>Some(velocity+control_dir*self.air_accel_limit.map_or(self.mv-d,|limit|limit.min(self.mv-d))),
|
||||
false=>None,
|
||||
}
|
||||
}
|
||||
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 const fn activates(&self,controls:Controls)->bool{
|
||||
self.enable.activates(controls)
|
||||
}
|
||||
pub const fn mask(&self,controls:Controls)->Controls{
|
||||
self.enable.mask(controls)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct PropulsionSettings{
|
||||
magnitude:Planar64,
|
||||
}
|
||||
impl PropulsionSettings{
|
||||
pub const fn new(magnitude:Planar64)->Self{
|
||||
Self{magnitude}
|
||||
}
|
||||
pub fn magnitude(&self)->Planar64{
|
||||
self.magnitude
|
||||
}
|
||||
pub fn acceleration(&self,control_dir:Planar64Vec3)->Planar64Vec3{
|
||||
control_dir*self.magnitude
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct JumpSettings{
|
||||
//information used to calculate jump power
|
||||
impulse:JumpImpulse,
|
||||
//information used to calculate jump behaviour
|
||||
calculation:JumpCalculation,
|
||||
}
|
||||
impl JumpSettings{
|
||||
pub const fn new(
|
||||
impulse:JumpImpulse,
|
||||
calculation:JumpCalculation,
|
||||
)->Self{
|
||||
Self{impulse,calculation}
|
||||
}
|
||||
pub fn into_inner(self)->(JumpImpulse,JumpCalculation){
|
||||
(self.impulse,self.calculation)
|
||||
}
|
||||
pub fn jumped_velocity(&self,style:&StyleModifiers,jump_dir:Planar64Vec3,velocity:Planar64Vec3)->Planar64Vec3{
|
||||
match self.calculation{
|
||||
//roblox style
|
||||
JumpCalculation::Capped=>todo!(),
|
||||
//something different
|
||||
JumpCalculation::Energy=>todo!(),
|
||||
//source style
|
||||
JumpCalculation::Linear=>velocity+jump_dir*(self.impulse.get_jump_deltav(&style.gravity,style.mass)/jump_dir.length()),
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct AccelerateSettings{
|
||||
accel:Planar64,
|
||||
topspeed:Planar64,
|
||||
}
|
||||
impl AccelerateSettings{
|
||||
pub const fn new(
|
||||
accel:Planar64,
|
||||
topspeed:Planar64,
|
||||
)->Self{
|
||||
Self{accel,topspeed}
|
||||
}
|
||||
pub const fn accel(&self)->Planar64{
|
||||
self.accel
|
||||
}
|
||||
pub const fn topspeed(&self)->Planar64{
|
||||
self.topspeed
|
||||
}
|
||||
}
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct WalkSettings{
|
||||
accelerate:AccelerateSettings,
|
||||
static_friction:Planar64,
|
||||
kinetic_friction:Planar64,
|
||||
//if a surf slope angle does not exist, then everything is slippery and walking is impossible
|
||||
surf_dot:Planar64,//surf_dot<n.dot(up)/n.length()
|
||||
}
|
||||
impl WalkSettings{
|
||||
pub const fn new(
|
||||
accelerate:AccelerateSettings,
|
||||
static_friction:Planar64,
|
||||
kinetic_friction:Planar64,
|
||||
surf_dot:Planar64,
|
||||
)->Self{
|
||||
Self{accelerate,static_friction,kinetic_friction,surf_dot}
|
||||
}
|
||||
pub fn into_inner(self)->(AccelerateSettings,Planar64,Planar64,Planar64){
|
||||
(self.accelerate,self.static_friction,self.kinetic_friction,self.surf_dot)
|
||||
}
|
||||
pub fn accel(&self,target_diff:Planar64Vec3,gravity:Planar64Vec3)->Planar64{
|
||||
//TODO: fallible walk accel
|
||||
let diff_len=target_diff.length();
|
||||
let friction=if diff_len<self.accelerate.topspeed{
|
||||
self.static_friction
|
||||
}else{
|
||||
self.kinetic_friction
|
||||
};
|
||||
self.accelerate.accel.min(-Planar64Vec3::Y.dot(gravity)*friction)
|
||||
}
|
||||
pub fn get_walk_target_velocity(&self,control_dir:Planar64Vec3,normal:Planar64Vec3)->Planar64Vec3{
|
||||
if control_dir==Planar64Vec3::ZERO{
|
||||
return control_dir;
|
||||
}
|
||||
let n=normal.length();
|
||||
let m=control_dir.length();
|
||||
let d=normal.dot(control_dir)/m;
|
||||
if d<n{
|
||||
let cr=normal.cross(control_dir);
|
||||
if cr==Planar64Vec3::ZERO{
|
||||
Planar64Vec3::ZERO
|
||||
}else{
|
||||
cr.cross(normal)*(self.accelerate.topspeed/(n*(n*n-d*d).sqrt()*m))
|
||||
}
|
||||
}else{
|
||||
Planar64Vec3::ZERO
|
||||
}
|
||||
}
|
||||
pub fn is_slope_walkable(&self,normal:Planar64Vec3,up:Planar64Vec3)->bool{
|
||||
//normal is not guaranteed to be unit length
|
||||
let ny=normal.dot(up);
|
||||
let h=normal.length();
|
||||
//remember this is a normal vector
|
||||
Planar64::ZERO<ny&&h*self.surf_dot<ny
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct LadderSettings{
|
||||
accelerate:AccelerateSettings,
|
||||
//how close to pushing directly into/out of the ladder normal
|
||||
//does your input need to be to redirect straight up/down the ladder
|
||||
dot:Planar64,
|
||||
}
|
||||
impl LadderSettings{
|
||||
pub const fn new(
|
||||
accelerate:AccelerateSettings,
|
||||
dot:Planar64,
|
||||
)->Self{
|
||||
Self{accelerate,dot}
|
||||
}
|
||||
pub fn into_inner(self)->(AccelerateSettings,Planar64){
|
||||
(self.accelerate,self.dot)
|
||||
}
|
||||
pub const fn accel(&self,target_diff:Planar64Vec3,gravity:Planar64Vec3)->Planar64{
|
||||
//TODO: fallible ladder accel
|
||||
self.accelerate.accel
|
||||
}
|
||||
pub fn get_ladder_target_velocity(&self,mut control_dir:Planar64Vec3,normal:Planar64Vec3)->Planar64Vec3{
|
||||
if control_dir==Planar64Vec3::ZERO{
|
||||
return control_dir;
|
||||
}
|
||||
let n=normal.length();
|
||||
let m=control_dir.length();
|
||||
let mut d=normal.dot(control_dir)/m;
|
||||
if d< -self.dot*n{
|
||||
control_dir=Planar64Vec3::Y*m;
|
||||
d=normal.y();
|
||||
}else if self.dot*n<d{
|
||||
control_dir=Planar64Vec3::NEG_Y*m;
|
||||
d=-normal.y();
|
||||
}
|
||||
//n=d if you are standing on top of a ladder and press E.
|
||||
//two fixes:
|
||||
//- ladder movement is not allowed on walkable surfaces
|
||||
//- fix the underlying issue
|
||||
if d.get().unsigned_abs()<n.get().unsigned_abs(){
|
||||
let cr=normal.cross(control_dir);
|
||||
if cr==Planar64Vec3::ZERO{
|
||||
Planar64Vec3::ZERO
|
||||
}else{
|
||||
cr.cross(normal)*(self.accelerate.topspeed/(n*(n*n-d*d).sqrt()))
|
||||
}
|
||||
}else{
|
||||
Planar64Vec3::ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
#[derive(Clone)]
|
||||
pub enum HitboxMesh{
|
||||
Box,//source
|
||||
Cylinder,//roblox
|
||||
@ -389,206 +268,22 @@ pub enum HitboxMesh{
|
||||
//DualCone,
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct Hitbox{
|
||||
pub halfsize:Planar64Vec3,
|
||||
pub mesh:HitboxMesh,
|
||||
}
|
||||
impl Hitbox{
|
||||
pub fn roblox()->Self{
|
||||
fn roblox()->Self{
|
||||
Self{
|
||||
halfsize:Planar64Vec3::int(2,5,2)/2,
|
||||
mesh:HitboxMesh::Cylinder,
|
||||
}
|
||||
}
|
||||
pub fn source()->Self{
|
||||
fn source()->Self{
|
||||
Self{
|
||||
halfsize:Planar64Vec3::int(33,73,33)/2*VALVE_SCALE,
|
||||
halfsize:Planar64Vec3::raw(33,73,33)/2*VALVE_SCALE,
|
||||
mesh:HitboxMesh::Box,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleModifiers{
|
||||
pub const RIGHT_DIR:Planar64Vec3=Planar64Vec3::X;
|
||||
pub const UP_DIR:Planar64Vec3=Planar64Vec3::Y;
|
||||
pub const FORWARD_DIR:Planar64Vec3=Planar64Vec3::NEG_Z;
|
||||
|
||||
pub fn neo()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::all(),
|
||||
controls_mask_state:Controls::all(),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:ControlsActivation::full_2d(),
|
||||
air_accel_limit:None,
|
||||
mv:Planar64::int(3),
|
||||
tick_rate:Ratio64::new(64,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump:Some(JumpSettings{
|
||||
impulse:JumpImpulse::FromEnergy(Planar64::int(512)),
|
||||
calculation:JumpCalculation::Energy,
|
||||
}),
|
||||
gravity:Planar64Vec3::int(0,-80,0),
|
||||
mass:Planar64::int(1),
|
||||
rocket:None,
|
||||
walk:Some(WalkSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(16),
|
||||
accel:Planar64::int(80),
|
||||
},
|
||||
static_friction:Planar64::int(2),
|
||||
kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
|
||||
surf_dot:Planar64::int(3)/4,
|
||||
}),
|
||||
ladder:Some(LadderSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(16),
|
||||
accel:Planar64::int(160),
|
||||
},
|
||||
dot:(Planar64::int(1)/2).sqrt(),
|
||||
}),
|
||||
swim:Some(PropulsionSettings{
|
||||
magnitude:Planar64::int(12),
|
||||
}),
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn roblox_bhop()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::all(),
|
||||
controls_mask_state:Controls::all(),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:ControlsActivation::full_2d(),
|
||||
air_accel_limit:None,
|
||||
mv:Planar64::int(27)/10,
|
||||
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump:Some(JumpSettings{
|
||||
impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
|
||||
calculation:JumpCalculation::Linear,//Should be capped
|
||||
}),
|
||||
gravity:Planar64Vec3::int(0,-100,0),
|
||||
mass:Planar64::int(1),
|
||||
rocket:None,
|
||||
walk:Some(WalkSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(18),
|
||||
accel:Planar64::int(90),
|
||||
},
|
||||
static_friction:Planar64::int(2),
|
||||
kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
|
||||
surf_dot:Planar64::int(3)/4,// normal.y=0.75
|
||||
}),
|
||||
ladder:Some(LadderSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(18),
|
||||
accel:Planar64::int(180),
|
||||
},
|
||||
dot:(Planar64::int(1)/2).sqrt(),
|
||||
}),
|
||||
swim:Some(PropulsionSettings{
|
||||
magnitude:Planar64::int(12),
|
||||
}),
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
pub fn roblox_surf()->Self{
|
||||
Self{
|
||||
gravity:Planar64Vec3::int(0,-50,0),
|
||||
..Self::roblox_bhop()
|
||||
}
|
||||
}
|
||||
pub fn roblox_rocket()->Self{
|
||||
Self{
|
||||
strafe:None,
|
||||
rocket:Some(PropulsionSettings{
|
||||
magnitude:Planar64::int(200),
|
||||
}),
|
||||
..Self::roblox_bhop()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_bhop()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::all()-Controls::MoveUp-Controls::MoveDown,
|
||||
controls_mask_state:Controls::all(),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:ControlsActivation::full_2d(),
|
||||
air_accel_limit:Some(Planar64::raw(150<<28)*100),
|
||||
mv:Planar64::raw(30)*VALVE_SCALE,
|
||||
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump:Some(JumpSettings{
|
||||
impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
|
||||
calculation:JumpCalculation::Linear,
|
||||
}),
|
||||
gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
|
||||
mass:Planar64::int(1),
|
||||
rocket:None,
|
||||
walk:Some(WalkSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(18),//?
|
||||
accel:Planar64::int(90),//?
|
||||
},
|
||||
static_friction:Planar64::int(2),//?
|
||||
kinetic_friction:Planar64::int(3),//?
|
||||
surf_dot:Planar64::int(3)/4,// normal.y=0.75
|
||||
}),
|
||||
ladder:Some(LadderSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(18),//?
|
||||
accel:Planar64::int(180),//?
|
||||
},
|
||||
dot:(Planar64::int(1)/2).sqrt(),//?
|
||||
}),
|
||||
swim:Some(PropulsionSettings{
|
||||
magnitude:Planar64::int(12),//?
|
||||
}),
|
||||
hitbox:Hitbox::source(),
|
||||
camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
|
||||
}
|
||||
}
|
||||
pub fn source_surf()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::all()-Controls::MoveUp-Controls::MoveDown,
|
||||
controls_mask_state:Controls::all(),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:ControlsActivation::full_2d(),
|
||||
air_accel_limit:Some(Planar64::int(150)*66*VALVE_SCALE),
|
||||
mv:Planar64::int(30)*VALVE_SCALE,
|
||||
tick_rate:Ratio64::new(66,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump:Some(JumpSettings{
|
||||
impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
|
||||
calculation:JumpCalculation::Linear,
|
||||
}),
|
||||
gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
|
||||
mass:Planar64::int(1),
|
||||
rocket:None,
|
||||
walk:Some(WalkSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(18),//?
|
||||
accel:Planar64::int(90),//?
|
||||
},
|
||||
static_friction:Planar64::int(2),//?
|
||||
kinetic_friction:Planar64::int(3),//?
|
||||
surf_dot:Planar64::int(3)/4,// normal.y=0.75
|
||||
}),
|
||||
ladder:Some(LadderSettings{
|
||||
accelerate:AccelerateSettings{
|
||||
topspeed:Planar64::int(18),//?
|
||||
accel:Planar64::int(180),//?
|
||||
},
|
||||
dot:(Planar64::int(1)/2).sqrt(),//?
|
||||
}),
|
||||
swim:Some(PropulsionSettings{
|
||||
magnitude:Planar64::int(12),//?
|
||||
}),
|
||||
hitbox:Hitbox::source(),
|
||||
camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
106
src/integer.rs
106
src/integer.rs
@ -10,32 +10,24 @@ impl Time{
|
||||
pub const ONE_MICROSECOND:Self=Self(1_000);
|
||||
pub const ONE_NANOSECOND:Self=Self(1);
|
||||
#[inline]
|
||||
pub const fn raw(num:i64)->Self{
|
||||
Self(num)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn get(self)->i64{
|
||||
self.0
|
||||
}
|
||||
#[inline]
|
||||
pub const fn from_secs(num:i64)->Self{
|
||||
pub fn from_secs(num:i64)->Self{
|
||||
Self(Self::ONE_SECOND.0*num)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn from_millis(num:i64)->Self{
|
||||
pub fn from_millis(num:i64)->Self{
|
||||
Self(Self::ONE_MILLISECOND.0*num)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn from_micros(num:i64)->Self{
|
||||
pub fn from_micros(num:i64)->Self{
|
||||
Self(Self::ONE_MICROSECOND.0*num)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn from_nanos(num:i64)->Self{
|
||||
pub fn from_nanos(num:i64)->Self{
|
||||
Self(Self::ONE_NANOSECOND.0*num)
|
||||
}
|
||||
//should I have checked subtraction? force all time variables to be positive?
|
||||
#[inline]
|
||||
pub const fn nanos(self)->i64{
|
||||
pub fn nanos(&self)->i64{
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@ -99,7 +91,7 @@ const fn gcd(mut a:u64,mut b:u64)->u64{
|
||||
};
|
||||
a
|
||||
}
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
#[derive(Clone,Hash)]
|
||||
pub struct Ratio64{
|
||||
num:i64,
|
||||
den:u64,
|
||||
@ -117,23 +109,15 @@ impl Ratio64{
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn num(self)->i64{
|
||||
self.num
|
||||
}
|
||||
#[inline]
|
||||
pub const fn den(self)->u64{
|
||||
self.den
|
||||
}
|
||||
#[inline]
|
||||
pub const fn mul_int(&self,rhs:i64)->i64{
|
||||
pub fn mul_int(&self,rhs:i64)->i64{
|
||||
rhs*self.num/(self.den as i64)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn rhs_div_int(&self,rhs:i64)->i64{
|
||||
pub fn rhs_div_int(&self,rhs:i64)->i64{
|
||||
rhs*(self.den as i64)/self.num
|
||||
}
|
||||
#[inline]
|
||||
pub const fn mul_ref(&self,rhs:&Ratio64)->Ratio64{
|
||||
pub fn mul_ref(&self,rhs:&Ratio64)->Ratio64{
|
||||
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
||||
let d=gcd(num.unsigned_abs(),den);
|
||||
Self{
|
||||
@ -275,7 +259,7 @@ impl std::ops::Div<u64> for Ratio64{
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
#[derive(Clone,Hash)]
|
||||
pub struct Ratio64Vec2{
|
||||
pub x:Ratio64,
|
||||
pub y:Ratio64,
|
||||
@ -283,11 +267,11 @@ pub struct Ratio64Vec2{
|
||||
impl Ratio64Vec2{
|
||||
pub const ONE:Self=Self{x:Ratio64::ONE,y:Ratio64::ONE};
|
||||
#[inline]
|
||||
pub const fn new(x:Ratio64,y:Ratio64)->Self{
|
||||
pub fn new(x:Ratio64,y:Ratio64)->Self{
|
||||
Self{x,y}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn mul_int(&self,rhs:glam::I64Vec2)->glam::I64Vec2{
|
||||
pub fn mul_int(&self,rhs:glam::I64Vec2)->glam::I64Vec2{
|
||||
glam::i64vec2(
|
||||
self.x.mul_int(rhs.x),
|
||||
self.y.mul_int(rhs.y),
|
||||
@ -614,35 +598,23 @@ impl Planar64Vec3{
|
||||
Self(glam::i64vec3(x.0,y.0,z.0))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn get(self)->glam::I64Vec3{
|
||||
self.0
|
||||
}
|
||||
#[inline]
|
||||
pub const fn int(x:i32,y:i32,z:i32)->Self{
|
||||
Self(glam::i64vec3((x as i64)<<32,(y as i64)<<32,(z as i64)<<32))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn raw_xyz(x:i64,y:i64,z:i64)->Self{
|
||||
pub const fn raw(x:i64,y:i64,z:i64)->Self{
|
||||
Self(glam::i64vec3(x,y,z))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn raw_array(xyz:[i64;3])->Self{
|
||||
Self(glam::I64Vec3::from_array(xyz))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn raw(xyz:glam::I64Vec3)->Self{
|
||||
Self(xyz)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn x(&self)->Planar64{
|
||||
pub fn x(&self)->Planar64{
|
||||
Planar64(self.0.x)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn y(&self)->Planar64{
|
||||
pub fn y(&self)->Planar64{
|
||||
Planar64(self.0.y)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn z(&self)->Planar64{
|
||||
pub fn z(&self)->Planar64{
|
||||
Planar64(self.0.z)
|
||||
}
|
||||
#[inline]
|
||||
@ -670,7 +642,7 @@ impl Planar64Vec3{
|
||||
self.0.cmplt(rhs.0)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn dot(&self,rhs:Self)->Planar64{
|
||||
pub fn dot(&self,rhs:Self)->Planar64{
|
||||
Planar64(((
|
||||
(self.0.x as i128)*(rhs.0.x as i128)+
|
||||
(self.0.y as i128)*(rhs.0.y as i128)+
|
||||
@ -678,13 +650,13 @@ impl Planar64Vec3{
|
||||
)>>32) as i64)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn dot128(&self,rhs:Self)->i128{
|
||||
pub fn dot128(&self,rhs:Self)->i128{
|
||||
(self.0.x as i128)*(rhs.0.x as i128)+
|
||||
(self.0.y as i128)*(rhs.0.y as i128)+
|
||||
(self.0.z as i128)*(rhs.0.z as i128)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn cross(&self,rhs:Self)->Planar64Vec3{
|
||||
pub fn cross(&self,rhs:Self)->Planar64Vec3{
|
||||
Planar64Vec3(glam::i64vec3(
|
||||
(((self.0.y as i128)*(rhs.0.z as i128)-(self.0.z as i128)*(rhs.0.y as i128))>>32) as i64,
|
||||
(((self.0.z as i128)*(rhs.0.x as i128)-(self.0.x as i128)*(rhs.0.z as i128))>>32) as i64,
|
||||
@ -692,6 +664,12 @@ impl Planar64Vec3{
|
||||
))
|
||||
}
|
||||
#[inline]
|
||||
pub fn walkable(&self,slope:Planar64,up:Self)->bool{
|
||||
let y=self.dot(up);
|
||||
let x=self.cross(up).length();
|
||||
x*slope<y
|
||||
}
|
||||
#[inline]
|
||||
pub fn length(&self)->Planar64{
|
||||
let radicand=(self.0.x as i128)*(self.0.x as i128)+(self.0.y as i128)*(self.0.y as i128)+(self.0.z as i128)*(self.0.z as i128);
|
||||
Planar64(unsafe{(radicand as f64).sqrt().to_int_unchecked()})
|
||||
@ -852,9 +830,9 @@ impl std::ops::Div<i64> for Planar64Vec3{
|
||||
///[-1.0,1.0] = [-2^32,2^32]
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct Planar64Mat3{
|
||||
pub x_axis:Planar64Vec3,
|
||||
pub y_axis:Planar64Vec3,
|
||||
pub z_axis:Planar64Vec3,
|
||||
x_axis:Planar64Vec3,
|
||||
y_axis:Planar64Vec3,
|
||||
z_axis:Planar64Vec3,
|
||||
}
|
||||
impl Default for Planar64Mat3{
|
||||
#[inline]
|
||||
@ -868,7 +846,7 @@ impl Default for Planar64Mat3{
|
||||
}
|
||||
impl Planar64Mat3{
|
||||
#[inline]
|
||||
pub const fn from_cols(x_axis:Planar64Vec3,y_axis:Planar64Vec3,z_axis:Planar64Vec3)->Self{
|
||||
pub fn from_cols(x_axis:Planar64Vec3,y_axis:Planar64Vec3,z_axis:Planar64Vec3)->Self{
|
||||
Self{
|
||||
x_axis,
|
||||
y_axis,
|
||||
@ -885,9 +863,9 @@ impl Planar64Mat3{
|
||||
#[inline]
|
||||
pub const fn from_diagonal(diagonal:Planar64Vec3)->Self{
|
||||
Self{
|
||||
x_axis:Planar64Vec3::raw_xyz(diagonal.0.x,0,0),
|
||||
y_axis:Planar64Vec3::raw_xyz(0,diagonal.0.y,0),
|
||||
z_axis:Planar64Vec3::raw_xyz(0,0,diagonal.0.z),
|
||||
x_axis:Planar64Vec3::raw(diagonal.0.x,0,0),
|
||||
y_axis:Planar64Vec3::raw(0,diagonal.0.y,0),
|
||||
z_axis:Planar64Vec3::raw(0,0,diagonal.0.z),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
@ -931,25 +909,25 @@ impl Planar64Mat3{
|
||||
+self.x_axis.0.x as i128*self.y_axis.0.y as i128*self.z_axis.0.z as i128
|
||||
)>>32;
|
||||
Self{
|
||||
x_axis:Planar64Vec3::raw_xyz((((-(self.y_axis.0.z as i128*self.z_axis.0.y as i128)+self.y_axis.0.y as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((self.x_axis.0.z as i128*self.z_axis.0.y as i128-self.x_axis.0.y as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((-(self.x_axis.0.z as i128*self.y_axis.0.y as i128)+self.x_axis.0.y as i128*self.y_axis.0.z as i128)<<32)/det) as i64),
|
||||
y_axis:Planar64Vec3::raw_xyz((((self.y_axis.0.z as i128*self.z_axis.0.x as i128-self.y_axis.0.x as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((-(self.x_axis.0.z as i128*self.z_axis.0.x as i128)+self.x_axis.0.x as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((self.x_axis.0.z as i128*self.y_axis.0.x as i128-self.x_axis.0.x as i128*self.y_axis.0.z as i128)<<32)/det) as i64),
|
||||
z_axis:Planar64Vec3::raw_xyz((((-(self.y_axis.0.y as i128*self.z_axis.0.x as i128)+self.y_axis.0.x as i128*self.z_axis.0.y as i128)<<32)/det) as i64,(((self.x_axis.0.y as i128*self.z_axis.0.x as i128-self.x_axis.0.x as i128*self.z_axis.0.y as i128)<<32)/det) as i64,(((-(self.x_axis.0.y as i128*self.y_axis.0.x as i128)+self.x_axis.0.x as i128*self.y_axis.0.y as i128)<<32)/det) as i64),
|
||||
x_axis:Planar64Vec3::raw((((-(self.y_axis.0.z as i128*self.z_axis.0.y as i128)+self.y_axis.0.y as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((self.x_axis.0.z as i128*self.z_axis.0.y as i128-self.x_axis.0.y as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((-(self.x_axis.0.z as i128*self.y_axis.0.y as i128)+self.x_axis.0.y as i128*self.y_axis.0.z as i128)<<32)/det) as i64),
|
||||
y_axis:Planar64Vec3::raw((((self.y_axis.0.z as i128*self.z_axis.0.x as i128-self.y_axis.0.x as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((-(self.x_axis.0.z as i128*self.z_axis.0.x as i128)+self.x_axis.0.x as i128*self.z_axis.0.z as i128)<<32)/det) as i64,(((self.x_axis.0.z as i128*self.y_axis.0.x as i128-self.x_axis.0.x as i128*self.y_axis.0.z as i128)<<32)/det) as i64),
|
||||
z_axis:Planar64Vec3::raw((((-(self.y_axis.0.y as i128*self.z_axis.0.x as i128)+self.y_axis.0.x as i128*self.z_axis.0.y as i128)<<32)/det) as i64,(((self.x_axis.0.y as i128*self.z_axis.0.x as i128-self.x_axis.0.x as i128*self.z_axis.0.y as i128)<<32)/det) as i64,(((-(self.x_axis.0.y as i128*self.y_axis.0.x as i128)+self.x_axis.0.x as i128*self.y_axis.0.y as i128)<<32)/det) as i64),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn inverse_times_det(&self)->Self{
|
||||
Self{
|
||||
x_axis:Planar64Vec3::raw_xyz(((-(self.y_axis.0.z as i128*self.z_axis.0.y as i128)+self.y_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.z_axis.0.y as i128-self.x_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.y_axis.0.y as i128)+self.x_axis.0.y as i128*self.y_axis.0.z as i128)>>32) as i64),
|
||||
y_axis:Planar64Vec3::raw_xyz(((self.y_axis.0.z as i128*self.z_axis.0.x as i128-self.y_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.z_axis.0.x as i128)+self.x_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.y_axis.0.x as i128-self.x_axis.0.x as i128*self.y_axis.0.z as i128)>>32) as i64),
|
||||
z_axis:Planar64Vec3::raw_xyz(((-(self.y_axis.0.y as i128*self.z_axis.0.x as i128)+self.y_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((self.x_axis.0.y as i128*self.z_axis.0.x as i128-self.x_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((-(self.x_axis.0.y as i128*self.y_axis.0.x as i128)+self.x_axis.0.x as i128*self.y_axis.0.y as i128)>>32) as i64),
|
||||
x_axis:Planar64Vec3::raw(((-(self.y_axis.0.z as i128*self.z_axis.0.y as i128)+self.y_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.z_axis.0.y as i128-self.x_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.y_axis.0.y as i128)+self.x_axis.0.y as i128*self.y_axis.0.z as i128)>>32) as i64),
|
||||
y_axis:Planar64Vec3::raw(((self.y_axis.0.z as i128*self.z_axis.0.x as i128-self.y_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.z_axis.0.x as i128)+self.x_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.y_axis.0.x as i128-self.x_axis.0.x as i128*self.y_axis.0.z as i128)>>32) as i64),
|
||||
z_axis:Planar64Vec3::raw(((-(self.y_axis.0.y as i128*self.z_axis.0.x as i128)+self.y_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((self.x_axis.0.y as i128*self.z_axis.0.x as i128-self.x_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((-(self.x_axis.0.y as i128*self.y_axis.0.x as i128)+self.x_axis.0.x as i128*self.y_axis.0.y as i128)>>32) as i64),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn transpose(&self)->Self{
|
||||
Self{
|
||||
x_axis:Planar64Vec3::raw_xyz(self.x_axis.0.x,self.y_axis.0.x,self.z_axis.0.x),
|
||||
y_axis:Planar64Vec3::raw_xyz(self.x_axis.0.y,self.y_axis.0.y,self.z_axis.0.y),
|
||||
z_axis:Planar64Vec3::raw_xyz(self.x_axis.0.z,self.y_axis.0.z,self.z_axis.0.z),
|
||||
x_axis:Planar64Vec3::raw(self.x_axis.0.x,self.y_axis.0.x,self.z_axis.0.x),
|
||||
y_axis:Planar64Vec3::raw(self.x_axis.0.y,self.y_axis.0.y,self.z_axis.0.y),
|
||||
z_axis:Planar64Vec3::raw(self.x_axis.0.z,self.y_axis.0.z,self.z_axis.0.z),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
@ -1074,4 +1052,4 @@ fn test_sqrt(){
|
||||
assert_eq!(1717986918400,r.get());
|
||||
let s=r.sqrt();
|
||||
assert_eq!(85899345920,s.get());
|
||||
}
|
||||
}
|
@ -2,12 +2,10 @@ pub mod bvh;
|
||||
pub mod map;
|
||||
pub mod aabb;
|
||||
pub mod model;
|
||||
pub mod timer;
|
||||
pub mod zeroes;
|
||||
pub mod integer;
|
||||
pub mod updatable;
|
||||
pub mod instruction;
|
||||
pub mod gameplay_attributes;
|
||||
pub mod gameplay_modes;
|
||||
pub mod gameplay_style;
|
||||
pub mod controls_bitflag;
|
||||
pub mod gameplay_attributes;
|
@ -9,6 +9,5 @@ pub struct CompleteMap{
|
||||
pub meshes:Vec<model::Mesh>,
|
||||
pub models:Vec<model::Model>,
|
||||
//RenderPattern
|
||||
pub textures:Vec<Vec<u8>>,
|
||||
pub render_configs:Vec<model::RenderConfig>,
|
||||
}
|
||||
|
12
src/model.rs
12
src/model.rs
@ -27,7 +27,6 @@ pub trait PolygonIter{
|
||||
pub trait MapVertexId{
|
||||
fn map_vertex_id<F:Fn(VertexId)->VertexId>(self,f:F)->Self;
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct PolygonList(Vec<IndexedVertexList>);
|
||||
impl PolygonList{
|
||||
pub const fn new(list:Vec<IndexedVertexList>)->Self{
|
||||
@ -55,7 +54,6 @@ impl MapVertexId for PolygonList{
|
||||
// }
|
||||
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
|
||||
pub struct PolygonGroupId(u32);
|
||||
#[derive(Clone)]
|
||||
pub enum PolygonGroup{
|
||||
PolygonList(PolygonList),
|
||||
//TriangleStrip(TriangleStrip),
|
||||
@ -76,11 +74,11 @@ impl MapVertexId for PolygonGroup{
|
||||
}
|
||||
}
|
||||
/// Ah yes, a group of things to render at the same time
|
||||
#[derive(Clone,Copy,Debug,Hash,id::Id,Eq,PartialEq)]
|
||||
#[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(Clone,Copy,Default)]
|
||||
#[derive(Default)]
|
||||
pub struct RenderConfig{
|
||||
pub texture:Option<TextureId>,
|
||||
}
|
||||
@ -91,21 +89,19 @@ impl RenderConfig{
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct IndexedGraphicsGroup{
|
||||
//Render pattern material/texture/shader/flat color
|
||||
pub render:RenderConfigId,
|
||||
pub groups:Vec<PolygonGroupId>,
|
||||
}
|
||||
#[derive(Clone,Default)]
|
||||
#[derive(Default)]
|
||||
pub struct IndexedPhysicsGroup{
|
||||
//the polygons in this group are guaranteed to make a closed convex shape
|
||||
pub groups:Vec<PolygonGroupId>,
|
||||
}
|
||||
//This is a superset of PhysicsModel and GraphicsModel
|
||||
#[derive(Clone,Copy,Debug,Hash,id::Id,Eq,PartialEq)]
|
||||
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct MeshId(u32);
|
||||
#[derive(Clone)]
|
||||
pub struct Mesh{
|
||||
pub unique_pos:Vec<Planar64Vec3>,//Unit32Vec3
|
||||
pub unique_normal:Vec<Planar64Vec3>,//Unit32Vec3
|
||||
|
209
src/timer.rs
209
src/timer.rs
@ -1,209 +0,0 @@
|
||||
use crate::integer::{Time,Ratio64};
|
||||
|
||||
//this could be about half as long if I only had
|
||||
//scaled timers and just used a scale of 1
|
||||
//but I thought the concept of a timer that could
|
||||
//only be paused and not scaled was cool
|
||||
|
||||
trait TimerState:Copy{
|
||||
fn get_time(&self,time:Time)->Time;
|
||||
fn set_time(&mut self,time:Time,new_time:Time);
|
||||
fn get_offset(&self)->Time;
|
||||
fn set_offset(&mut self,offset:Time);
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct Scaled{
|
||||
scale:Ratio64,
|
||||
offset:Time,
|
||||
}
|
||||
impl Scaled{
|
||||
const fn identity()->Self{
|
||||
Self{scale:Ratio64::ONE,offset:Time::ZERO}
|
||||
}
|
||||
const fn with_scale(scale:Ratio64)->Self{
|
||||
Self{scale,offset:Time::ZERO}
|
||||
}
|
||||
const fn scale(&self,time:Time)->Time{
|
||||
Time::raw(self.scale.mul_int(time.get()))
|
||||
}
|
||||
const fn get_scale(&self)->Ratio64{
|
||||
self.scale
|
||||
}
|
||||
fn set_scale(&mut self,time:Time,new_scale:Ratio64){
|
||||
let new_time=self.get_time(time);
|
||||
self.scale=new_scale;
|
||||
self.set_time(time,new_time);
|
||||
}
|
||||
}
|
||||
impl TimerState for Scaled{
|
||||
fn get_time(&self,time:Time)->Time{
|
||||
self.scale(time)+self.offset
|
||||
}
|
||||
fn set_time(&mut self,time:Time,new_time:Time){
|
||||
self.offset=new_time-self.scale(time);
|
||||
}
|
||||
fn get_offset(&self)->Time{
|
||||
self.offset
|
||||
}
|
||||
fn set_offset(&mut self,offset:Time){
|
||||
self.offset=offset;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct Realtime{
|
||||
offset:Time,
|
||||
}
|
||||
impl Realtime{
|
||||
const fn identity()->Self{
|
||||
Self{offset:Time::ZERO}
|
||||
}
|
||||
}
|
||||
impl TimerState for Realtime{
|
||||
fn get_time(&self,time:Time)->Time{
|
||||
time+self.offset
|
||||
}
|
||||
fn set_time(&mut self,time:Time,new_time:Time){
|
||||
self.offset=new_time-time;
|
||||
}
|
||||
fn get_offset(&self)->Time{
|
||||
self.offset
|
||||
}
|
||||
fn set_offset(&mut self,offset:Time){
|
||||
self.offset=offset;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct Timer<T>{
|
||||
state:T,
|
||||
paused:bool,
|
||||
}
|
||||
|
||||
impl Timer<Realtime>{
|
||||
pub fn realtime(time:Time,new_time:Time)->Self{
|
||||
let mut timer=Self{
|
||||
state:Realtime::identity(),
|
||||
paused:false,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub fn realtime_paused(offset:Time)->Self{
|
||||
Self{
|
||||
state:Realtime{offset},
|
||||
paused:true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
AlreadyPaused,
|
||||
AlreadyUnpaused,
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
impl Timer<Scaled>{
|
||||
pub fn new(time:Time,new_time:Time,scale:Ratio64,paused:bool)->Self{
|
||||
let mut timer=Self{
|
||||
state:Scaled::with_scale(scale),
|
||||
paused,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub fn scaled(time:Time,new_time:Time,scale:Ratio64)->Self{
|
||||
let mut timer=Self{
|
||||
state:Scaled::with_scale(scale),
|
||||
paused:false,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub fn scaled_paused(time:Time,new_time:Time,scale:Ratio64)->Self{
|
||||
let mut timer=Self{
|
||||
state:Scaled::with_scale(scale),
|
||||
paused:true,
|
||||
};
|
||||
timer.set_time(time,new_time);
|
||||
timer
|
||||
}
|
||||
pub const fn get_scale(&self)->Ratio64{
|
||||
self.state.get_scale()
|
||||
}
|
||||
pub fn set_scale(&mut self,time:Time,new_scale:Ratio64){
|
||||
self.state.set_scale(time,new_scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:TimerState> Timer<T>{
|
||||
pub fn time(&self,time:Time)->Time{
|
||||
match self.paused{
|
||||
true=>self.state.get_offset(),
|
||||
false=>self.state.get_time(time),
|
||||
}
|
||||
}
|
||||
pub fn set_time(&mut self,time:Time,new_time:Time){
|
||||
match self.paused{
|
||||
true=>self.state.set_offset(new_time),
|
||||
false=>self.state.set_time(time,new_time),
|
||||
}
|
||||
}
|
||||
pub fn pause(&mut self,time:Time)->Result<(),Error>{
|
||||
match self.paused{
|
||||
true=>Err(Error::AlreadyPaused),
|
||||
false=>{
|
||||
let new_time=self.time(time);
|
||||
self.state.set_offset(new_time);
|
||||
self.paused=true;
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn unpause(&mut self,time:Time)->Result<(),Error>{
|
||||
match self.paused{
|
||||
true=>{
|
||||
let new_time=self.time(time);
|
||||
self.state.set_time(time,new_time);
|
||||
self.paused=false;
|
||||
Ok(())
|
||||
},
|
||||
false=>Err(Error::AlreadyUnpaused),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod test{
|
||||
use super::{Time,Timer,Error};
|
||||
macro_rules! sec {
|
||||
($s: expr) => {
|
||||
Time::from_secs($s)
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_timer()->Result<(),Error>{
|
||||
//create a paused timer that reads 0s
|
||||
let mut timer=Timer::realtime_paused(sec!(0));
|
||||
//the paused timer at 1 second should read 0s
|
||||
assert_eq!(timer.time(sec!(1)),sec!(0));
|
||||
|
||||
//unpause it after one second
|
||||
timer.unpause(sec!(1))?;
|
||||
//the timer at 6 seconds should read 5s
|
||||
assert_eq!(timer.time(sec!(6)),sec!(5));
|
||||
|
||||
//pause the timer after 11 seconds
|
||||
timer.pause(sec!(11))?;
|
||||
//the paused timer at 20 seconds should read 10s
|
||||
assert_eq!(timer.time(sec!(20)),sec!(10));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user