Compare commits
35 Commits
bsp-brush3
...
entity
Author | SHA1 | Date | |
---|---|---|---|
a56195c887 | |||
70fb970582 | |||
31184d21da | |||
6b4b17f49d | |||
d0c17873f6 | |||
d39705d5e7 | |||
a3a50580f8 | |||
d5bf4549a9 | |||
b5da85fae1 | |||
78c53ae429 | |||
e794b2649c | |||
50f6fe5bd8 | |||
fc3681f41f | |||
a2369b4211 | |||
bfea49ffae | |||
8c7063d340 | |||
651150760c | |||
3d203e2da9 | |||
3798f438cf | |||
4ace8317fe | |||
ab4a9bb922 | |||
a9ef07ce78 | |||
561e41c760 | |||
9896a09576 | |||
82840fa6cb | |||
2c87cb71df | |||
709f622547 | |||
b20264b382 | |||
17cce2d702 | |||
a2b2ddc9ce | |||
cb57d893e0 | |||
9e8d66cec1 | |||
39fe833198 | |||
e7688a95fd | |||
d2cc98b04d |
Cargo.lock
engine/physics/src
integration-testing/src
lib
bsp_loader
common
fixed_wide
rbx_loader
snf
src
map-tool
493
Cargo.lock
generated
493
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -982,10 +982,7 @@ impl PhysicsContext<'_>{
|
||||
impl PhysicsData{
|
||||
/// use with caution, this is the only non-instruction way to mess with physics
|
||||
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
||||
let mut modes=map.modes.clone();
|
||||
for mode in &mut modes.modes{
|
||||
mode.denormalize_data();
|
||||
}
|
||||
let mut modes=map.modes.clone().denormalize();
|
||||
let mut used_contact_attributes=Vec::new();
|
||||
let mut used_intersect_attributes=Vec::new();
|
||||
|
||||
@ -1814,14 +1811,18 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
||||
},
|
||||
Instruction::Mode(ModeInstruction::Restart(mode_id))=>{
|
||||
//teleport to mode start zone
|
||||
let mut spawn_point=vec3::ZERO;
|
||||
let mode=data.modes.get_mode(mode_id);
|
||||
let spawn_point=mode.and_then(|mode|
|
||||
if let Some(mode)=mode{
|
||||
// set style
|
||||
state.style=mode.get_style().clone();
|
||||
//TODO: spawn at the bottom of the start zone plus the hitbox size
|
||||
//TODO: set camera andles to face the same way as the start zone
|
||||
data.models.get_model_transform(mode.get_start().into()).map(|transform|
|
||||
transform.vertex.translation
|
||||
)
|
||||
).unwrap_or(vec3::ZERO);
|
||||
//TODO: set camera angles to face the same way as the start zone
|
||||
if let Some(transform)=data.models.get_model_transform(mode.get_start()){
|
||||
// NOTE: this value may be 0,0,0 on source maps
|
||||
spawn_point=transform.vertex.translation;
|
||||
}
|
||||
}
|
||||
set_position(spawn_point,&mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state,mode,&data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time);
|
||||
set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,vec3::ZERO);
|
||||
state.set_move_state(data,MoveState::Air);
|
||||
@ -1831,6 +1832,9 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
||||
Instruction::Mode(ModeInstruction::Spawn(mode_id,stage_id))=>{
|
||||
//spawn at a particular stage
|
||||
if let Some(mode)=data.modes.get_mode(mode_id){
|
||||
// set style
|
||||
state.style=mode.get_style().clone();
|
||||
// teleport to stage in mode
|
||||
if let Some(stage)=mode.get_stage(stage_id){
|
||||
let _=teleport_to_spawn(
|
||||
stage.spawn(),
|
||||
|
@ -1,5 +1,7 @@
|
||||
|
||||
use std::{io::{Cursor,Read},path::Path};
|
||||
use std::io::Cursor;
|
||||
use std::path::Path;
|
||||
use std::time::Instant;
|
||||
|
||||
use strafesnet_physics::physics::{PhysicsData,PhysicsState,PhysicsContext};
|
||||
|
||||
@ -37,9 +39,7 @@ impl From<strafesnet_snf::bot::Error> for ReplayError{
|
||||
}
|
||||
|
||||
fn read_entire_file(path:impl AsRef<Path>)->Result<Cursor<Vec<u8>>,std::io::Error>{
|
||||
let mut file=std::fs::File::open(path)?;
|
||||
let mut data=Vec::new();
|
||||
file.read_to_end(&mut data)?;
|
||||
let data=std::fs::read(path)?;
|
||||
Ok(Cursor::new(data))
|
||||
}
|
||||
|
||||
@ -72,7 +72,12 @@ enum DeterminismResult{
|
||||
Deterministic,
|
||||
NonDeterministic,
|
||||
}
|
||||
fn segment_determinism(bot:strafesnet_snf::bot::Segment,physics_data:&PhysicsData)->DeterminismResult{
|
||||
struct SegmentResult{
|
||||
determinism:DeterminismResult,
|
||||
ticks:u64,
|
||||
nanoseconds:u64,
|
||||
}
|
||||
fn segment_determinism(bot:strafesnet_snf::bot::Segment,physics_data:&PhysicsData)->SegmentResult{
|
||||
// create default physics state
|
||||
let mut physics_deterministic=PhysicsState::default();
|
||||
// create a second physics state
|
||||
@ -82,6 +87,9 @@ fn segment_determinism(bot:strafesnet_snf::bot::Segment,physics_data:&PhysicsDat
|
||||
println!("simulating...");
|
||||
|
||||
let mut non_idle_count=0;
|
||||
let instruction_count=bot.instructions.len();
|
||||
|
||||
let start=Instant::now();
|
||||
|
||||
for (i,ins) in bot.instructions.into_iter().enumerate(){
|
||||
let state_deterministic=physics_deterministic.clone();
|
||||
@ -97,6 +105,7 @@ fn segment_determinism(bot:strafesnet_snf::bot::Segment,physics_data:&PhysicsDat
|
||||
let b0=physics_deterministic.camera_body();
|
||||
let b1=physics_filtered.camera_body();
|
||||
if b0.position!=b1.position{
|
||||
let nanoseconds=start.elapsed().as_nanos() as u64;
|
||||
println!("desync at instruction #{}",i);
|
||||
println!("non idle instructions completed={non_idle_count}");
|
||||
println!("instruction #{i}={:?}",other);
|
||||
@ -104,11 +113,16 @@ fn segment_determinism(bot:strafesnet_snf::bot::Segment,physics_data:&PhysicsDat
|
||||
println!("filtered state0:\n{state_filtered:?}");
|
||||
println!("deterministic state1:\n{:?}",physics_deterministic);
|
||||
println!("filtered state1:\n{:?}",physics_filtered);
|
||||
return DeterminismResult::NonDeterministic;
|
||||
return SegmentResult{
|
||||
determinism:DeterminismResult::NonDeterministic,
|
||||
ticks:1+i as u64+non_idle_count,
|
||||
nanoseconds,
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let nanoseconds=start.elapsed().as_nanos() as u64;
|
||||
match physics_deterministic.get_finish_time(){
|
||||
Some(time)=>println!("[with idle] finish time:{}",time),
|
||||
None=>println!("[with idle] simulation did not end in finished state"),
|
||||
@ -117,9 +131,14 @@ fn segment_determinism(bot:strafesnet_snf::bot::Segment,physics_data:&PhysicsDat
|
||||
Some(time)=>println!("[filtered] finish time:{}",time),
|
||||
None=>println!("[filtered] simulation did not end in finished state"),
|
||||
}
|
||||
DeterminismResult::Deterministic
|
||||
SegmentResult{
|
||||
determinism:DeterminismResult::Deterministic,
|
||||
ticks:instruction_count as u64+non_idle_count,
|
||||
nanoseconds,
|
||||
}
|
||||
|
||||
}
|
||||
type ThreadResult=Result<Option<DeterminismResult>,ReplayError>;
|
||||
type ThreadResult=Result<Option<SegmentResult>,ReplayError>;
|
||||
fn read_and_run(file_path:std::path::PathBuf,physics_data:&PhysicsData)->ThreadResult{
|
||||
let data=read_entire_file(file_path.as_path())?;
|
||||
let bot=strafesnet_snf::read_bot(data)?.read_all()?;
|
||||
@ -198,10 +217,18 @@ fn test_determinism()->Result<(),ReplayError>{
|
||||
invalid:u32,
|
||||
error:u32,
|
||||
}
|
||||
let mut nanoseconds=0;
|
||||
let mut ticks=0;
|
||||
let Totals{deterministic,nondeterministic,invalid,error}=thread_results.into_iter().fold(Totals::default(),|mut totals,result|{
|
||||
match result{
|
||||
Ok(Some(DeterminismResult::Deterministic))=>totals.deterministic+=1,
|
||||
Ok(Some(DeterminismResult::NonDeterministic))=>totals.nondeterministic+=1,
|
||||
Ok(Some(segment_result))=>{
|
||||
ticks+=segment_result.ticks;
|
||||
nanoseconds+=segment_result.nanoseconds;
|
||||
match segment_result.determinism{
|
||||
DeterminismResult::Deterministic=>totals.deterministic+=1,
|
||||
DeterminismResult::NonDeterministic=>totals.nondeterministic+=1,
|
||||
}
|
||||
},
|
||||
Ok(None)=>totals.invalid+=1,
|
||||
Err(_)=>totals.error+=1,
|
||||
}
|
||||
@ -212,6 +239,7 @@ fn test_determinism()->Result<(),ReplayError>{
|
||||
println!("nondeterministic={nondeterministic}");
|
||||
println!("invalid={invalid}");
|
||||
println!("error={error}");
|
||||
println!("average ticks/s per core: {}",ticks*1_000_000_000/nanoseconds);
|
||||
|
||||
assert!(nondeterministic==0);
|
||||
assert!(invalid==0);
|
||||
|
@ -13,7 +13,7 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
||||
glam = "0.30.0"
|
||||
strafesnet_common = { version = "0.6.0", path = "../common", registry = "strafesnet" }
|
||||
strafesnet_deferred_loader = { version = "0.5.0", path = "../deferred_loader", registry = "strafesnet" }
|
||||
vbsp = { version = "0.7.0-codegen5", registry = "strafesnet", default-features = false }
|
||||
vbsp-entities = { version = "0.1.0", registry = "strafesnet", default-features = false, features = ["css"]}
|
||||
vbsp = "0.8.0"
|
||||
vbsp-entities-css = "0.6.0"
|
||||
vmdl = "0.2.0"
|
||||
vpk = "0.2.0"
|
||||
vpk = "0.3.0"
|
||||
|
@ -240,7 +240,7 @@ pub fn brush_to_mesh(bsp:&vbsp::Bsp,brush:&vbsp::Brush)->Result<model::Mesh,Brus
|
||||
// The so-called tumor brushes have TRIGGER bit set
|
||||
// but also ignore visleaf hint and skip sides
|
||||
const TUMOR:vbsp::TextureFlags=vbsp::TextureFlags::HINT.union(vbsp::TextureFlags::SKIP).union(vbsp::TextureFlags::TRIGGER);
|
||||
if let Some(texture_info)=bsp.textures_info.get(side.texture_info as usize){
|
||||
if let Some(texture_info)=bsp.texture_info(side.texture_info as usize){
|
||||
if texture_info.flags.intersects(TUMOR){
|
||||
return None;
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use vbsp_entities::css::Entity;
|
||||
use vbsp_entities_css::Entity;
|
||||
|
||||
use strafesnet_common::{map,model,integer,gameplay_attributes};
|
||||
use strafesnet_common::{map,model,integer,gameplay_attributes as attr};
|
||||
use strafesnet_deferred_loader::deferred_loader::{MeshDeferredLoader,RenderConfigDeferredLoader};
|
||||
use strafesnet_deferred_loader::mesh::Meshes;
|
||||
use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
|
||||
use strafesnet_common::gameplay_modes::{NormalizedMode,NormalizedModes,Mode,Stage};
|
||||
|
||||
use crate::valve_transform;
|
||||
|
||||
@ -41,7 +42,7 @@ fn add_brush<'a>(
|
||||
model:&'a str,
|
||||
origin:vbsp::Vector,
|
||||
rendercolor:vbsp::Color,
|
||||
attributes:gameplay_attributes::CollisionAttributesId,
|
||||
attributes:attr::CollisionAttributesId,
|
||||
){
|
||||
let transform=integer::Planar64Affine3::from_translation(
|
||||
valve_transform(origin.into())
|
||||
@ -82,29 +83,60 @@ pub fn convert<'a>(
|
||||
)->PartialMap1{
|
||||
let bsp=bsp.as_ref();
|
||||
//figure out real attributes later
|
||||
let mut unique_attributes=Vec::new();
|
||||
unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration);
|
||||
unique_attributes.push(gameplay_attributes::CollisionAttributes::contact_default());
|
||||
unique_attributes.push(gameplay_attributes::CollisionAttributes::intersect_default());
|
||||
const ATTRIBUTE_DECORATION:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(0);
|
||||
const ATTRIBUTE_CONTACT_DEFAULT:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(1);
|
||||
const ATTRIBUTE_INTERSECT_DEFAULT:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(2);
|
||||
let unique_attributes=vec![
|
||||
attr::CollisionAttributes::Decoration,
|
||||
attr::CollisionAttributes::contact_default(),
|
||||
attr::CollisionAttributes::intersect_default(),
|
||||
// ladder
|
||||
attr::CollisionAttributes::Contact(
|
||||
attr::ContactAttributes{
|
||||
contacting:attr::ContactingAttributes{
|
||||
contact_behaviour:Some(attr::ContactingBehaviour::Ladder(
|
||||
attr::ContactingLadder{sticky:true}
|
||||
))
|
||||
},
|
||||
general:attr::GeneralAttributes::default(),
|
||||
}
|
||||
),
|
||||
// water
|
||||
attr::CollisionAttributes::Intersect(
|
||||
attr::IntersectAttributes{
|
||||
intersecting:attr::IntersectingAttributes{
|
||||
water:Some(attr::IntersectingWater{
|
||||
viscosity:integer::Planar64::ONE,
|
||||
density:integer::Planar64::ONE,
|
||||
velocity:integer::vec3::ZERO,
|
||||
}),
|
||||
},
|
||||
general:attr::GeneralAttributes::default(),
|
||||
}
|
||||
),
|
||||
];
|
||||
const ATTRIBUTE_DECORATION:attr::CollisionAttributesId=attr::CollisionAttributesId::new(0);
|
||||
const ATTRIBUTE_CONTACT_DEFAULT:attr::CollisionAttributesId=attr::CollisionAttributesId::new(1);
|
||||
const ATTRIBUTE_INTERSECT_DEFAULT:attr::CollisionAttributesId=attr::CollisionAttributesId::new(2);
|
||||
const ATTRIBUTE_LADDER_DEFAULT:attr::CollisionAttributesId=attr::CollisionAttributesId::new(3);
|
||||
const ATTRIBUTE_WATER_DEFAULT:attr::CollisionAttributesId=attr::CollisionAttributesId::new(4);
|
||||
|
||||
//declare all prop models to Loader
|
||||
let mut prop_models=bsp.static_props().map(|prop|{
|
||||
const DEG_TO_RAD:f32=std::f32::consts::TAU/360.0;
|
||||
//get or create mesh_id
|
||||
let mesh_id=mesh_deferred_loader.acquire_mesh_id(prop.model());
|
||||
let placement=prop.as_prop_placement();
|
||||
model::Model{
|
||||
mesh:mesh_id,
|
||||
attributes:ATTRIBUTE_DECORATION,
|
||||
transform:integer::Planar64Affine3::new(
|
||||
integer::mat3::try_from_f32_array_2d((
|
||||
glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale))
|
||||
integer::mat3::try_from_f32_array_2d(
|
||||
//TODO: figure this out
|
||||
*glam::Mat3A::from_quat(glam::Quat::from_array(placement.rotation.into()))
|
||||
).to_cols_array_2d()).unwrap(),
|
||||
valve_transform(placement.origin.into()),
|
||||
glam::Mat3A::from_euler(
|
||||
glam::EulerRot::XYZ,
|
||||
prop.angles.pitch*DEG_TO_RAD,
|
||||
prop.angles.yaw*DEG_TO_RAD,
|
||||
prop.angles.roll*DEG_TO_RAD
|
||||
).to_cols_array_2d()
|
||||
).unwrap(),
|
||||
valve_transform(prop.origin.into()),
|
||||
),
|
||||
color:glam::Vec4::ONE,
|
||||
}
|
||||
@ -177,52 +209,204 @@ pub fn convert<'a>(
|
||||
color:glam::Vec4::W,
|
||||
});
|
||||
|
||||
// THE CUBE OF DESTINY
|
||||
let destination_mesh_id=model::MeshId::new(world_meshes.len() as u32);
|
||||
world_meshes.push(crate::brush::unit_cube());
|
||||
|
||||
const WHITE:vbsp::Color=vbsp::Color{r:255,g:255,b:255};
|
||||
const ENTITY_ATTRIBUTE:attr::CollisionAttributesId=ATTRIBUTE_DECORATION;
|
||||
const ENTITY_TRIGGER_ATTRIBUTE:attr::CollisionAttributesId=ATTRIBUTE_INTERSECT_DEFAULT;
|
||||
for raw_ent in &bsp.entities{
|
||||
macro_rules! ent_brush_default{
|
||||
($entity:ident)=>{
|
||||
add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,$entity.model,$entity.origin,$entity.rendercolor,ENTITY_ATTRIBUTE)
|
||||
};
|
||||
} macro_rules! ent_brush_prop{
|
||||
($entity:ident)=>{
|
||||
add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,$entity.model,$entity.origin,WHITE,ENTITY_ATTRIBUTE)
|
||||
};
|
||||
}
|
||||
macro_rules! ent_brush_trigger{
|
||||
($entity:ident)=>{
|
||||
add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,$entity.model,$entity.origin,WHITE,ENTITY_TRIGGER_ATTRIBUTE)
|
||||
};
|
||||
}
|
||||
match raw_ent.parse(){
|
||||
Ok(Entity::Cycler(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::EnvSprite(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor.parse().unwrap_or(WHITE),ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncBreakable(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncBrush(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncButton(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncDoor(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncDoorRotating(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::AmbientGeneric(_ambient_generic))=>(),
|
||||
Ok(Entity::Cycler(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::EnvBeam(_env_beam))=>(),
|
||||
Ok(Entity::EnvBubbles(_env_bubbles))=>(),
|
||||
Ok(Entity::EnvDetailController(_env_detail_controller))=>(),
|
||||
Ok(Entity::EnvEmbers(_env_embers))=>(),
|
||||
Ok(Entity::EnvEntityMaker(_env_entity_maker))=>(),
|
||||
Ok(Entity::EnvExplosion(_env_explosion))=>(),
|
||||
Ok(Entity::EnvFade(_env_fade))=>(),
|
||||
Ok(Entity::EnvFire(_env_fire))=>(),
|
||||
Ok(Entity::EnvFireTrail(_env_fire_trail))=>(),
|
||||
Ok(Entity::EnvFiresource(_env_firesource))=>(),
|
||||
Ok(Entity::EnvFogController(_env_fog_controller))=>(),
|
||||
Ok(Entity::EnvHudhint(_env_hudhint))=>(),
|
||||
Ok(Entity::EnvLaser(_env_laser))=>(),
|
||||
Ok(Entity::EnvLightglow(_env_lightglow))=>(),
|
||||
Ok(Entity::EnvPhysexplosion(_env_physexplosion))=>(),
|
||||
Ok(Entity::EnvProjectedtexture(_env_projectedtexture))=>(),
|
||||
Ok(Entity::EnvScreenoverlay(_env_screenoverlay))=>(),
|
||||
Ok(Entity::EnvShake(_env_shake))=>(),
|
||||
Ok(Entity::EnvShooter(_env_shooter))=>(),
|
||||
Ok(Entity::EnvSmokestack(_env_smokestack))=>(),
|
||||
Ok(Entity::EnvSoundscape(_env_soundscape))=>(),
|
||||
Ok(Entity::EnvSoundscapeProxy(_env_soundscape_proxy))=>(),
|
||||
Ok(Entity::EnvSoundscapeTriggerable(_env_soundscape_triggerable))=>(),
|
||||
Ok(Entity::EnvSpark(_env_spark))=>(),
|
||||
Ok(Entity::EnvSprite(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::EnvSpritetrail(_env_spritetrail))=>(),
|
||||
Ok(Entity::EnvSteam(_env_steam))=>(),
|
||||
Ok(Entity::EnvSun(_env_sun))=>(),
|
||||
Ok(Entity::EnvTonemapController(_env_tonemap_controller))=>(),
|
||||
Ok(Entity::EnvWind(_env_wind))=>(),
|
||||
// trigger_teleport.filtername probably has to do with one of these
|
||||
Ok(Entity::FilterActivatorClass(_filter_activator_class))=>(),
|
||||
Ok(Entity::FilterActivatorName(_filter_activator_name))=>(),
|
||||
Ok(Entity::FilterDamageType(_filter_damage_type))=>(),
|
||||
Ok(Entity::FilterMulti(_filter_multi))=>(),
|
||||
Ok(Entity::FuncAreaportal(_func_areaportal))=>(),
|
||||
Ok(Entity::FuncAreaportalwindow(_func_areaportalwindow))=>(),
|
||||
Ok(Entity::FuncBombTarget(_func_bomb_target))=>(),
|
||||
Ok(Entity::FuncBreakable(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncBreakableSurf(_func_breakable_surf))=>(),
|
||||
Ok(Entity::FuncBrush(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncButton(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncBuyzone(_func_buyzone))=>(),
|
||||
Ok(Entity::FuncClipVphysics(_func_clip_vphysics))=>(),
|
||||
Ok(Entity::FuncConveyor(_func_conveyor))=>(),
|
||||
// FuncDoor is Platform
|
||||
Ok(Entity::FuncDoor(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncDoorRotating(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncDustcloud(_func_dustcloud))=>(),
|
||||
Ok(Entity::FuncDustmotes(_func_dustmotes))=>(),
|
||||
Ok(Entity::FuncFishPool(_func_fish_pool))=>(),
|
||||
Ok(Entity::FuncFootstepControl(_func_footstep_control))=>(),
|
||||
Ok(Entity::FuncHostageRescue(_func_hostage_rescue))=>(),
|
||||
Ok(Entity::FuncIllusionary(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncMonitor(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncMovelinear(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncPhysbox(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncPhysboxMultiplayer(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncRotButton(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncRotating(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncTracktrain(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncTrain(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncWall(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin.unwrap_or_default(),brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncWallToggle(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin.unwrap_or_default(),brush.rendercolor,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::FuncWaterAnalog(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor.unwrap_or(WHITE),ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::PropDoorRotating(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::PropDynamic(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::PropDynamicOverride(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::PropPhysics(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::PropPhysicsMultiplayer(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::PropPhysicsOverride(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::PropRagdoll(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerGravity(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerHurt(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerLook(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerMultiple(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model.unwrap_or_default(),brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerOnce(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerProximity(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerPush(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerSoundscape(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerTeleport(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model.unwrap_or_default(),brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerVphysicsMotion(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::TriggerWind(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,WHITE,ATTRIBUTE_DECORATION),
|
||||
Ok(Entity::InfoPlayerCounterterrorist(spawn))=>{
|
||||
found_spawn=Some(valve_transform(spawn.origin.into()));
|
||||
},
|
||||
Ok(Entity::InfoPlayerTerrorist(spawn))=>{
|
||||
found_spawn=Some(valve_transform(spawn.origin.into()));
|
||||
},
|
||||
Ok(Entity::FuncLod(_func_lod))=>(),
|
||||
Ok(Entity::FuncMonitor(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncMovelinear(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncOccluder(_func_occluder))=>(),
|
||||
Ok(Entity::FuncPhysbox(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncPhysboxMultiplayer(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncPrecipitation(_func_precipitation))=>(),
|
||||
Ok(Entity::FuncRotButton(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::FuncRotating(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncSmokevolume(_func_smokevolume))=>(),
|
||||
Ok(Entity::FuncTracktrain(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncTrain(brush))=>ent_brush_default!(brush),
|
||||
Ok(Entity::FuncWall(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin.unwrap_or_default(),brush.rendercolor,ENTITY_ATTRIBUTE),
|
||||
Ok(Entity::FuncWallToggle(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin.unwrap_or_default(),brush.rendercolor,ENTITY_ATTRIBUTE),
|
||||
Ok(Entity::FuncWaterAnalog(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model,brush.origin,brush.rendercolor.unwrap_or(WHITE),ENTITY_ATTRIBUTE),
|
||||
Ok(Entity::GamePlayerEquip(_game_player_equip))=>(),
|
||||
Ok(Entity::GameText(_game_text))=>(),
|
||||
Ok(Entity::GameUi(_game_ui))=>(),
|
||||
Ok(Entity::GameWeaponManager(_game_weapon_manager))=>(),
|
||||
Ok(Entity::HostageEntity(_hostage_entity))=>(),
|
||||
Ok(Entity::InfoCameraLink(_info_camera_link))=>(),
|
||||
Ok(Entity::InfoLadder(_info_ladder))=>(),
|
||||
Ok(Entity::InfoLightingRelative(_info_lighting_relative))=>(),
|
||||
Ok(Entity::InfoMapParameters(_info_map_parameters))=>(),
|
||||
Ok(Entity::InfoNode(_info_node))=>(),
|
||||
Ok(Entity::InfoNodeHint(_info_node_hint))=>(),
|
||||
Ok(Entity::InfoParticleSystem(_info_particle_system))=>(),
|
||||
Ok(Entity::InfoPlayerCounterterrorist(spawn))=>found_spawn=Some(spawn.origin),
|
||||
Ok(Entity::InfoPlayerLogo(_info_player_logo))=>(),
|
||||
Ok(Entity::InfoPlayerStart(_info_player_start))=>(),
|
||||
Ok(Entity::InfoPlayerTerrorist(spawn))=>found_spawn=Some(spawn.origin),
|
||||
Ok(Entity::InfoTarget(_info_target))=>(),
|
||||
// InfoTeleportDestination is Spawn#
|
||||
Ok(Entity::InfoTeleportDestination(_info_teleport_destination))=>(),
|
||||
Ok(Entity::Infodecal(_infodecal))=>(),
|
||||
Ok(Entity::KeyframeRope(_keyframe_rope))=>(),
|
||||
Ok(Entity::Light(_light))=>(),
|
||||
Ok(Entity::LightEnvironment(_light_environment))=>(),
|
||||
Ok(Entity::LightSpot(_light_spot))=>(),
|
||||
Ok(Entity::LogicAuto(_logic_auto))=>(),
|
||||
Ok(Entity::LogicBranch(_logic_branch))=>(),
|
||||
Ok(Entity::LogicCase(_logic_case))=>(),
|
||||
Ok(Entity::LogicCompare(_logic_compare))=>(),
|
||||
Ok(Entity::LogicMeasureMovement(_logic_measure_movement))=>(),
|
||||
Ok(Entity::LogicRelay(_logic_relay))=>(),
|
||||
Ok(Entity::LogicTimer(_logic_timer))=>(),
|
||||
Ok(Entity::MathCounter(_math_counter))=>(),
|
||||
Ok(Entity::MoveRope(_move_rope))=>(),
|
||||
Ok(Entity::PathTrack(_path_track))=>(),
|
||||
Ok(Entity::PhysBallsocket(_phys_ballsocket))=>(),
|
||||
Ok(Entity::PhysConstraint(_phys_constraint))=>(),
|
||||
Ok(Entity::PhysConstraintsystem(_phys_constraintsystem))=>(),
|
||||
Ok(Entity::PhysHinge(_phys_hinge))=>(),
|
||||
Ok(Entity::PhysKeepupright(_phys_keepupright))=>(),
|
||||
Ok(Entity::PhysLengthconstraint(_phys_lengthconstraint))=>(),
|
||||
Ok(Entity::PhysPulleyconstraint(_phys_pulleyconstraint))=>(),
|
||||
Ok(Entity::PhysRagdollconstraint(_phys_ragdollconstraint))=>(),
|
||||
Ok(Entity::PhysRagdollmagnet(_phys_ragdollmagnet))=>(),
|
||||
Ok(Entity::PhysThruster(_phys_thruster))=>(),
|
||||
Ok(Entity::PhysTorque(_phys_torque))=>(),
|
||||
Ok(Entity::PlayerSpeedmod(_player_speedmod))=>(),
|
||||
Ok(Entity::PlayerWeaponstrip(_player_weaponstrip))=>(),
|
||||
Ok(Entity::PointCamera(_point_camera))=>(),
|
||||
Ok(Entity::PointClientcommand(_point_clientcommand))=>(),
|
||||
Ok(Entity::PointDevshotCamera(_point_devshot_camera))=>(),
|
||||
Ok(Entity::PointServercommand(_point_servercommand))=>(),
|
||||
Ok(Entity::PointSpotlight(_point_spotlight))=>(),
|
||||
Ok(Entity::PointSurroundtest(_point_surroundtest))=>(),
|
||||
Ok(Entity::PointTemplate(_point_template))=>(),
|
||||
Ok(Entity::PointTesla(_point_tesla))=>(),
|
||||
Ok(Entity::PointViewcontrol(_point_viewcontrol))=>(),
|
||||
Ok(Entity::PropDoorRotating(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::PropDynamic(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::PropDynamicOverride(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::PropPhysics(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::PropPhysicsMultiplayer(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::PropPhysicsOverride(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::PropRagdoll(brush))=>ent_brush_prop!(brush),
|
||||
Ok(Entity::ShadowControl(_shadow_control))=>(),
|
||||
Ok(Entity::SkyCamera(_sky_camera))=>(),
|
||||
Ok(Entity::TriggerGravity(brush))=>ent_brush_trigger!(brush),
|
||||
Ok(Entity::TriggerHurt(brush))=>ent_brush_trigger!(brush),
|
||||
Ok(Entity::TriggerLook(brush))=>ent_brush_trigger!(brush),
|
||||
Ok(Entity::TriggerMultiple(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model.unwrap_or_default(),brush.origin,WHITE,ENTITY_TRIGGER_ATTRIBUTE),
|
||||
Ok(Entity::TriggerOnce(brush))=>ent_brush_trigger!(brush),
|
||||
Ok(Entity::TriggerProximity(brush))=>ent_brush_trigger!(brush),
|
||||
// TriggerPush is booster
|
||||
Ok(Entity::TriggerPush(brush))=>ent_brush_trigger!(brush),
|
||||
Ok(Entity::TriggerSoundscape(brush))=>ent_brush_trigger!(brush),
|
||||
// TriggerTeleport is Trigger#
|
||||
Ok(Entity::TriggerTeleport(brush))=>add_brush(mesh_deferred_loader,&mut world_models,&mut prop_models,brush.model.unwrap_or_default(),brush.origin,WHITE,ENTITY_TRIGGER_ATTRIBUTE),
|
||||
Ok(Entity::TriggerVphysicsMotion(brush))=>ent_brush_trigger!(brush),
|
||||
Ok(Entity::TriggerWind(brush))=>ent_brush_trigger!(brush),
|
||||
Ok(Entity::WaterLodControl(_water_lod_control))=>(),
|
||||
Ok(Entity::WeaponAk47(_weapon_ak47))=>(),
|
||||
Ok(Entity::WeaponAwp(_weapon_awp))=>(),
|
||||
Ok(Entity::WeaponDeagle(_weapon_deagle))=>(),
|
||||
Ok(Entity::WeaponElite(_weapon_elite))=>(),
|
||||
Ok(Entity::WeaponFamas(_weapon_famas))=>(),
|
||||
Ok(Entity::WeaponFiveseven(_weapon_fiveseven))=>(),
|
||||
Ok(Entity::WeaponFlashbang(_weapon_flashbang))=>(),
|
||||
Ok(Entity::WeaponG3sg1(_weapon_g3sg1))=>(),
|
||||
Ok(Entity::WeaponGlock(_weapon_glock))=>(),
|
||||
Ok(Entity::WeaponHegrenade(_weapon_hegrenade))=>(),
|
||||
Ok(Entity::WeaponKnife(_weapon_knife))=>(),
|
||||
Ok(Entity::WeaponM249(_weapon_m249))=>(),
|
||||
Ok(Entity::WeaponM3(_weapon_m3))=>(),
|
||||
Ok(Entity::WeaponM4a1(_weapon_m4a1))=>(),
|
||||
Ok(Entity::WeaponMac10(_weapon_mac10))=>(),
|
||||
Ok(Entity::WeaponP228(_weapon_p228))=>(),
|
||||
Ok(Entity::WeaponP90(_weapon_p90))=>(),
|
||||
Ok(Entity::WeaponScout(_weapon_scout))=>(),
|
||||
Ok(Entity::WeaponSg550(_weapon_sg550))=>(),
|
||||
Ok(Entity::WeaponSmokegrenade(_weapon_smokegrenade))=>(),
|
||||
Ok(Entity::WeaponTmp(_weapon_tmp))=>(),
|
||||
Ok(Entity::WeaponUmp45(_weapon_ump45))=>(),
|
||||
Ok(Entity::WeaponUsp(_weapon_usp))=>(),
|
||||
Ok(Entity::WeaponXm1014(_weapon_xm1014))=>(),
|
||||
Ok(Entity::Worldspawn(_worldspawn))=>(),
|
||||
Err(e)=>{
|
||||
println!("Bsp Entity parse error: {e}");
|
||||
},
|
||||
@ -232,9 +416,27 @@ pub fn convert<'a>(
|
||||
|
||||
// physics models
|
||||
for brush in &bsp.brushes{
|
||||
if !brush.flags.contains(vbsp::BrushFlags::SOLID){
|
||||
const RELEVANT:vbsp::BrushFlags=
|
||||
vbsp::BrushFlags::SOLID
|
||||
.union(vbsp::BrushFlags::PLAYERCLIP)
|
||||
.union(vbsp::BrushFlags::WATER)
|
||||
.union(vbsp::BrushFlags::MOVEABLE)
|
||||
.union(vbsp::BrushFlags::LADDER);
|
||||
if !brush.flags.intersects(RELEVANT){
|
||||
continue;
|
||||
}
|
||||
let is_ladder=brush.flags.contains(vbsp::BrushFlags::LADDER);
|
||||
let is_water=brush.flags.contains(vbsp::BrushFlags::WATER);
|
||||
let attributes=match (is_ladder,is_water){
|
||||
(true,false)=>ATTRIBUTE_LADDER_DEFAULT,
|
||||
(false,true)=>ATTRIBUTE_WATER_DEFAULT,
|
||||
(false,false)=>ATTRIBUTE_CONTACT_DEFAULT,
|
||||
(true,true)=>{
|
||||
// water ladder? wtf
|
||||
println!("brush is a water ladder o_o defaulting to ladder");
|
||||
ATTRIBUTE_LADDER_DEFAULT
|
||||
}
|
||||
};
|
||||
let mesh_result=crate::brush::brush_to_mesh(bsp,brush);
|
||||
match mesh_result{
|
||||
Ok(mesh)=>{
|
||||
@ -242,7 +444,7 @@ pub fn convert<'a>(
|
||||
world_meshes.push(mesh);
|
||||
world_models.push(model::Model{
|
||||
mesh:mesh_id,
|
||||
attributes:ATTRIBUTE_CONTACT_DEFAULT,
|
||||
attributes,
|
||||
transform:integer::Planar64Affine3::new(
|
||||
integer::mat3::identity(),
|
||||
integer::vec3::ZERO,
|
||||
@ -256,27 +458,24 @@ pub fn convert<'a>(
|
||||
|
||||
let mut modes_list=Vec::new();
|
||||
if let Some(spawn_point)=found_spawn{
|
||||
// create a new mesh
|
||||
let mesh_id=model::MeshId::new(world_meshes.len() as u32);
|
||||
world_meshes.push(crate::brush::unit_cube());
|
||||
// create a new model
|
||||
let model_id=model::ModelId::new(world_models.len() as u32);
|
||||
world_models.push(model::Model{
|
||||
mesh:mesh_id,
|
||||
mesh:destination_mesh_id,
|
||||
attributes:ATTRIBUTE_INTERSECT_DEFAULT,
|
||||
transform:integer::Planar64Affine3::from_translation(spawn_point),
|
||||
transform:integer::Planar64Affine3::from_translation(valve_transform(spawn_point.into())),
|
||||
color:glam::Vec4::W,
|
||||
});
|
||||
|
||||
let first_stage=strafesnet_common::gameplay_modes::Stage::empty(model_id);
|
||||
let main_mode=strafesnet_common::gameplay_modes::Mode::new(
|
||||
let first_stage=Stage::empty(model_id);
|
||||
let main_mode=Mode::new(
|
||||
strafesnet_common::gameplay_style::StyleModifiers::source_bhop(),
|
||||
model_id,
|
||||
std::collections::HashMap::new(),
|
||||
vec![first_stage],
|
||||
std::collections::HashMap::new(),
|
||||
);
|
||||
modes_list.push(main_mode);
|
||||
modes_list.push(NormalizedMode::new(main_mode));
|
||||
}
|
||||
|
||||
PartialMap1{
|
||||
@ -284,17 +483,17 @@ pub fn convert<'a>(
|
||||
world_meshes,
|
||||
prop_models,
|
||||
world_models,
|
||||
modes:strafesnet_common::gameplay_modes::Modes::new(modes_list),
|
||||
modes:NormalizedModes::new(modes_list),
|
||||
}
|
||||
}
|
||||
|
||||
//partially constructed map types
|
||||
pub struct PartialMap1{
|
||||
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
|
||||
attributes:Vec<attr::CollisionAttributes>,
|
||||
prop_models:Vec<model::Model>,
|
||||
world_meshes:Vec<model::Mesh>,
|
||||
world_models:Vec<model::Model>,
|
||||
modes:strafesnet_common::gameplay_modes::Modes,
|
||||
modes:NormalizedModes,
|
||||
}
|
||||
impl PartialMap1{
|
||||
pub fn add_prop_meshes<'a>(
|
||||
@ -312,12 +511,12 @@ impl PartialMap1{
|
||||
}
|
||||
}
|
||||
pub struct PartialMap2{
|
||||
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
|
||||
attributes:Vec<attr::CollisionAttributes>,
|
||||
prop_meshes:Vec<(model::MeshId,model::Mesh)>,
|
||||
prop_models:Vec<model::Model>,
|
||||
world_meshes:Vec<model::Mesh>,
|
||||
world_models:Vec<model::Model>,
|
||||
modes:strafesnet_common::gameplay_modes::Modes,
|
||||
modes:NormalizedModes,
|
||||
}
|
||||
impl PartialMap2{
|
||||
pub fn add_render_configs_and_textures(
|
||||
|
@ -7,46 +7,57 @@ pub struct Aabb{
|
||||
}
|
||||
|
||||
impl Default for Aabb{
|
||||
#[inline]
|
||||
fn default()->Self{
|
||||
Self{min:vec3::MAX,max:vec3::MIN}
|
||||
}
|
||||
}
|
||||
|
||||
impl Aabb{
|
||||
#[inline]
|
||||
pub const fn new(min:Planar64Vec3,max:Planar64Vec3)->Self{
|
||||
Self{min,max}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn max(&self)->Planar64Vec3{
|
||||
self.max
|
||||
}
|
||||
#[inline]
|
||||
pub const fn min(&self)->Planar64Vec3{
|
||||
self.min
|
||||
}
|
||||
#[inline]
|
||||
pub fn grow(&mut self,point:Planar64Vec3){
|
||||
self.min=self.min.min(point);
|
||||
self.max=self.max.max(point);
|
||||
}
|
||||
#[inline]
|
||||
pub fn join(&mut self,aabb:&Aabb){
|
||||
self.min=self.min.min(aabb.min);
|
||||
self.max=self.max.max(aabb.max);
|
||||
}
|
||||
#[inline]
|
||||
pub fn inflate(&mut self,hs:Planar64Vec3){
|
||||
self.min-=hs;
|
||||
self.max+=hs;
|
||||
}
|
||||
#[inline]
|
||||
pub fn contains(&self,point:Planar64Vec3)->bool{
|
||||
let bvec=self.min.lt(point)&point.lt(self.max);
|
||||
bvec.all()
|
||||
}
|
||||
#[inline]
|
||||
pub fn intersects(&self,aabb:&Aabb)->bool{
|
||||
let bvec=self.min.lt(aabb.max)&aabb.min.lt(self.max);
|
||||
bvec.all()
|
||||
}
|
||||
#[inline]
|
||||
pub fn size(&self)->Planar64Vec3{
|
||||
self.max-self.min
|
||||
}
|
||||
#[inline]
|
||||
pub fn center(&self)->Planar64Vec3{
|
||||
self.min+(self.max-self.min)>>1
|
||||
self.min.map_zip(self.max,|(min,max)|min.midpoint(max))
|
||||
}
|
||||
//probably use floats for area & volume because we don't care about precision
|
||||
// pub fn area_weight(&self)->f32{
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::collections::{HashSet,HashMap};
|
||||
use crate::model::ModelId;
|
||||
use crate::gameplay_style;
|
||||
use crate::updatable::Updatable;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StageElement{
|
||||
@ -128,18 +127,6 @@ impl Stage{
|
||||
self.unordered_checkpoints.contains(&model_id)
|
||||
}
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct StageUpdate{
|
||||
//other behaviour models of this stage can have
|
||||
ordered_checkpoints:HashMap<CheckpointId,ModelId>,
|
||||
unordered_checkpoints:HashSet<ModelId>,
|
||||
}
|
||||
impl Updatable<StageUpdate> for Stage{
|
||||
fn update(&mut self,update:StageUpdate){
|
||||
self.ordered_checkpoints.extend(update.ordered_checkpoints);
|
||||
self.unordered_checkpoints.extend(update.unordered_checkpoints);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub enum Zone{
|
||||
@ -211,34 +198,47 @@ impl Mode{
|
||||
pub fn push_stage(&mut self,stage:Stage){
|
||||
self.stages.push(stage)
|
||||
}
|
||||
pub fn get_stage_mut(&mut self,stage:StageId)->Option<&mut Stage>{
|
||||
self.stages.get_mut(stage.0 as usize)
|
||||
pub fn get_stage_mut(&mut self,StageId(stage_id):StageId)->Option<&mut Stage>{
|
||||
self.stages.get_mut(stage_id as usize)
|
||||
}
|
||||
pub fn get_spawn_model_id(&self,stage:StageId)->Option<ModelId>{
|
||||
self.stages.get(stage.0 as usize).map(|s|s.spawn)
|
||||
pub fn get_spawn_model_id(&self,StageId(stage_id):StageId)->Option<ModelId>{
|
||||
self.stages.get(stage_id as usize).map(|s|s.spawn)
|
||||
}
|
||||
pub fn get_zone(&self,model_id:ModelId)->Option<&Zone>{
|
||||
self.zones.get(&model_id)
|
||||
}
|
||||
pub fn get_stage(&self,stage_id:StageId)->Option<&Stage>{
|
||||
self.stages.get(stage_id.0 as usize)
|
||||
pub fn get_stage(&self,StageId(stage_id):StageId)->Option<&Stage>{
|
||||
self.stages.get(stage_id as usize)
|
||||
}
|
||||
pub fn get_element(&self,model_id:ModelId)->Option<&StageElement>{
|
||||
self.elements.get(&model_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NormalizedMode(Mode);
|
||||
impl NormalizedMode{
|
||||
pub fn new(mode:Mode)->Self{
|
||||
Self(mode)
|
||||
}
|
||||
pub fn into_inner(self)->Mode{
|
||||
let Self(mode)=self;
|
||||
mode
|
||||
}
|
||||
//TODO: put this in the SNF
|
||||
pub fn denormalize_data(&mut self){
|
||||
pub fn denormalize(self)->Mode{
|
||||
let NormalizedMode(mut mode)=self;
|
||||
//expand and index normalized data
|
||||
self.zones.insert(self.start,Zone::Start);
|
||||
for (stage_id,stage) in self.stages.iter().enumerate(){
|
||||
self.elements.insert(stage.spawn,StageElement{
|
||||
mode.zones.insert(mode.start,Zone::Start);
|
||||
for (stage_id,stage) in mode.stages.iter().enumerate(){
|
||||
mode.elements.insert(stage.spawn,StageElement{
|
||||
stage_id:StageId(stage_id as u32),
|
||||
force:false,
|
||||
behaviour:StageElementBehaviour::SpawnAt,
|
||||
jump_limit:None,
|
||||
});
|
||||
for (_,&model) in &stage.ordered_checkpoints{
|
||||
self.elements.insert(model,StageElement{
|
||||
mode.elements.insert(model,StageElement{
|
||||
stage_id:StageId(stage_id as u32),
|
||||
force:false,
|
||||
behaviour:StageElementBehaviour::Checkpoint,
|
||||
@ -246,7 +246,7 @@ impl Mode{
|
||||
});
|
||||
}
|
||||
for &model in &stage.unordered_checkpoints{
|
||||
self.elements.insert(model,StageElement{
|
||||
mode.elements.insert(model,StageElement{
|
||||
stage_id:StageId(stage_id as u32),
|
||||
force:false,
|
||||
behaviour:StageElementBehaviour::Checkpoint,
|
||||
@ -254,53 +254,13 @@ impl Mode{
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//this would be nice as a macro
|
||||
#[derive(Default)]
|
||||
pub struct ModeUpdate{
|
||||
zones:HashMap<ModelId,Zone>,
|
||||
stages:HashMap<StageId,StageUpdate>,
|
||||
//mutually exlusive stage element behaviour
|
||||
elements:HashMap<ModelId,StageElement>,
|
||||
}
|
||||
impl Updatable<ModeUpdate> for Mode{
|
||||
fn update(&mut self,update:ModeUpdate){
|
||||
self.zones.extend(update.zones);
|
||||
for (stage,stage_update) in update.stages{
|
||||
if let Some(stage)=self.stages.get_mut(stage.0 as usize){
|
||||
stage.update(stage_update);
|
||||
}
|
||||
}
|
||||
self.elements.extend(update.elements);
|
||||
}
|
||||
}
|
||||
impl ModeUpdate{
|
||||
pub fn zone(model_id:ModelId,zone:Zone)->Self{
|
||||
let mut mu=Self::default();
|
||||
mu.zones.insert(model_id,zone);
|
||||
mu
|
||||
}
|
||||
pub fn stage(stage_id:StageId,stage_update:StageUpdate)->Self{
|
||||
let mut mu=Self::default();
|
||||
mu.stages.insert(stage_id,stage_update);
|
||||
mu
|
||||
}
|
||||
pub fn element(model_id:ModelId,element:StageElement)->Self{
|
||||
let mut mu=Self::default();
|
||||
mu.elements.insert(model_id,element);
|
||||
mu
|
||||
}
|
||||
pub fn 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);
|
||||
}
|
||||
mode
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default,Clone)]
|
||||
pub struct Modes{
|
||||
pub modes:Vec<Mode>,
|
||||
modes:Vec<Mode>,
|
||||
}
|
||||
impl Modes{
|
||||
pub const fn new(modes:Vec<Mode>)->Self{
|
||||
@ -314,19 +274,182 @@ impl Modes{
|
||||
pub fn push_mode(&mut self,mode:Mode){
|
||||
self.modes.push(mode)
|
||||
}
|
||||
pub fn get_mode(&self,mode:ModeId)->Option<&Mode>{
|
||||
self.modes.get(mode.0 as usize)
|
||||
pub fn get_mode(&self,ModeId(mode_id):ModeId)->Option<&Mode>{
|
||||
self.modes.get(mode_id as usize)
|
||||
}
|
||||
}
|
||||
pub struct ModesUpdate{
|
||||
modes:HashMap<ModeId,ModeUpdate>,
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NormalizedModes{
|
||||
modes:Vec<NormalizedMode>,
|
||||
}
|
||||
impl Updatable<ModesUpdate> for Modes{
|
||||
fn update(&mut self,update:ModesUpdate){
|
||||
for (mode,mode_update) in update.modes{
|
||||
if let Some(mode)=self.modes.get_mut(mode.0 as usize){
|
||||
mode.update(mode_update);
|
||||
}
|
||||
impl NormalizedModes{
|
||||
pub fn new(modes:Vec<NormalizedMode>)->Self{
|
||||
Self{modes}
|
||||
}
|
||||
pub fn len(&self)->usize{
|
||||
self.modes.len()
|
||||
}
|
||||
pub fn denormalize(self)->Modes{
|
||||
Modes{
|
||||
modes:self.modes.into_iter().map(NormalizedMode::denormalize).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IntoIterator for NormalizedModes{
|
||||
type Item=<Vec<NormalizedMode> as IntoIterator>::Item;
|
||||
type IntoIter=<Vec<NormalizedMode> as IntoIterator>::IntoIter;
|
||||
fn into_iter(self)->Self::IntoIter{
|
||||
self.modes.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct StageUpdate{
|
||||
//other behaviour models of this stage can have
|
||||
ordered_checkpoints:HashMap<CheckpointId,ModelId>,
|
||||
unordered_checkpoints:HashSet<ModelId>,
|
||||
}
|
||||
impl StageUpdate{
|
||||
fn apply_to(self,stage:&mut Stage){
|
||||
stage.ordered_checkpoints.extend(self.ordered_checkpoints);
|
||||
stage.unordered_checkpoints.extend(self.unordered_checkpoints);
|
||||
}
|
||||
}
|
||||
|
||||
//this would be nice as a macro
|
||||
#[derive(Default)]
|
||||
pub struct ModeUpdate{
|
||||
zones:Option<(ModelId,Zone)>,
|
||||
stages:Option<(StageId,StageUpdate)>,
|
||||
//mutually exlusive stage element behaviour
|
||||
elements:Option<(ModelId,StageElement)>,
|
||||
}
|
||||
impl ModeUpdate{
|
||||
fn apply_to(self,mode:&mut Mode){
|
||||
mode.zones.extend(self.zones);
|
||||
if let Some((StageId(stage_id),stage_update))=self.stages{
|
||||
if let Some(stage)=mode.stages.get_mut(stage_id as usize){
|
||||
stage_update.apply_to(stage);
|
||||
}
|
||||
}
|
||||
mode.elements.extend(self.elements);
|
||||
}
|
||||
}
|
||||
impl ModeUpdate{
|
||||
pub fn zone(model_id:ModelId,zone:Zone)->Self{
|
||||
Self{
|
||||
zones:Some((model_id,zone)),
|
||||
stages:None,
|
||||
elements:None,
|
||||
}
|
||||
}
|
||||
pub fn stage(stage_id:StageId,stage_update:StageUpdate)->Self{
|
||||
Self{
|
||||
zones:None,
|
||||
stages:Some((stage_id,stage_update)),
|
||||
elements:None,
|
||||
}
|
||||
}
|
||||
pub fn element(model_id:ModelId,element:StageElement)->Self{
|
||||
Self{
|
||||
zones:None,
|
||||
stages:None,
|
||||
elements:Some((model_id,element)),
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ModeBuilder{
|
||||
mode:Mode,
|
||||
stage_id_map:HashMap<StageId,StageId>,
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct ModesBuilder{
|
||||
modes:HashMap<ModeId,Mode>,
|
||||
stages:HashMap<ModeId,HashMap<StageId,Stage>>,
|
||||
mode_updates:Vec<(ModeId,ModeUpdate)>,
|
||||
stage_updates:Vec<(ModeId,StageId,StageUpdate)>,
|
||||
}
|
||||
impl ModesBuilder{
|
||||
pub fn build_normalized(mut self)->NormalizedModes{
|
||||
//collect modes and stages into contiguous arrays
|
||||
let mut unique_modes:Vec<(ModeId,Mode)>
|
||||
=self.modes.into_iter().collect();
|
||||
unique_modes.sort_by_key(|&(mode_id,_)|mode_id);
|
||||
let (mut modes,mode_id_map):(Vec<ModeBuilder>,HashMap<ModeId,ModeId>)
|
||||
=unique_modes.into_iter().enumerate()
|
||||
.map(|(final_mode_id,(builder_mode_id,mut mode))|{
|
||||
(
|
||||
ModeBuilder{
|
||||
stage_id_map:self.stages.remove(&builder_mode_id).map_or_else(||HashMap::new(),|stages|{
|
||||
let mut unique_stages:Vec<(StageId,Stage)>
|
||||
=stages.into_iter().collect();
|
||||
unique_stages.sort_by_key(|&(StageId(stage_id),_)|stage_id);
|
||||
unique_stages.into_iter().enumerate()
|
||||
.map(|(final_stage_id,(builder_stage_id,stage))|{
|
||||
mode.push_stage(stage);
|
||||
(builder_stage_id,StageId::new(final_stage_id as u32))
|
||||
}).collect()
|
||||
}),
|
||||
mode,
|
||||
},
|
||||
(
|
||||
builder_mode_id,
|
||||
ModeId::new(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)=mode_id_map.get(&builder_mode_id){
|
||||
if let Some(mode)=modes.get_mut(final_mode_id.get() as usize){
|
||||
if let Some(&final_stage_id)=mode.stage_id_map.get(&builder_stage_id){
|
||||
if let Some(stage)=mode.mode.get_stage_mut(final_stage_id){
|
||||
stage_update.apply_to(stage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//push mode updates
|
||||
for (builder_mode_id,mut mode_update) in self.mode_updates{
|
||||
if let Some(final_mode_id)=mode_id_map.get(&builder_mode_id){
|
||||
if let Some(mode)=modes.get_mut(final_mode_id.get() as usize){
|
||||
//map stage id on stage elements
|
||||
mode_update.map_stage_element_ids(|stage_id|
|
||||
//walk down one stage id at a time until a stage is found
|
||||
//TODO use better logic like BTreeMap::upper_bound instead of walking
|
||||
// final_stage_id_from_builder_stage_id.upper_bound(Bound::Included(&stage_id))
|
||||
// .value().copied().unwrap_or(StageId::FIRST)
|
||||
(0..=stage_id.get()).rev().find_map(|builder_stage_id|
|
||||
//map the stage element to that stage
|
||||
mode.stage_id_map.get(&StageId::new(builder_stage_id)).copied()
|
||||
).unwrap_or(StageId::FIRST)
|
||||
);
|
||||
mode_update.apply_to(&mut mode.mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
NormalizedModes::new(modes.into_iter().map(|mode_builder|NormalizedMode(mode_builder.mode)).collect())
|
||||
}
|
||||
pub fn insert_mode(&mut self,mode_id:ModeId,mode:Mode){
|
||||
assert!(self.modes.insert(mode_id,mode).is_none(),"Cannot replace existing mode");
|
||||
}
|
||||
pub fn insert_stage(&mut self,mode_id:ModeId,stage_id:StageId,stage:Stage){
|
||||
assert!(self.stages.entry(mode_id).or_insert(HashMap::new()).insert(stage_id,stage).is_none(),"Cannot replace existing stage");
|
||||
}
|
||||
pub fn push_mode_update(&mut self,mode_id:ModeId,mode_update:ModeUpdate){
|
||||
self.mode_updates.push((mode_id,mode_update));
|
||||
}
|
||||
// fn push_stage_update(&mut self,mode_id:ModeId,stage_id:StageId,stage_update:StageUpdate){
|
||||
// self.stage_updates.push((mode_id,stage_id,stage_update));
|
||||
// }
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ impl JumpImpulse{
|
||||
velocity:Planar64Vec3,
|
||||
jump_dir:Planar64Vec3,
|
||||
gravity:&Planar64Vec3,
|
||||
mass:Planar64,
|
||||
_mass:Planar64,
|
||||
)->Planar64Vec3{
|
||||
match self{
|
||||
&JumpImpulse::Time(time)=>velocity-(*gravity*time).map(|t|t.divide().fix_1()),
|
||||
@ -78,7 +78,7 @@ impl JumpImpulse{
|
||||
velocity-(*gravity*(radicand.sqrt().fix_2()+v_g)/gg).divide().fix_1()
|
||||
},
|
||||
&JumpImpulse::Linear(jump_speed)=>velocity+(jump_dir*jump_speed/jump_dir.length()).divide().fix_1(),
|
||||
&JumpImpulse::Energy(energy)=>{
|
||||
&JumpImpulse::Energy(_energy)=>{
|
||||
//calculate energy
|
||||
//let e=gravity.dot(velocity);
|
||||
//add
|
||||
@ -355,7 +355,7 @@ pub struct LadderSettings{
|
||||
pub dot:Planar64,
|
||||
}
|
||||
impl LadderSettings{
|
||||
pub const fn accel(&self,target_diff:Planar64Vec3,gravity:Planar64Vec3)->Planar64{
|
||||
pub const fn accel(&self,_target_diff:Planar64Vec3,_gravity:Planar64Vec3)->Planar64{
|
||||
//TODO: fallible ladder accel
|
||||
self.accelerate.accel
|
||||
}
|
||||
@ -529,12 +529,12 @@ impl StyleModifiers{
|
||||
|
||||
pub fn source_bhop()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::all()-Controls::MoveUp-Controls::MoveDown,
|
||||
controls_mask:Controls::all(),
|
||||
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).fix_1(),
|
||||
air_accel_limit:Some(Planar64::raw((150<<28)*100)),
|
||||
mv:Planar64::raw(30<<28),
|
||||
tick_rate:Ratio64::new(100,AbsoluteTime::ONE_SECOND.get() as u64).unwrap(),
|
||||
}),
|
||||
jump:Some(JumpSettings{
|
||||
@ -570,12 +570,12 @@ impl StyleModifiers{
|
||||
}
|
||||
pub fn source_surf()->Self{
|
||||
Self{
|
||||
controls_mask:Controls::all()-Controls::MoveUp-Controls::MoveDown,
|
||||
controls_mask:Controls::all(),
|
||||
controls_mask_state:Controls::all(),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:ControlsActivation::full_2d(),
|
||||
air_accel_limit:Some((int(150)*66*VALVE_SCALE).fix_1()),
|
||||
mv:(int(30)*VALVE_SCALE).fix_1(),
|
||||
mv:Planar64::raw(30<<28),
|
||||
tick_rate:Ratio64::new(66,AbsoluteTime::ONE_SECOND.get() as u64).unwrap(),
|
||||
}),
|
||||
jump:Some(JumpSettings{
|
||||
|
@ -9,7 +9,6 @@ pub mod timer;
|
||||
pub mod integer;
|
||||
pub mod physics;
|
||||
pub mod session;
|
||||
pub mod updatable;
|
||||
pub mod instruction;
|
||||
pub mod gameplay_attributes;
|
||||
pub mod gameplay_modes;
|
||||
|
@ -4,7 +4,7 @@ use crate::gameplay_attributes;
|
||||
//this is a temporary struct to try to get the code running again
|
||||
//TODO: use snf::map::Region to update the data in physics and graphics instead of this
|
||||
pub struct CompleteMap{
|
||||
pub modes:gameplay_modes::Modes,
|
||||
pub modes:gameplay_modes::NormalizedModes,
|
||||
pub attributes:Vec<gameplay_attributes::CollisionAttributes>,
|
||||
pub meshes:Vec<model::Mesh>,
|
||||
pub models:Vec<model::Model>,
|
||||
|
@ -1,57 +0,0 @@
|
||||
// This whole thing should be a drive macro
|
||||
|
||||
pub trait Updatable<Updater>{
|
||||
fn update(&mut self,update:Updater);
|
||||
}
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
struct InnerId(u32);
|
||||
#[derive(Clone)]
|
||||
struct Inner{
|
||||
id:InnerId,
|
||||
enabled:bool,
|
||||
}
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
struct OuterId(u32);
|
||||
struct Outer{
|
||||
id:OuterId,
|
||||
inners:std::collections::HashMap<InnerId,Inner>,
|
||||
}
|
||||
|
||||
enum Update<I,U>{
|
||||
Insert(I),
|
||||
Update(U),
|
||||
Remove
|
||||
}
|
||||
|
||||
struct InnerUpdate{
|
||||
//#[updatable(Update)]
|
||||
enabled:Option<bool>,
|
||||
}
|
||||
struct OuterUpdate{
|
||||
//#[updatable(Insert,Update,Remove)]
|
||||
inners:std::collections::HashMap<InnerId,Update<Inner,InnerUpdate>>,
|
||||
//#[updatable(Update)]
|
||||
//inners:std::collections::HashMap<InnerId,InnerUpdate>,
|
||||
}
|
||||
impl Updatable<InnerUpdate> for Inner{
|
||||
fn update(&mut self,update:InnerUpdate){
|
||||
if let Some(enabled)=update.enabled{
|
||||
self.enabled=enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Updatable<OuterUpdate> for Outer{
|
||||
fn update(&mut self,update:OuterUpdate){
|
||||
for (id,up) in update.inners{
|
||||
match up{
|
||||
Update::Insert(new_inner)=>self.inners.insert(id,new_inner),
|
||||
Update::Update(inner_update)=>self.inners.get_mut(&id).map(|inner|{
|
||||
let old=inner.clone();
|
||||
inner.update(inner_update);
|
||||
old
|
||||
}),
|
||||
Update::Remove=>self.inners.remove(&id),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ wide-mul=[]
|
||||
zeroes=["dep:arrayvec"]
|
||||
|
||||
[dependencies]
|
||||
bnum = "0.12.0"
|
||||
bnum = "0.13.0"
|
||||
arrayvec = { version = "0.7.6", optional = true }
|
||||
paste = "1.0.15"
|
||||
ratio_ops = { version = "0.1.0", path = "../ratio_ops", registry = "strafesnet", optional = true }
|
||||
|
@ -33,6 +33,14 @@ impl<const N:usize,const F:usize> Fixed<N,F>{
|
||||
self.bits
|
||||
}
|
||||
#[inline]
|
||||
pub const fn as_bits(&self)->&BInt<N>{
|
||||
&self.bits
|
||||
}
|
||||
#[inline]
|
||||
pub const fn as_bits_mut(&mut self)->&mut BInt<N>{
|
||||
&mut self.bits
|
||||
}
|
||||
#[inline]
|
||||
pub const fn raw_digit(value:i64)->Self{
|
||||
let mut digits=[0u64;N];
|
||||
digits[0]=value.abs() as u64;
|
||||
@ -56,6 +64,10 @@ impl<const N:usize,const F:usize> Fixed<N,F>{
|
||||
pub const fn abs(self)->Self{
|
||||
Self::from_bits(self.bits.abs())
|
||||
}
|
||||
#[inline]
|
||||
pub const fn midpoint(self,other:Self)->Self{
|
||||
Self::from_bits(self.bits.midpoint(other.bits))
|
||||
}
|
||||
}
|
||||
impl<const F:usize> Fixed<1,F>{
|
||||
/// My old code called this function everywhere so let's provide it
|
||||
@ -788,13 +800,10 @@ macro_rules! impl_not_const_generic{
|
||||
let wide_self=self.[<fix_ $_2n>]();
|
||||
//descend down the bits and check if flipping each bit would push the square over the input value
|
||||
for shift in (0..=max_shift).rev(){
|
||||
let new_result={
|
||||
let mut bits=result.to_bits().to_bits();
|
||||
bits.set_bit(shift,true);
|
||||
Self::from_bits(BInt::from_bits(bits))
|
||||
};
|
||||
if new_result.[<wide_mul_ $n _ $n>](new_result)<=wide_self{
|
||||
result=new_result;
|
||||
result.as_bits_mut().as_bits_mut().set_bit(shift,true);
|
||||
if wide_self<result.[<wide_mul_ $n _ $n>](result){
|
||||
// put it back lol
|
||||
result.as_bits_mut().as_bits_mut().set_bit(shift,false);
|
||||
}
|
||||
}
|
||||
result
|
||||
|
@ -84,13 +84,13 @@ where
|
||||
fn ingest_faces2_lods3(
|
||||
polygon_groups:&mut Vec<PolygonGroup>,
|
||||
vertex_id_map:&HashMap<rbx_mesh::mesh::VertexId2,VertexId>,
|
||||
faces:&Vec<rbx_mesh::mesh::Face2>,
|
||||
lods:&Vec<rbx_mesh::mesh::Lod3>
|
||||
faces:&[rbx_mesh::mesh::Face2],
|
||||
lods:&[rbx_mesh::mesh::Lod3],
|
||||
){
|
||||
//faces have to be split into polygon groups based on lod
|
||||
polygon_groups.extend(lods.windows(2).map(|lod_pair|
|
||||
PolygonGroup::PolygonList(PolygonList::new(faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize].iter().map(|face|
|
||||
vec![vertex_id_map[&face.0],vertex_id_map[&face.1],vertex_id_map[&face.2]]
|
||||
PolygonGroup::PolygonList(PolygonList::new(faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize].iter().map(|rbx_mesh::mesh::Face2(v0,v1,v2)|
|
||||
vec![vertex_id_map[&v0],vertex_id_map[&v1],vertex_id_map[&v2]]
|
||||
).collect()))
|
||||
))
|
||||
}
|
||||
|
@ -4,12 +4,11 @@ use crate::primitives;
|
||||
use strafesnet_common::aabb::Aabb;
|
||||
use strafesnet_common::map;
|
||||
use strafesnet_common::model;
|
||||
use strafesnet_common::gameplay_modes;
|
||||
use strafesnet_common::gameplay_modes::{NormalizedModes,Mode,ModeId,ModeUpdate,ModesBuilder,Stage,StageElement,StageElementBehaviour,StageId,Zone};
|
||||
use strafesnet_common::gameplay_style;
|
||||
use strafesnet_common::gameplay_attributes as attr;
|
||||
use strafesnet_common::integer::{self,vec3,Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3};
|
||||
use strafesnet_common::model::RenderConfigId;
|
||||
use strafesnet_common::updatable::Updatable;
|
||||
use strafesnet_deferred_loader::deferred_loader::{RenderConfigDeferredLoader,MeshDeferredLoader};
|
||||
use strafesnet_deferred_loader::mesh::Meshes;
|
||||
use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
|
||||
@ -52,93 +51,7 @@ fn planar64_affine3_from_roblox(cf:&rbx_dom_weak::types::CFrame,size:&rbx_dom_we
|
||||
vec3::try_from_f32_array([cf.position.x,cf.position.y,cf.position.z]).unwrap()
|
||||
)
|
||||
}
|
||||
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_key(|&(mode_id,_)|mode_id);
|
||||
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::new(final_stage_id as u32))
|
||||
}).collect()
|
||||
}),
|
||||
mode,
|
||||
},
|
||||
(
|
||||
builder_mode_id,
|
||||
gameplay_modes::ModeId::new(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,mut 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){
|
||||
//map stage id on stage elements
|
||||
mode_update.map_stage_element_ids(|stage_id|
|
||||
//walk down one stage id at a time until a stage is found
|
||||
//TODO use better logic like BTreeMap::upper_bound instead of walking
|
||||
// final_stage_id_from_builder_stage_id.upper_bound(Bound::Included(&stage_id))
|
||||
// .value().copied().unwrap_or(gameplay_modes::StageId::FIRST)
|
||||
(0..=stage_id.get()).rev().find_map(|builder_stage_id|
|
||||
//map the stage element to that stage
|
||||
mode.final_stage_id_from_builder_stage_id.get(&gameplay_modes::StageId::new(builder_stage_id)).copied()
|
||||
).unwrap_or(gameplay_modes::StageId::FIRST)
|
||||
);
|
||||
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(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:model::ModelId,modes_builder:&mut ModesBuilder,wormhole_in_model_to_id:&mut HashMap<model::ModelId,u32>,wormhole_id_to_out_model:&mut HashMap<u32,model::ModelId>)->attr::CollisionAttributes{
|
||||
let mut general=attr::GeneralAttributes::default();
|
||||
let mut intersecting=attr::IntersectingAttributes::default();
|
||||
@ -167,8 +80,8 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
force_can_collide=false;
|
||||
force_intersecting=true;
|
||||
modes_builder.insert_mode(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::Mode::empty(
|
||||
ModeId::MAIN,
|
||||
Mode::empty(
|
||||
gameplay_style::StyleModifiers::roblox_bhop(),
|
||||
model_id
|
||||
)
|
||||
@ -178,10 +91,10 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
force_can_collide=false;
|
||||
force_intersecting=true;
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::zone(
|
||||
ModeId::MAIN,
|
||||
ModeUpdate::zone(
|
||||
model_id,
|
||||
gameplay_modes::Zone::Finish,
|
||||
Zone::Finish,
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -189,19 +102,19 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
force_can_collide=false;
|
||||
force_intersecting=true;
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::zone(
|
||||
ModeId::MAIN,
|
||||
ModeUpdate::zone(
|
||||
model_id,
|
||||
gameplay_modes::Zone::Anticheat,
|
||||
Zone::Anticheat,
|
||||
),
|
||||
);
|
||||
},
|
||||
"Platform"=>{
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::element(
|
||||
ModeId::MAIN,
|
||||
ModeUpdate::element(
|
||||
model_id,
|
||||
gameplay_modes::StageElement::new(gameplay_modes::StageId::FIRST,false,gameplay_modes::StageElementBehaviour::Platform,None),//roblox does not know which stage the platform belongs to
|
||||
StageElement::new(StageId::FIRST,false,StageElementBehaviour::Platform,None),//roblox does not know which stage the platform belongs to
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -213,8 +126,8 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
force_can_collide=false;
|
||||
force_intersecting=true;
|
||||
modes_builder.insert_mode(
|
||||
gameplay_modes::ModeId::new(captures[2].parse::<u32>().unwrap()),
|
||||
gameplay_modes::Mode::empty(
|
||||
ModeId::new(captures[2].parse::<u32>().unwrap()),
|
||||
Mode::empty(
|
||||
gameplay_style::StyleModifiers::roblox_bhop(),
|
||||
model_id
|
||||
)
|
||||
@ -231,8 +144,8 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
}else if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Spawn|SpawnAt|Trigger|Teleport|Platform)(\d+)$")
|
||||
.captures(other){
|
||||
force_intersecting=true;
|
||||
let stage_id=gameplay_modes::StageId::new(captures[3].parse::<u32>().unwrap());
|
||||
let stage_element=gameplay_modes::StageElement::new(
|
||||
let stage_id=StageId::new(captures[3].parse::<u32>().unwrap());
|
||||
let stage_element=StageElement::new(
|
||||
//stage_id:
|
||||
stage_id,
|
||||
//force:
|
||||
@ -244,26 +157,26 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
match &captures[2]{
|
||||
"Spawn"=>{
|
||||
modes_builder.insert_stage(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
ModeId::MAIN,
|
||||
stage_id,
|
||||
gameplay_modes::Stage::empty(model_id),
|
||||
Stage::empty(model_id),
|
||||
);
|
||||
//TODO: let denormalize handle this
|
||||
gameplay_modes::StageElementBehaviour::SpawnAt
|
||||
StageElementBehaviour::SpawnAt
|
||||
},
|
||||
"SpawnAt"=>gameplay_modes::StageElementBehaviour::SpawnAt,
|
||||
"SpawnAt"=>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,
|
||||
"Trigger"=>{force_can_collide=false;StageElementBehaviour::Trigger},
|
||||
"Teleport"=>{force_can_collide=false;StageElementBehaviour::Teleport},
|
||||
"Platform"=>StageElementBehaviour::Platform,
|
||||
_=>panic!("regex1[2] messed up bad"),
|
||||
},
|
||||
None
|
||||
);
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::element(
|
||||
ModeId::MAIN,
|
||||
ModeUpdate::element(
|
||||
model_id,
|
||||
stage_element,
|
||||
),
|
||||
@ -272,14 +185,14 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
.captures(other){
|
||||
match &captures[1]{
|
||||
"Jump"=>modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::MAIN,
|
||||
gameplay_modes::ModeUpdate::element(
|
||||
ModeId::MAIN,
|
||||
ModeUpdate::element(
|
||||
model_id,
|
||||
//jump_limit:
|
||||
gameplay_modes::StageElement::new(
|
||||
gameplay_modes::StageId::FIRST,
|
||||
StageElement::new(
|
||||
StageId::FIRST,
|
||||
false,
|
||||
gameplay_modes::StageElementBehaviour::Check,
|
||||
StageElementBehaviour::Check,
|
||||
Some(captures[2].parse::<u8>().unwrap())
|
||||
)
|
||||
),
|
||||
@ -296,13 +209,13 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
force_can_collide=false;
|
||||
force_intersecting=true;
|
||||
modes_builder.push_mode_update(
|
||||
gameplay_modes::ModeId::new(captures[2].parse::<u32>().unwrap()),
|
||||
gameplay_modes::ModeUpdate::zone(
|
||||
ModeId::new(captures[2].parse::<u32>().unwrap()),
|
||||
ModeUpdate::zone(
|
||||
model_id,
|
||||
//zone:
|
||||
match &captures[1]{
|
||||
"Finish"=>gameplay_modes::Zone::Finish,
|
||||
"Anticheat"=>gameplay_modes::Zone::Anticheat,
|
||||
"Finish"=>Zone::Finish,
|
||||
"Anticheat"=>Zone::Anticheat,
|
||||
_=>panic!("regex3[1] messed up bad"),
|
||||
},
|
||||
),
|
||||
@ -312,9 +225,9 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
// .captures(other){
|
||||
// match &captures[1]{
|
||||
// "OrderedCheckpoint"=>modes_builder.push_stage_update(
|
||||
// gameplay_modes::ModeId::MAIN,
|
||||
// gameplay_modes::StageId::new(0),
|
||||
// gameplay_modes::StageUpdate::ordered_checkpoint(captures[2].parse::<u32>().unwrap()),
|
||||
// ModeId::MAIN,
|
||||
// StageId::new(0),
|
||||
// StageUpdate::ordered_checkpoint(captures[2].parse::<u32>().unwrap()),
|
||||
// ),
|
||||
// _=>panic!("regex3[1] messed up bad"),
|
||||
// }
|
||||
@ -1009,7 +922,7 @@ impl PartialMap1<'_>{
|
||||
PartialMap2{
|
||||
meshes:self.primitive_meshes,
|
||||
models,
|
||||
modes:modes_builder.build(),
|
||||
modes:modes_builder.build_normalized(),
|
||||
attributes:unique_attributes,
|
||||
}
|
||||
}
|
||||
@ -1018,7 +931,7 @@ impl PartialMap1<'_>{
|
||||
pub struct PartialMap2{
|
||||
meshes:Vec<model::Mesh>,
|
||||
models:Vec<model::Model>,
|
||||
modes:gameplay_modes::Modes,
|
||||
modes:NormalizedModes,
|
||||
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
|
||||
}
|
||||
impl PartialMap2{
|
||||
|
@ -138,7 +138,7 @@ struct MapHeader{
|
||||
//#[br(count=num_resources_external)]
|
||||
//external_resources:Vec<ResourceExternalHeader>,
|
||||
#[br(count=num_modes)]
|
||||
modes:Vec<newtypes::gameplay_modes::Mode>,
|
||||
modes:Vec<newtypes::gameplay_modes::NormalizedMode>,
|
||||
#[br(count=num_attributes)]
|
||||
attributes:Vec<newtypes::gameplay_attributes::CollisionAttributes>,
|
||||
#[br(count=num_render_configs)]
|
||||
@ -181,7 +181,7 @@ fn read_texture<R:BinReaderExt>(file:&mut crate::file::File<R>,block_id:BlockId)
|
||||
pub struct StreamableMap<R:BinReaderExt>{
|
||||
file:crate::file::File<R>,
|
||||
//this includes every platform... move the unconstrained datas to their appropriate data block?
|
||||
modes:gameplay_modes::Modes,
|
||||
modes:gameplay_modes::NormalizedModes,
|
||||
//this is every possible attribute... need some sort of streaming system
|
||||
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
|
||||
//this is every possible render configuration... shaders and such... need streaming
|
||||
@ -223,7 +223,7 @@ impl<R:BinReaderExt> StreamableMap<R>{
|
||||
}
|
||||
Ok(Self{
|
||||
file,
|
||||
modes:strafesnet_common::gameplay_modes::Modes::new(modes),
|
||||
modes:strafesnet_common::gameplay_modes::NormalizedModes::new(modes),
|
||||
attributes,
|
||||
render_configs,
|
||||
bvh:strafesnet_common::bvh::generate_bvh(bvh),
|
||||
@ -430,13 +430,13 @@ pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::Comple
|
||||
num_spacial_blocks:spacial_blocks.len() as u32,
|
||||
num_resource_blocks:resource_blocks.len() as u32,
|
||||
//num_resources_external:0,
|
||||
num_modes:map.modes.modes.len() as u32,
|
||||
num_modes:map.modes.len() as u32,
|
||||
num_attributes:map.attributes.len() as u32,
|
||||
num_render_configs:map.render_configs.len() as u32,
|
||||
spacial_blocks,
|
||||
resource_blocks,
|
||||
//external_resources:Vec::new(),
|
||||
modes:map.modes.modes.into_iter().map(Into::into).collect(),
|
||||
modes:map.modes.into_iter().map(Into::into).collect(),
|
||||
attributes:map.attributes.into_iter().map(Into::into).collect(),
|
||||
render_configs:map.render_configs.into_iter().map(Into::into).collect(),
|
||||
};
|
||||
|
@ -157,7 +157,7 @@ pub struct ModeHeader{
|
||||
}
|
||||
#[binrw::binrw]
|
||||
#[brw(little)]
|
||||
pub struct Mode{
|
||||
pub struct NormalizedMode{
|
||||
pub header:ModeHeader,
|
||||
pub style:super::gameplay_style::StyleModifiers,
|
||||
pub start:u32,
|
||||
@ -179,10 +179,10 @@ impl std::fmt::Display for ModeError{
|
||||
}
|
||||
}
|
||||
impl std::error::Error for ModeError{}
|
||||
impl TryInto<strafesnet_common::gameplay_modes::Mode> for Mode{
|
||||
impl TryInto<strafesnet_common::gameplay_modes::NormalizedMode> for NormalizedMode{
|
||||
type Error=ModeError;
|
||||
fn try_into(self)->Result<strafesnet_common::gameplay_modes::Mode,Self::Error>{
|
||||
Ok(strafesnet_common::gameplay_modes::Mode::new(
|
||||
fn try_into(self)->Result<strafesnet_common::gameplay_modes::NormalizedMode,Self::Error>{
|
||||
Ok(strafesnet_common::gameplay_modes::NormalizedMode::new(strafesnet_common::gameplay_modes::Mode::new(
|
||||
self.style.try_into().map_err(ModeError::StyleModifier)?,
|
||||
strafesnet_common::model::ModelId::new(self.start),
|
||||
self.zones.into_iter().map(|(model_id,zone)|
|
||||
@ -192,12 +192,12 @@ impl TryInto<strafesnet_common::gameplay_modes::Mode> for Mode{
|
||||
self.elements.into_iter().map(|(model_id,stage_element)|
|
||||
Ok((strafesnet_common::model::ModelId::new(model_id),stage_element.try_into()?))
|
||||
).collect::<Result<_,_>>().map_err(ModeError::StageElement)?,
|
||||
))
|
||||
)))
|
||||
}
|
||||
}
|
||||
impl From<strafesnet_common::gameplay_modes::Mode> for Mode{
|
||||
fn from(value:strafesnet_common::gameplay_modes::Mode)->Self{
|
||||
let (style,start,zones,stages,elements)=value.into_inner();
|
||||
impl From<strafesnet_common::gameplay_modes::NormalizedMode> for NormalizedMode{
|
||||
fn from(value:strafesnet_common::gameplay_modes::NormalizedMode)->Self{
|
||||
let (style,start,zones,stages,elements)=value.into_inner().into_inner();
|
||||
Self{
|
||||
header:ModeHeader{
|
||||
zones:zones.len() as u32,
|
||||
|
@ -25,11 +25,11 @@ strafesnet_rbx_loader = { version = "0.6.0", path = "../lib/rbx_loader", registr
|
||||
strafesnet_snf = { version = "0.3.0", path = "../lib/snf", registry = "strafesnet" }
|
||||
thiserror = "2.0.11"
|
||||
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "fs"] }
|
||||
vbsp = { version = "0.7.0-codegen5", registry = "strafesnet", default-features = false }
|
||||
vbsp-entities = { version = "0.1.0", registry = "strafesnet", default-features = false, features = ["css"]}
|
||||
vbsp = "0.8.0"
|
||||
vbsp-entities-css = "0.6.0"
|
||||
vmdl = "0.2.0"
|
||||
vmt-parser = "0.2.0"
|
||||
vpk = "0.2.0"
|
||||
vpk = "0.3.0"
|
||||
vtf = "0.3.0"
|
||||
|
||||
#[profile.release]
|
||||
|
@ -6,7 +6,7 @@ use futures::StreamExt;
|
||||
use strafesnet_bsp_loader::loader::BspFinder;
|
||||
use strafesnet_deferred_loader::loader::Loader;
|
||||
use strafesnet_deferred_loader::deferred_loader::{LoadFailureMode,MeshDeferredLoader,RenderConfigDeferredLoader};
|
||||
use vbsp_entities::css::Entity;
|
||||
use vbsp_entities_css::Entity;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands{
|
||||
|
Reference in New Issue
Block a user