Compare commits
4 Commits
0d2c27f60f
...
451808f9af
Author | SHA1 | Date | |
---|---|---|---|
451808f9af | |||
2cc7d76a48 | |||
56859d4e0c | |||
20bbb6924e |
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -410,7 +410,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "strafesnet_common"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.itzana.me/StrafesNET/common?rev=434ca29aef7e3015c9ca1ed45de8fef42e33fdfb#434ca29aef7e3015c9ca1ed45de8fef42e33fdfb"
|
||||
source = "git+https://git.itzana.me/StrafesNET/common?rev=5ee826d9487b5e2bea4b3cf99a68ce9a95d72f72#5ee826d9487b5e2bea4b3cf99a68ce9a95d72f72"
|
||||
dependencies = [
|
||||
"glam",
|
||||
]
|
||||
|
@ -12,4 +12,4 @@ rbx_binary = "0.7.4"
|
||||
rbx_dom_weak = "2.7.0"
|
||||
rbx_reflection_database = "0.2.10"
|
||||
rbx_xml = "0.13.3"
|
||||
strafesnet_common = { git = "https://git.itzana.me/StrafesNET/common", rev = "434ca29aef7e3015c9ca1ed45de8fef42e33fdfb" }
|
||||
strafesnet_common = { git = "https://git.itzana.me/StrafesNET/common", rev = "5ee826d9487b5e2bea4b3cf99a68ce9a95d72f72" }
|
||||
|
@ -126,7 +126,7 @@ const CORNERWEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[
|
||||
Planar64Vec3::int( 0,-1, 0),//CornerWedge::Bottom
|
||||
Planar64Vec3::int( 0, 0,-1),//CornerWedge::Front
|
||||
];
|
||||
pub fn unit_sphere()->crate::model::IndexedModel{
|
||||
pub fn unit_sphere()->IndexedModel{
|
||||
unit_cube()
|
||||
}
|
||||
#[derive(Default)]
|
||||
@ -139,7 +139,7 @@ impl CubeFaceDescription{
|
||||
self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u)))
|
||||
}
|
||||
}
|
||||
pub fn unit_cube()->crate::model::IndexedModel{
|
||||
pub fn unit_cube()->IndexedModel{
|
||||
let mut t=CubeFaceDescription::default();
|
||||
t.insert(CubeFace::Right,FaceDescription::default());
|
||||
t.insert(CubeFace::Top,FaceDescription::default());
|
||||
@ -149,7 +149,7 @@ pub fn unit_cube()->crate::model::IndexedModel{
|
||||
t.insert(CubeFace::Front,FaceDescription::default());
|
||||
generate_partial_unit_cube(t)
|
||||
}
|
||||
pub fn unit_cylinder()->crate::model::IndexedModel{
|
||||
pub fn unit_cylinder()->IndexedModel{
|
||||
unit_cube()
|
||||
}
|
||||
#[derive(Default)]
|
||||
@ -162,7 +162,7 @@ impl WedgeFaceDescription{
|
||||
self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u)))
|
||||
}
|
||||
}
|
||||
pub fn unit_wedge()->crate::model::IndexedModel{
|
||||
pub fn unit_wedge()->IndexedModel{
|
||||
let mut t=WedgeFaceDescription::default();
|
||||
t.insert(WedgeFace::Right,FaceDescription::default());
|
||||
t.insert(WedgeFace::TopFront,FaceDescription::default());
|
||||
@ -181,7 +181,7 @@ impl CornerWedgeFaceDescription{
|
||||
self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u)))
|
||||
}
|
||||
}
|
||||
pub fn unit_cornerwedge()->crate::model::IndexedModel{
|
||||
pub fn unit_cornerwedge()->IndexedModel{
|
||||
let mut t=CornerWedgeFaceDescription::default();
|
||||
t.insert(CornerWedgeFace::Right,FaceDescription::default());
|
||||
t.insert(CornerWedgeFace::TopBack,FaceDescription::default());
|
||||
@ -208,7 +208,7 @@ impl std::default::Default for FaceDescription{
|
||||
}
|
||||
//TODO: it's probably better to use a shared vertex buffer between all primitives and use indexed rendering instead of generating a unique vertex buffer for each primitive.
|
||||
//implementation: put all roblox primitives into one model.groups <- this won't work but I forget why
|
||||
pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->crate::model::IndexedModel{
|
||||
pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->IndexedModel{
|
||||
let mut generated_pos=Vec::new();
|
||||
let mut generated_tex=Vec::new();
|
||||
let mut generated_normal=Vec::new();
|
||||
@ -276,11 +276,10 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->crate:
|
||||
unique_color:generated_color,
|
||||
unique_vertices:generated_vertices,
|
||||
groups,
|
||||
instances:Vec::new(),
|
||||
}
|
||||
}
|
||||
//don't think too hard about the copy paste because this is all going into the map tool eventually...
|
||||
pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->crate::model::IndexedModel{
|
||||
pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->IndexedModel{
|
||||
let wedge_default_polys=vec![
|
||||
// right (1, 0, 0)
|
||||
vec![
|
||||
@ -383,11 +382,10 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->crat
|
||||
unique_color:generated_color,
|
||||
unique_vertices:generated_vertices,
|
||||
groups,
|
||||
instances:Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescription)->crate::model::IndexedModel{
|
||||
pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescription)->IndexedModel{
|
||||
let cornerwedge_default_polys=vec![
|
||||
// right (1, 0, 0)
|
||||
vec![
|
||||
@ -488,6 +486,5 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
|
||||
unique_color:generated_color,
|
||||
unique_vertices:generated_vertices,
|
||||
groups,
|
||||
instances:Vec::new(),
|
||||
}
|
||||
}
|
||||
|
401
src/rbx.rs
401
src/rbx.rs
@ -1,6 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::primitives;
|
||||
use strafesnet_common::gameplay_attributes;
|
||||
use strafesnet_common::map;
|
||||
use strafesnet_common::model;
|
||||
use strafesnet_common::gameplay_modes;
|
||||
use strafesnet_common::gameplay_style;
|
||||
use strafesnet_common::gameplay_attributes as attr;
|
||||
use strafesnet_common::integer::{Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3};
|
||||
use strafesnet_common::updatable::Updatable;
|
||||
|
||||
fn class_is_a(class: &str, superclass: &str) -> bool {
|
||||
if class==superclass {
|
||||
@ -40,91 +46,203 @@ fn planar64_affine3_from_roblox(cf:&rbx_dom_weak::types::CFrame,size:&rbx_dom_we
|
||||
Planar64Vec3::try_from([cf.position.x,cf.position.y,cf.position.z]).unwrap()
|
||||
)
|
||||
}
|
||||
fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_intersecting:bool)->model::CollisionAttributes{
|
||||
let mut general=model::GameMechanicAttributes::default();
|
||||
let mut intersecting=model::IntersectingAttributes::default();
|
||||
let mut contacting=model::ContactingAttributes::default();
|
||||
struct ModeBuilder{
|
||||
mode:gameplay_modes::Mode,
|
||||
final_stage_id_from_builder_stage_id:HashMap<gameplay_modes::StageId,gameplay_modes::StageId>,
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct ModesBuilder{
|
||||
modes:HashMap<gameplay_modes::ModeId,gameplay_modes::Mode>,
|
||||
stages:HashMap<gameplay_modes::ModeId,HashMap<gameplay_modes::StageId,gameplay_modes::Stage>>,
|
||||
mode_updates:Vec<(gameplay_modes::ModeId,gameplay_modes::ModeUpdate)>,
|
||||
stage_updates:Vec<(gameplay_modes::ModeId,gameplay_modes::StageId,gameplay_modes::StageUpdate)>,
|
||||
}
|
||||
impl ModesBuilder{
|
||||
fn build(mut self)->gameplay_modes::Modes{
|
||||
//collect modes and stages into contiguous arrays
|
||||
let mut unique_modes:Vec<(gameplay_modes::ModeId,gameplay_modes::Mode)>
|
||||
=self.modes.into_iter().collect();
|
||||
unique_modes.sort_by(|a,b|a.0.cmp(&b.0));
|
||||
let (mut modes,final_mode_id_from_builder_mode_id):(Vec<ModeBuilder>,HashMap<gameplay_modes::ModeId,gameplay_modes::ModeId>)
|
||||
=unique_modes.into_iter().enumerate()
|
||||
.map(|(final_mode_id,(builder_mode_id,mut mode))|{
|
||||
(
|
||||
ModeBuilder{
|
||||
final_stage_id_from_builder_stage_id:self.stages.remove(&builder_mode_id).map_or_else(||HashMap::new(),|stages|{
|
||||
let mut unique_stages:Vec<(gameplay_modes::StageId,gameplay_modes::Stage)>
|
||||
=stages.into_iter().collect();
|
||||
unique_stages.sort_by(|a,b|a.0.cmp(&b.0));
|
||||
unique_stages.into_iter().enumerate()
|
||||
.map(|(final_stage_id,(builder_stage_id,stage))|{
|
||||
mode.push_stage(stage);
|
||||
(builder_stage_id,gameplay_modes::StageId::id(final_stage_id as u32))
|
||||
}).collect()
|
||||
}),
|
||||
mode,
|
||||
},
|
||||
(
|
||||
builder_mode_id,
|
||||
gameplay_modes::ModeId::id(final_mode_id as u32)
|
||||
)
|
||||
)
|
||||
}).unzip();
|
||||
//TODO: failure messages or errors or something
|
||||
//push stage updates
|
||||
for (builder_mode_id,builder_stage_id,stage_update) in self.stage_updates{
|
||||
if let Some(final_mode_id)=final_mode_id_from_builder_mode_id.get(&builder_mode_id){
|
||||
if let Some(mode)=modes.get_mut(final_mode_id.get() as usize){
|
||||
if let Some(&final_stage_id)=mode.final_stage_id_from_builder_stage_id.get(&builder_stage_id){
|
||||
if let Some(stage)=mode.mode.get_stage_mut(final_stage_id){
|
||||
stage.update(stage_update);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//push mode updates
|
||||
for (builder_mode_id,mode_update) in self.mode_updates{
|
||||
if let Some(final_mode_id)=final_mode_id_from_builder_mode_id.get(&builder_mode_id){
|
||||
if let Some(mode)=modes.get_mut(final_mode_id.get() as usize){
|
||||
mode.mode.update(mode_update);
|
||||
}
|
||||
}
|
||||
}
|
||||
gameplay_modes::Modes::new(modes.into_iter().map(|mode_builder|mode_builder.mode).collect())
|
||||
}
|
||||
fn insert_mode(&mut self,mode_id:gameplay_modes::ModeId,mode:gameplay_modes::Mode){
|
||||
assert!(self.modes.insert(mode_id,mode).is_none(),"Cannot replace existing mode");
|
||||
}
|
||||
fn insert_stage(&mut self,mode_id:gameplay_modes::ModeId,stage_id:gameplay_modes::StageId,stage:gameplay_modes::Stage){
|
||||
assert!(self.stages.entry(mode_id).or_insert(HashMap::new()).insert(stage_id,stage).is_none(),"Cannot replace existing stage");
|
||||
}
|
||||
fn push_mode_update(&mut self,mode_id:gameplay_modes::ModeId,mode_update:gameplay_modes::ModeUpdate){
|
||||
self.mode_updates.push((mode_id,mode_update));
|
||||
}
|
||||
fn push_stage_update(&mut self,mode_id:gameplay_modes::ModeId,stage_id:gameplay_modes::StageId,stage_update:gameplay_modes::StageUpdate){
|
||||
self.stage_updates.push((mode_id,stage_id,stage_update));
|
||||
}
|
||||
}
|
||||
fn get_attributes(object:&rbx_dom_weak::Instance,can_collide:bool,velocity:Planar64Vec3,force_intersecting:bool,model_id:model::ModelId,modes_builder:&mut ModesBuilder,wormhole_in_model_to_id:&mut HashMap<model::ModelId,u32>)->attr::CollisionAttributes{
|
||||
let name=object.name.as_str();
|
||||
let mut general=attr::GeneralAttributes::default();
|
||||
let mut intersecting=attr::IntersectingAttributes::default();
|
||||
let mut contacting=attr::ContactingAttributes::default();
|
||||
let mut force_can_collide=can_collide;
|
||||
match name{
|
||||
"Water"=>{
|
||||
force_can_collide=false;
|
||||
//TODO: read stupid CustomPhysicalProperties
|
||||
intersecting.water=Some(model::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,velocity});
|
||||
intersecting.water=Some(attr::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,velocity});
|
||||
},
|
||||
"Accelerator"=>{
|
||||
//although the new game supports collidable accelerators, this is a roblox compatability map loader
|
||||
force_can_collide=false;
|
||||
general.accelerator=Some(model::GameMechanicAccelerator{acceleration:velocity});
|
||||
general.accelerator=Some(attr::Accelerator{acceleration:velocity});
|
||||
},
|
||||
// "UnorderedCheckpoint"=>general.teleport_behaviour=Some(model::TeleportBehaviour::StageElement(model::GameMechanicStageElement{
|
||||
// "UnorderedCheckpoint"=>general.teleport_behaviour=Some(model::TeleportBehaviour::StageElement(attr::StageElement{
|
||||
// mode_id:0,
|
||||
// stage_id:0,
|
||||
// force:false,
|
||||
// behaviour:model::StageElementBehaviour::Unordered
|
||||
// })),
|
||||
"SetVelocity"=>general.trajectory=Some(model::GameMechanicSetTrajectory::Velocity(velocity)),
|
||||
"MapFinish"=>{force_can_collide=false;general.zone=Some(model::GameMechanicZone{mode_id:0,behaviour:model::ZoneBehaviour::Finish})},
|
||||
"MapAnticheat"=>{force_can_collide=false;general.zone=Some(model::GameMechanicZone{mode_id:0,behaviour:model::ZoneBehaviour::Anitcheat})},
|
||||
"Platform"=>general.teleport_behaviour=Some(model::TeleportBehaviour::StageElement(model::GameMechanicStageElement{
|
||||
mode_id:0,
|
||||
stage_id:0,
|
||||
force:false,
|
||||
behaviour:model::StageElementBehaviour::Platform,
|
||||
})),
|
||||
"SetVelocity"=>general.trajectory=Some(attr::SetTrajectory::Velocity(velocity)),
|
||||
"MapFinish"=>{
|
||||
force_can_collide=false;
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::zone(
|
||||
model_id,
|
||||
gameplay_modes::Zone::Finish,
|
||||
),
|
||||
);
|
||||
},
|
||||
"MapAnticheat"=>{
|
||||
force_can_collide=false;
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::zone(
|
||||
model_id,
|
||||
gameplay_modes::Zone::Anticheat,
|
||||
),
|
||||
);
|
||||
},
|
||||
"Platform"=>{
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::element(
|
||||
model_id,
|
||||
gameplay_modes::StageElement::new(0,false,gameplay_modes::StageElementBehaviour::Platform),//roblox does not know which stage the platform belongs to
|
||||
),
|
||||
);
|
||||
},
|
||||
other=>{
|
||||
if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Spawn|SpawnAt|Trigger|Teleport|Platform)(\d+)$")
|
||||
.captures(other){
|
||||
general.teleport_behaviour=Some(model::TeleportBehaviour::StageElement(model::GameMechanicStageElement{
|
||||
mode_id:0,
|
||||
stage_id:captures[3].parse::<u32>().unwrap(),
|
||||
force:match captures.get(1){
|
||||
Some(m)=>m.as_str()=="Force",
|
||||
None=>false,
|
||||
},
|
||||
behaviour:match &captures[2]{
|
||||
"Spawn"|"SpawnAt"=>model::StageElementBehaviour::SpawnAt,
|
||||
//cancollide false so you don't hit the side
|
||||
//NOT a decoration
|
||||
"Trigger"=>{force_can_collide=false;model::StageElementBehaviour::Trigger},
|
||||
"Teleport"=>{force_can_collide=false;model::StageElementBehaviour::Teleport},
|
||||
"Platform"=>model::StageElementBehaviour::Platform,
|
||||
_=>panic!("regex1[2] messed up bad"),
|
||||
}
|
||||
}));
|
||||
}else if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Jump)(\d+)$")
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::element(
|
||||
model_id,
|
||||
gameplay_modes::StageElement::new(
|
||||
//stage_id:
|
||||
captures[3].parse::<u32>().unwrap(),
|
||||
//force:
|
||||
match captures.get(1){
|
||||
Some(m)=>m.as_str()=="Force",
|
||||
None=>false,
|
||||
},
|
||||
//behaviour:
|
||||
match &captures[2]{
|
||||
"Spawn"|"SpawnAt"=>gameplay_modes::StageElementBehaviour::SpawnAt,
|
||||
//cancollide false so you don't hit the side
|
||||
//NOT a decoration
|
||||
"Trigger"=>{force_can_collide=false;gameplay_modes::StageElementBehaviour::Trigger},
|
||||
"Teleport"=>{force_can_collide=false;gameplay_modes::StageElementBehaviour::Teleport},
|
||||
"Platform"=>gameplay_modes::StageElementBehaviour::Platform,
|
||||
_=>panic!("regex1[2] messed up bad"),
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}else if let Some(captures)=lazy_regex::regex!(r"^(Jump|WormholeIn)(\d+)$")
|
||||
.captures(other){
|
||||
general.teleport_behaviour=Some(model::TeleportBehaviour::StageElement(model::GameMechanicStageElement{
|
||||
mode_id:0,
|
||||
stage_id:0,
|
||||
force:match captures.get(1){
|
||||
Some(m)=>m.as_str()=="Force",
|
||||
None=>false,
|
||||
match &captures[1]{
|
||||
"Jump"=>modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::jump_limit(
|
||||
model_id,
|
||||
//jump_limit:
|
||||
captures[2].parse::<u32>().unwrap()
|
||||
),
|
||||
),
|
||||
"WormholeIn"=>{
|
||||
force_can_collide=false;
|
||||
assert!(wormhole_in_model_to_id.insert(model_id,captures[2].parse::<u32>().unwrap()).is_none(),"Impossible");
|
||||
},
|
||||
behaviour:match &captures[2]{
|
||||
"Jump"=>model::StageElementBehaviour::JumpLimit(captures[3].parse::<u32>().unwrap()),
|
||||
_=>panic!("regex4[1] messed up bad"),
|
||||
}
|
||||
}));
|
||||
}
|
||||
}else if let Some(captures)=lazy_regex::regex!(r"^Bonus(Finish|Anticheat)(\d+)$")
|
||||
.captures(other){
|
||||
force_can_collide=false;
|
||||
match &captures[1]{
|
||||
"Finish"=>general.zone=Some(model::GameMechanicZone{mode_id:captures[2].parse::<u32>().unwrap(),behaviour:model::ZoneBehaviour::Finish}),
|
||||
"Anticheat"=>general.zone=Some(model::GameMechanicZone{mode_id:captures[2].parse::<u32>().unwrap(),behaviour:model::ZoneBehaviour::Anitcheat}),
|
||||
_=>panic!("regex2[1] messed up bad"),
|
||||
}
|
||||
}else if let Some(captures)=lazy_regex::regex!(r"^(WormholeIn)(\d+)$")
|
||||
.captures(other){
|
||||
force_can_collide=false;
|
||||
match &captures[1]{
|
||||
"WormholeIn"=>general.teleport_behaviour=Some(model::TeleportBehaviour::Wormhole(model::GameMechanicWormhole{destination_model_id:captures[2].parse::<u32>().unwrap()})),
|
||||
_=>panic!("regex3[1] messed up bad"),
|
||||
}
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::id(captures[2].parse::<u32>().unwrap()),
|
||||
gameplay_modes::ModeUpdate::zone(
|
||||
model_id,
|
||||
//zone:
|
||||
match &captures[1]{
|
||||
"Finish"=>gameplay_modes::Zone::Finish,
|
||||
"Anticheat"=>gameplay_modes::Zone::Anticheat,
|
||||
_=>panic!("regex2[1] messed up bad"),
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
// else if let Some(captures)=lazy_regex::regex!(r"^(OrderedCheckpoint)(\d+)$")
|
||||
// else if let Some(captures)=lazy_regex::regex!(r"^Stage(\d+)OrderedCheckpoint(\d+)$")
|
||||
// .captures(other){
|
||||
// match &captures[1]{
|
||||
// "OrderedCheckpoint"=>general.checkpoint=Some(model::GameMechanicCheckpoint::Ordered{mode_id:0,checkpoint_id:captures[2].parse::<u32>().unwrap()}),
|
||||
// "OrderedCheckpoint"=>modes_builder.push_stage_update(
|
||||
// gameplay_modes::ModeId::MAIN,
|
||||
// gameplay_modes::StageId::id(0),
|
||||
// gameplay_modes::StageUpdate::ordered_checkpoint(captures[2].parse::<u32>().unwrap()),
|
||||
// ),
|
||||
// _=>panic!("regex3[1] messed up bad"),
|
||||
// }
|
||||
// }
|
||||
@ -132,25 +250,25 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse
|
||||
}
|
||||
//need some way to skip this
|
||||
if velocity!=Planar64Vec3::ZERO{
|
||||
general.booster=Some(model::GameMechanicBooster::Velocity(velocity));
|
||||
general.booster=Some(attr::Booster::Velocity(velocity));
|
||||
}
|
||||
match force_can_collide{
|
||||
true=>{
|
||||
match name{
|
||||
"Bounce"=>contacting.contact_behaviour=Some(model::ContactingBehaviour::Elastic(u32::MAX)),
|
||||
"Surf"=>contacting.contact_behaviour=Some(model::ContactingBehaviour::Surf),
|
||||
"Ladder"=>contacting.contact_behaviour=Some(model::ContactingBehaviour::Ladder(model::ContactingLadder{sticky:true})),
|
||||
"Bounce"=>contacting.contact_behaviour=Some(attr::ContactingBehaviour::Elastic(u32::MAX)),
|
||||
"Surf"=>contacting.contact_behaviour=Some(attr::ContactingBehaviour::Surf),
|
||||
"Ladder"=>contacting.contact_behaviour=Some(attr::ContactingBehaviour::Ladder(attr::ContactingLadder{sticky:true})),
|
||||
_=>(),
|
||||
}
|
||||
model::CollisionAttributes::Contact{contacting,general}
|
||||
attr::CollisionAttributes::Contact{contacting,general}
|
||||
},
|
||||
false=>if force_intersecting
|
||||
||general.any()
|
||||
||intersecting.any()
|
||||
{
|
||||
model::CollisionAttributes::Intersect{intersecting,general}
|
||||
attr::CollisionAttributes::Intersect{intersecting,general}
|
||||
}else{
|
||||
model::CollisionAttributes::Decoration
|
||||
attr::CollisionAttributes::Decoration
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -233,12 +351,24 @@ enum RobloxBasePartDescription{
|
||||
Wedge(RobloxWedgeDescription),
|
||||
CornerWedge(RobloxCornerWedgeDescription),
|
||||
}
|
||||
pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> model::IndexedModelInstances{
|
||||
//IndexedModelInstances includes textures
|
||||
let mut spawn_point=Planar64Vec3::ZERO;
|
||||
struct ModelOwnedAttributes{
|
||||
model:model::IndexedModelId,
|
||||
attributes:attr::CollisionAttributes,
|
||||
color:model::Color4,//transparency is in here
|
||||
transform:Planar64Affine3,
|
||||
}
|
||||
pub fn convert(dom:rbx_dom_weak::WeakDom)->map::Map{
|
||||
let mut modes_builder=ModesBuilder::default();
|
||||
|
||||
let mut models1=Vec::new();
|
||||
let mut indexed_models=Vec::new();
|
||||
let mut model_id_from_description=std::collections::HashMap::<RobloxBasePartDescription,usize>::new();
|
||||
let mut indexed_model_id_from_description=std::collections::HashMap::new();
|
||||
|
||||
let mut unique_attributes=Vec::new();
|
||||
let mut attributes_id_from_attributes=HashMap::new();
|
||||
|
||||
let mut wormhole_in_model_to_id=HashMap::new();
|
||||
let mut wormhole_id_to_out_model=HashMap::new();
|
||||
|
||||
let mut texture_id_from_asset_id=std::collections::HashMap::<u64,u32>::new();
|
||||
let mut asset_id_from_texture_id=Vec::new();
|
||||
@ -278,31 +408,54 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> model::IndexedModel
|
||||
continue;
|
||||
}
|
||||
|
||||
//push TempIndexedAttributes
|
||||
let mut force_intersecting=false;
|
||||
let mut temp_indexing_attributes=Vec::new();
|
||||
if let Some(attr)=match &object.name[..]{
|
||||
//at this point a new model is going to be generated for sure.
|
||||
let model_id=model::ModelId::id(models1.len() as u32);
|
||||
|
||||
let force_intersecting=match &object.name[..]{
|
||||
"MapStart"=>{
|
||||
spawn_point=model_transform.transform_point3(Planar64Vec3::ZERO)+Planar64Vec3::Y*5/2;
|
||||
Some(model::TempIndexedAttributes::Start(model::TempAttrStart{mode_id:0}))
|
||||
modes_builder.insert_mode(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::Mode::new(
|
||||
gameplay_style::StyleModifiers::roblox_bhop(),
|
||||
model_id
|
||||
)
|
||||
);
|
||||
true
|
||||
},
|
||||
other=>{
|
||||
let regman=lazy_regex::regex!(r"^(BonusStart|Spawn|ForceSpawn|WormholeOut)(\d+)$");
|
||||
if let Some(captures) = regman.captures(other) {
|
||||
let regman=lazy_regex::regex!(r"^(BonusStart|Spawn|WormholeOut)(\d+)$");
|
||||
if let Some(captures)=regman.captures(other){
|
||||
match &captures[1]{
|
||||
"BonusStart"=>Some(model::TempIndexedAttributes::Start(model::TempAttrStart{mode_id:captures[2].parse::<u32>().unwrap()})),
|
||||
"Spawn"|"ForceSpawn"=>Some(model::TempIndexedAttributes::Spawn(model::TempAttrSpawn{mode_id:0,stage_id:captures[2].parse::<u32>().unwrap()})),
|
||||
"WormholeOut"=>Some(model::TempIndexedAttributes::Wormhole(model::TempAttrWormhole{wormhole_id:captures[2].parse::<u32>().unwrap()})),
|
||||
_=>None,
|
||||
"BonusStart"=>{
|
||||
modes_builder.insert_mode(
|
||||
gameplay_modes::ModeId::id(captures[2].parse::<u32>().unwrap()),
|
||||
gameplay_modes::Mode::new(
|
||||
gameplay_style::StyleModifiers::roblox_bhop(),
|
||||
model_id
|
||||
)
|
||||
);
|
||||
true
|
||||
},
|
||||
"Spawn"=>{
|
||||
modes_builder.insert_stage(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::StageId::id(captures[2].parse::<u32>().unwrap()),
|
||||
gameplay_modes::Stage::new(model_id),
|
||||
);
|
||||
true
|
||||
},
|
||||
"WormholeOut"=>{
|
||||
//this object is not special in strafe client, but the roblox mapping needs to be converted to model id
|
||||
assert!(wormhole_id_to_out_model.insert(captures[2].parse::<u32>().unwrap(),model_id).is_none(),"Cannot have multiple WormholeOut with same id");
|
||||
false
|
||||
},
|
||||
_=>false,
|
||||
}
|
||||
}else{
|
||||
None
|
||||
false
|
||||
}
|
||||
}
|
||||
}{
|
||||
force_intersecting=true;
|
||||
temp_indexing_attributes.push(attr);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO: also detect "CylinderMesh" etc here
|
||||
let shape=match &object.class[..]{
|
||||
@ -436,12 +589,12 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> model::IndexedModel
|
||||
]),
|
||||
};
|
||||
//make new model if unit cube has not been created before
|
||||
let model_id=if let Some(&model_id)=model_id_from_description.get(&basepart_texture_description){
|
||||
let indexed_model_id=if let Some(&indexed_model_id)=indexed_model_id_from_description.get(&basepart_texture_description){
|
||||
//push to existing texture model
|
||||
model_id
|
||||
indexed_model_id
|
||||
}else{
|
||||
let model_id=indexed_models.len();
|
||||
model_id_from_description.insert(basepart_texture_description.clone(),model_id);//borrow checker going crazy
|
||||
let indexed_model_id=model::IndexedModelId::id(indexed_models.len() as u32);
|
||||
indexed_model_id_from_description.insert(basepart_texture_description.clone(),indexed_model_id);//borrow checker going crazy
|
||||
indexed_models.push(match basepart_texture_description{
|
||||
RobloxBasePartDescription::Sphere(part_texture_description)
|
||||
|RobloxBasePartDescription::Cylinder(part_texture_description)
|
||||
@ -504,21 +657,67 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> model::IndexedModel
|
||||
primitives::generate_partial_unit_cornerwedge(cornerwedge_face_description)
|
||||
},
|
||||
});
|
||||
model_id
|
||||
indexed_model_id
|
||||
};
|
||||
indexed_models[model_id].instances.push(model::ModelInstance {
|
||||
let attributes=get_attributes(
|
||||
&object,
|
||||
*can_collide,
|
||||
Planar64Vec3::try_from([velocity.x,velocity.y,velocity.z]).unwrap(),
|
||||
force_intersecting,
|
||||
model_id,
|
||||
&mut modes_builder,
|
||||
&mut wormhole_in_model_to_id,
|
||||
);
|
||||
models1.push(ModelOwnedAttributes{
|
||||
model:indexed_model_id,
|
||||
transform:model_transform,
|
||||
color:glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
|
||||
attributes:get_attributes(&object.name,*can_collide,Planar64Vec3::try_from([velocity.x,velocity.y,velocity.z]).unwrap(),force_intersecting),
|
||||
temp_indexing:temp_indexing_attributes,
|
||||
attributes,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
model::IndexedModelInstances{
|
||||
textures:asset_id_from_texture_id.iter().map(|t|t.to_string()).collect(),
|
||||
models:indexed_models,
|
||||
spawn_point,
|
||||
modes:Vec::new(),
|
||||
let models=models1.into_iter().enumerate().map(|(model_id,mut model1)|{
|
||||
let model_id=model::ModelId::id(model_id as u32);
|
||||
//update attributes with wormhole id
|
||||
//TODO: errors/prints
|
||||
if let Some(wormhole_id)=wormhole_in_model_to_id.get(&model_id){
|
||||
if let Some(&wormhole_out_model_id)=wormhole_id_to_out_model.get(wormhole_id){
|
||||
match &mut model1.attributes{
|
||||
attr::CollisionAttributes::Contact{contacting:_,general}
|
||||
|attr::CollisionAttributes::Intersect{intersecting:_,general}
|
||||
=>general.wormhole=Some(attr::Wormhole{destination_model:wormhole_out_model_id}),
|
||||
attr::CollisionAttributes::Decoration=>println!("Not a wormhole"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//index the attributes
|
||||
let attributes_id=if let Some(&attributes_id)=attributes_id_from_attributes.get(&model1.attributes){
|
||||
attributes_id
|
||||
}else{
|
||||
let attributes_id=attr::CollisionAttributesId::new(unique_attributes.len() as u32);
|
||||
attributes_id_from_attributes.insert(model1.attributes,attributes_id);
|
||||
unique_attributes.push(model1.attributes);
|
||||
attributes_id
|
||||
};
|
||||
(model_id,model::Model{
|
||||
model:model1.model,
|
||||
transform:model1.transform,
|
||||
color:model1.color,
|
||||
attributes:attributes_id,
|
||||
})
|
||||
}).collect();
|
||||
map::Map{
|
||||
textures:Vec::new(),//asset_id_from_texture_id.iter().map(|t|t.to_string()).collect(),
|
||||
models:model::Models::new(
|
||||
indexed_models.into_iter().enumerate()
|
||||
.map(|(indexed_model_id,indexed_model)|
|
||||
(model::IndexedModelId::id(indexed_model_id as u32),indexed_model)
|
||||
).collect(),
|
||||
models,
|
||||
),
|
||||
modes:modes_builder.build(),
|
||||
attributes:unique_attributes,
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user