2023-10-18 02:12:25 +00:00
|
|
|
use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Affine3};
|
2023-09-27 09:12:20 +00:00
|
|
|
pub type TextureCoordinate=glam::Vec2;
|
|
|
|
pub type Color4=glam::Vec4;
|
2023-09-29 02:10:22 +00:00
|
|
|
#[derive(Clone,Hash,PartialEq,Eq)]
|
2023-09-28 00:24:25 +00:00
|
|
|
pub struct IndexedVertex{
|
|
|
|
pub pos:u32,
|
2023-09-28 22:43:10 +00:00
|
|
|
pub tex:u32,
|
2023-09-28 00:24:25 +00:00
|
|
|
pub normal:u32,
|
|
|
|
pub color:u32,
|
|
|
|
}
|
|
|
|
pub struct IndexedPolygon{
|
|
|
|
pub vertices:Vec<u32>,
|
|
|
|
}
|
|
|
|
pub struct IndexedGroup{
|
|
|
|
pub texture:Option<u32>,//RenderPattern? material/texture/shader/flat color
|
|
|
|
pub polys:Vec<IndexedPolygon>,
|
|
|
|
}
|
|
|
|
pub struct IndexedModel{
|
2023-09-27 09:12:20 +00:00
|
|
|
pub unique_pos:Vec<Planar64Vec3>,
|
|
|
|
pub unique_normal:Vec<Planar64Vec3>,
|
|
|
|
pub unique_tex:Vec<TextureCoordinate>,
|
|
|
|
pub unique_color:Vec<Color4>,
|
2023-09-28 00:24:25 +00:00
|
|
|
pub unique_vertices:Vec<IndexedVertex>,
|
|
|
|
pub groups: Vec<IndexedGroup>,
|
2023-09-29 02:10:22 +00:00
|
|
|
pub instances:Vec<ModelInstance>,
|
|
|
|
}
|
2023-09-28 00:24:25 +00:00
|
|
|
pub struct ModelInstance{
|
2023-10-03 23:34:54 +00:00
|
|
|
//pub id:u64,//this does not actually help with map fixes resimulating bots, they must always be resimulated
|
2023-09-27 09:12:20 +00:00
|
|
|
pub transform:Planar64Affine3,
|
|
|
|
pub color:Color4,//transparency is in here
|
2023-10-03 23:34:54 +00:00
|
|
|
pub attributes:CollisionAttributes,
|
2023-10-04 02:46:54 +00:00
|
|
|
pub temp_indexing:Vec<TempIndexedAttributes>,
|
|
|
|
}
|
|
|
|
impl std::default::Default for ModelInstance{
|
|
|
|
fn default() -> Self {
|
|
|
|
Self{
|
2023-09-27 09:12:20 +00:00
|
|
|
color:Color4::ONE,
|
2023-10-04 02:46:54 +00:00
|
|
|
transform:Default::default(),
|
|
|
|
attributes:Default::default(),
|
|
|
|
temp_indexing:Default::default(),
|
|
|
|
}
|
|
|
|
}
|
2023-09-22 22:21:13 +00:00
|
|
|
}
|
2023-09-28 00:24:25 +00:00
|
|
|
pub struct IndexedModelInstances{
|
|
|
|
pub textures:Vec<String>,//RenderPattern
|
|
|
|
pub models:Vec<IndexedModel>,
|
2023-10-03 23:34:54 +00:00
|
|
|
//may make this into an object later.
|
2023-10-04 02:42:07 +00:00
|
|
|
pub modes:Vec<ModeDescription>,
|
2023-09-27 09:12:20 +00:00
|
|
|
pub spawn_point:Planar64Vec3,
|
2023-09-23 02:41:27 +00:00
|
|
|
}
|
2023-10-03 05:45:20 +00:00
|
|
|
//stage description referencing flattened ids is spooky, but the map loading is meant to be deterministic.
|
2023-10-04 02:42:07 +00:00
|
|
|
pub struct ModeDescription{
|
2023-11-01 23:06:48 +00:00
|
|
|
//TODO: put "default" style modifiers in mode
|
|
|
|
//pub style:StyleModifiers,
|
2023-10-18 23:21:06 +00:00
|
|
|
pub start:usize,//start=model_id
|
|
|
|
pub spawns:Vec<usize>,//spawns[spawn_id]=model_id
|
2023-10-04 21:13:25 +00:00
|
|
|
pub spawn_from_stage_id:std::collections::HashMap::<u32,usize>,
|
|
|
|
pub ordered_checkpoint_from_checkpoint_id:std::collections::HashMap::<u32,usize>,
|
|
|
|
}
|
|
|
|
impl ModeDescription{
|
2023-10-18 23:21:06 +00:00
|
|
|
pub fn get_spawn_model_id(&self,stage_id:u32)->Option<&usize>{
|
|
|
|
self.spawns.get(*self.spawn_from_stage_id.get(&stage_id)?)
|
2023-10-04 21:13:25 +00:00
|
|
|
}
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-10-18 22:59:38 +00:00
|
|
|
//I don't want this code to exist!
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct TempAttrStart{
|
|
|
|
pub mode_id:u32,
|
|
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct TempAttrSpawn{
|
|
|
|
pub mode_id:u32,
|
|
|
|
pub stage_id:u32,
|
|
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct TempAttrWormhole{
|
|
|
|
pub wormhole_id:u32,
|
|
|
|
}
|
2023-10-04 02:46:54 +00:00
|
|
|
pub enum TempIndexedAttributes{
|
2023-10-18 22:59:38 +00:00
|
|
|
Start(TempAttrStart),
|
|
|
|
Spawn(TempAttrSpawn),
|
|
|
|
Wormhole(TempAttrWormhole),
|
2023-10-04 02:46:54 +00:00
|
|
|
}
|
2023-10-03 05:45:20 +00:00
|
|
|
|
|
|
|
//you have this effect while in contact
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub struct ContactingLadder{
|
|
|
|
pub sticky:bool
|
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-17 07:17:54 +00:00
|
|
|
pub enum ContactingBehaviour{
|
2023-11-02 01:02:21 +00:00
|
|
|
Surf,
|
2023-11-02 01:02:29 +00:00
|
|
|
Cling,//usable as a zipline, or other weird and wonderful things
|
2023-11-02 01:02:21 +00:00
|
|
|
Ladder(ContactingLadder),
|
|
|
|
Elastic(u32),//[1/2^32,1] 0=None (elasticity+1)/2^32
|
2023-10-17 07:17:54 +00:00
|
|
|
}
|
2023-10-03 05:45:20 +00:00
|
|
|
//you have this effect while intersecting
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub struct IntersectingWater{
|
2023-09-27 09:12:20 +00:00
|
|
|
pub viscosity:Planar64,
|
|
|
|
pub density:Planar64,
|
2023-11-03 23:16:44 +00:00
|
|
|
pub velocity:Planar64Vec3,
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-10-18 02:12:25 +00:00
|
|
|
//All models can be given these attributes
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-18 02:12:25 +00:00
|
|
|
pub struct GameMechanicAccelerator{
|
2023-09-27 09:12:20 +00:00
|
|
|
pub acceleration:Planar64Vec3
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-11-03 04:31:55 +00:00
|
|
|
pub enum GameMechanicBooster{
|
|
|
|
Affine(Planar64Affine3),//capable of SetVelocity,DotVelocity,normal booster,bouncy part,redirect velocity, and much more
|
|
|
|
Velocity(Planar64Vec3),//straight up boost velocity adds to your current velocity
|
|
|
|
Energy{direction:Planar64Vec3,energy:Planar64},//increase energy in direction
|
|
|
|
}
|
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-18 02:12:25 +00:00
|
|
|
pub enum TrajectoryChoice{
|
|
|
|
HighArcLongDuration,//underhand lob at target: less horizontal speed and more air time
|
|
|
|
LowArcShortDuration,//overhand throw at target: more horizontal speed and less air time
|
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-18 02:12:25 +00:00
|
|
|
pub enum GameMechanicSetTrajectory{
|
2023-11-03 04:31:55 +00:00
|
|
|
//Speed-type SetTrajectory
|
2023-10-18 02:12:25 +00:00
|
|
|
AirTime(Time),//air time (relative to gravity direction) is invariant across mass and gravity changes
|
|
|
|
Height(Planar64),//boost height (relative to gravity direction) is invariant across mass and gravity changes
|
2023-11-03 04:31:55 +00:00
|
|
|
DotVelocity{direction:Planar64Vec3,dot:Planar64},//set your velocity in a specific direction without touching other directions
|
|
|
|
//Velocity-type SetTrajectory
|
2023-10-18 02:12:25 +00:00
|
|
|
TargetPointTime{//launch on a trajectory that will land at a target point in a set amount of time
|
|
|
|
target_point:Planar64Vec3,
|
|
|
|
time:Time,//short time = fast and direct, long time = launch high in the air, negative time = wrong way
|
|
|
|
},
|
2023-11-02 01:18:26 +00:00
|
|
|
TargetPointSpeed{//launch at a fixed speed and land at a target point
|
2023-10-18 02:12:25 +00:00
|
|
|
target_point:Planar64Vec3,
|
|
|
|
speed:Planar64,//if speed is too low this will fail to reach the target. The closest-passing trajectory will be chosen instead
|
|
|
|
trajectory_choice:TrajectoryChoice,
|
|
|
|
},
|
|
|
|
Velocity(Planar64Vec3),//SetVelocity
|
2023-11-03 04:31:55 +00:00
|
|
|
}
|
|
|
|
impl GameMechanicSetTrajectory{
|
|
|
|
fn is_velocity(&self)->bool{
|
|
|
|
match self{
|
|
|
|
GameMechanicSetTrajectory::AirTime(_)
|
|
|
|
|GameMechanicSetTrajectory::Height(_)
|
|
|
|
|GameMechanicSetTrajectory::DotVelocity{direction:_,dot:_}=>false,
|
|
|
|
GameMechanicSetTrajectory::TargetPointTime{target_point:_,time:_}
|
|
|
|
|GameMechanicSetTrajectory::TargetPointSpeed{target_point:_,speed:_,trajectory_choice:_}
|
|
|
|
|GameMechanicSetTrajectory::Velocity(_)=>true,
|
|
|
|
}
|
|
|
|
}
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub enum ZoneBehaviour{
|
|
|
|
//Start is indexed
|
|
|
|
//Checkpoints are indexed
|
|
|
|
Finish,
|
|
|
|
Anitcheat,
|
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub struct GameMechanicZone{
|
|
|
|
pub mode_id:u32,
|
|
|
|
pub behaviour:ZoneBehaviour,
|
|
|
|
}
|
|
|
|
// enum TrapCondition{
|
2023-10-18 02:12:25 +00:00
|
|
|
// FasterThan(Planar64),
|
|
|
|
// SlowerThan(Planar64),
|
|
|
|
// InRange(Planar64,Planar64),
|
|
|
|
// OutsideRange(Planar64,Planar64),
|
2023-10-03 05:45:20 +00:00
|
|
|
// }
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub enum StageElementBehaviour{
|
2023-11-02 01:02:21 +00:00
|
|
|
//Spawn,//The behaviour of stepping on a spawn setting the spawnid
|
2023-11-03 23:16:50 +00:00
|
|
|
SpawnAt,//must be standing on top to get effect. except cancollide false
|
2023-11-02 01:02:21 +00:00
|
|
|
Trigger,
|
|
|
|
Teleport,
|
|
|
|
Platform,
|
2023-11-03 23:16:28 +00:00
|
|
|
//Checkpoint acts like a trigger if you haven't hit all the checkpoints yet.
|
|
|
|
//Note that all stage elements act like this for the next stage.
|
|
|
|
Checkpoint,
|
|
|
|
//OrderedCheckpoint. You must pass through all of these in ascending order.
|
2023-11-04 01:01:01 +00:00
|
|
|
//If you hit them out of order it acts like a trigger.
|
|
|
|
//Do not support backtracking at all for now.
|
|
|
|
Ordered{
|
|
|
|
checkpoint_id:u32,
|
|
|
|
},
|
2023-11-03 23:16:28 +00:00
|
|
|
//UnorderedCheckpoint. You must pass through all of these in any order.
|
|
|
|
Unordered,
|
|
|
|
//If you get reset by a jump limit
|
2023-11-02 01:02:21 +00:00
|
|
|
JumpLimit(u32),
|
|
|
|
//Speedtrap(TrapCondition),//Acts as a trigger with a speed condition
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub struct GameMechanicStageElement{
|
|
|
|
pub mode_id:u32,
|
|
|
|
pub stage_id:u32,//which spawn to send to
|
|
|
|
pub force:bool,//allow setting to lower spawn id i.e. 7->3
|
|
|
|
pub behaviour:StageElementBehaviour
|
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-15 00:56:35 +00:00
|
|
|
pub struct GameMechanicWormhole{
|
|
|
|
//destination does not need to be another wormhole
|
|
|
|
//this defines a one way portal to a destination model transform
|
|
|
|
//two of these can create a two way wormhole
|
|
|
|
pub destination_model_id:u32,
|
|
|
|
//(position,angles)*=origin.transform.inverse()*destination.transform
|
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
2023-10-15 00:56:35 +00:00
|
|
|
pub enum TeleportBehaviour{
|
|
|
|
StageElement(GameMechanicStageElement),
|
|
|
|
Wormhole(GameMechanicWormhole),
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-10-18 02:12:25 +00:00
|
|
|
//attributes listed in order of handling
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Default,Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub struct GameMechanicAttributes{
|
|
|
|
pub zone:Option<GameMechanicZone>,
|
2023-10-18 02:12:25 +00:00
|
|
|
pub booster:Option<GameMechanicBooster>,
|
|
|
|
pub trajectory:Option<GameMechanicSetTrajectory>,
|
2023-10-15 00:56:35 +00:00
|
|
|
pub teleport_behaviour:Option<TeleportBehaviour>,
|
2023-10-18 02:12:25 +00:00
|
|
|
pub accelerator:Option<GameMechanicAccelerator>,
|
|
|
|
}
|
|
|
|
impl GameMechanicAttributes{
|
|
|
|
pub fn any(&self)->bool{
|
2023-10-28 23:38:16 +00:00
|
|
|
self.zone.is_some()
|
|
|
|
||self.booster.is_some()
|
2023-10-18 02:12:25 +00:00
|
|
|
||self.trajectory.is_some()
|
|
|
|
||self.teleport_behaviour.is_some()
|
|
|
|
||self.accelerator.is_some()
|
|
|
|
}
|
2023-11-03 04:31:55 +00:00
|
|
|
pub fn is_wrcp(&self,current_mode_id:u32)->bool{
|
|
|
|
self.trajectory.as_ref().map_or(false,|t|t.is_velocity())
|
|
|
|
&&match &self.teleport_behaviour{
|
|
|
|
Some(TeleportBehaviour::StageElement(
|
|
|
|
GameMechanicStageElement{
|
|
|
|
mode_id,
|
|
|
|
stage_id:_,
|
|
|
|
force:true,
|
|
|
|
behaviour:StageElementBehaviour::Trigger|StageElementBehaviour::Teleport
|
|
|
|
}
|
|
|
|
))=>current_mode_id==*mode_id,
|
|
|
|
_=>false,
|
|
|
|
}
|
|
|
|
}
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Default,Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub struct ContactingAttributes{
|
|
|
|
//friction?
|
2023-10-17 07:17:54 +00:00
|
|
|
pub contact_behaviour:Option<ContactingBehaviour>,
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
2023-10-18 02:12:25 +00:00
|
|
|
impl ContactingAttributes{
|
|
|
|
pub fn any(&self)->bool{
|
|
|
|
self.contact_behaviour.is_some()
|
|
|
|
}
|
|
|
|
}
|
2023-11-02 23:44:14 +00:00
|
|
|
#[derive(Default,Clone,Hash,Eq,PartialEq)]
|
2023-10-03 05:45:20 +00:00
|
|
|
pub struct IntersectingAttributes{
|
|
|
|
pub water:Option<IntersectingWater>,
|
2023-10-18 02:12:25 +00:00
|
|
|
}
|
|
|
|
impl IntersectingAttributes{
|
|
|
|
pub fn any(&self)->bool{
|
|
|
|
self.water.is_some()
|
|
|
|
}
|
2023-10-03 05:45:20 +00:00
|
|
|
}
|
|
|
|
//Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes
|
2023-11-01 04:42:42 +00:00
|
|
|
//TODO: deduplicate attributes
|
2023-10-03 05:45:20 +00:00
|
|
|
pub enum CollisionAttributes{
|
|
|
|
Decoration,//visual only
|
|
|
|
Contact{//track whether you are contacting the object
|
|
|
|
contacting:ContactingAttributes,
|
|
|
|
general:GameMechanicAttributes,
|
|
|
|
},
|
|
|
|
Intersect{//track whether you are intersecting the object
|
|
|
|
intersecting:IntersectingAttributes,
|
|
|
|
general:GameMechanicAttributes,
|
|
|
|
},
|
|
|
|
}
|
2023-10-04 02:45:01 +00:00
|
|
|
impl std::default::Default for CollisionAttributes{
|
|
|
|
fn default() -> Self {
|
2023-10-03 23:34:54 +00:00
|
|
|
Self::Contact{
|
|
|
|
contacting:ContactingAttributes::default(),
|
|
|
|
general:GameMechanicAttributes::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-23 02:41:27 +00:00
|
|
|
|
2023-09-27 09:12:20 +00:00
|
|
|
pub fn generate_indexed_model_list_from_obj(data:obj::ObjData,color:Color4)->Vec<IndexedModel>{
|
2023-09-28 00:24:25 +00:00
|
|
|
let mut unique_vertex_index = std::collections::HashMap::<obj::IndexTuple,u32>::new();
|
|
|
|
return data.objects.iter().map(|object|{
|
|
|
|
unique_vertex_index.clear();
|
|
|
|
let mut unique_vertices = Vec::new();
|
|
|
|
let groups = object.groups.iter().map(|group|{
|
|
|
|
IndexedGroup{
|
|
|
|
texture:None,
|
|
|
|
polys:group.polys.iter().map(|poly|{
|
|
|
|
IndexedPolygon{
|
|
|
|
vertices:poly.0.iter().map(|&tup|{
|
|
|
|
if let Some(&i)=unique_vertex_index.get(&tup){
|
|
|
|
i
|
|
|
|
}else{
|
|
|
|
let i=unique_vertices.len() as u32;
|
|
|
|
unique_vertices.push(IndexedVertex{
|
|
|
|
pos: tup.0 as u32,
|
2023-09-28 22:43:10 +00:00
|
|
|
tex: tup.1.unwrap() as u32,
|
2023-09-28 00:24:25 +00:00
|
|
|
normal: tup.2.unwrap() as u32,
|
|
|
|
color: 0,
|
|
|
|
});
|
|
|
|
unique_vertex_index.insert(tup,i);
|
|
|
|
i
|
|
|
|
}
|
|
|
|
}).collect()
|
2023-09-23 02:41:27 +00:00
|
|
|
}
|
2023-09-28 00:24:25 +00:00
|
|
|
}).collect()
|
2023-09-23 02:41:27 +00:00
|
|
|
}
|
2023-09-28 00:24:25 +00:00
|
|
|
}).collect();
|
|
|
|
IndexedModel{
|
2023-09-27 09:12:20 +00:00
|
|
|
unique_pos: data.position.iter().map(|&v|Planar64Vec3::try_from(v).unwrap()).collect(),
|
|
|
|
unique_tex: data.texture.iter().map(|&v|TextureCoordinate::from_array(v)).collect(),
|
|
|
|
unique_normal: data.normal.iter().map(|&v|Planar64Vec3::try_from(v).unwrap()).collect(),
|
2023-09-28 00:24:25 +00:00
|
|
|
unique_color: vec![color],
|
|
|
|
unique_vertices,
|
|
|
|
groups,
|
2023-09-29 02:10:22 +00:00
|
|
|
instances:Vec::new(),
|
2023-09-23 02:41:27 +00:00
|
|
|
}
|
2023-09-28 00:24:25 +00:00
|
|
|
}).collect()
|
|
|
|
}
|