21 Commits

Author SHA1 Message Date
05e609521a implement texture_loader 2024-02-13 02:09:35 -08:00
b5ab8f377d update common 2024-02-13 02:09:20 -08:00
5c9a79390a todo 2024-02-12 22:07:44 -08:00
5baff7a6e7 fix wormholes 2024-02-12 22:07:44 -08:00
c3fef4dc35 update common 2024-02-12 22:07:44 -08:00
ea48c40938 fix touching spawns 2024-02-12 21:37:54 -08:00
66269f326d fix stage_elements 2024-02-12 21:33:55 -08:00
77fb784c7e fix attributes & modes 2024-02-12 20:43:09 -08:00
cb80773db4 todo 2024-02-12 20:42:54 -08:00
da9fa7c51c sneak into stack 2024-02-12 18:54:54 -08:00
7a6b494358 update common 2024-02-09 00:18:09 -08:00
864f9dc551 rbx_loader::read 2024-02-08 20:58:00 -08:00
5fc2dda3a1 update common 2024-02-08 20:32:51 -08:00
777ee3439c update common 2024-02-07 22:42:07 -08:00
69f08061ed update common 2024-02-06 22:54:13 -08:00
1ad6104c14 collapse Models struct into Map 2024-02-04 22:42:07 -08:00
20cc3ef96f make it work 2024-02-04 20:57:25 -08:00
ffb20c6dc9 update common 2024-02-04 20:57:01 -08:00
451808f9af primitives wip 2024-02-01 22:17:44 -08:00
2cc7d76a48 wip 2024-02-01 20:03:22 -08:00
56859d4e0c wip make it work 2024-02-01 04:05:30 -08:00
5 changed files with 71 additions and 96 deletions

22
Cargo.lock generated
View File

@@ -272,7 +272,8 @@ dependencies = [
[[package]]
name = "rbx_binary"
version = "0.7.4"
source = "git+https://github.com/krakow10/rbx-dom?rev=841643178680c9f3143422778f9c52f949b222b9#841643178680c9f3143422778f9c52f949b222b9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6314dd6bf5c21d0598cdb53cf5d241aa643ba41da8b8abf7402b4a35096f03f6"
dependencies = [
"log",
"lz4",
@@ -286,7 +287,8 @@ dependencies = [
[[package]]
name = "rbx_dom_weak"
version = "2.7.0"
source = "git+https://github.com/krakow10/rbx-dom?rev=841643178680c9f3143422778f9c52f949b222b9#841643178680c9f3143422778f9c52f949b222b9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b67b56bac99849c2e3c57547b036927f71c57cf7f4d900d04e3e4ee774ec316"
dependencies = [
"rbx_types",
"serde",
@@ -295,7 +297,8 @@ dependencies = [
[[package]]
name = "rbx_reflection"
version = "4.5.0"
source = "git+https://github.com/krakow10/rbx-dom?rev=841643178680c9f3143422778f9c52f949b222b9#841643178680c9f3143422778f9c52f949b222b9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d41509c991b53a7276a746a795eae2b9204f398164920f61976995b47fe1722"
dependencies = [
"rbx_types",
"serde",
@@ -305,7 +308,8 @@ dependencies = [
[[package]]
name = "rbx_reflection_database"
version = "0.2.10+roblox-607"
source = "git+https://github.com/krakow10/rbx-dom?rev=841643178680c9f3143422778f9c52f949b222b9#841643178680c9f3143422778f9c52f949b222b9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12e20c06fa41f7aadc79005c8354f592b2c2f4d0c61e1080ed5718dafc30aea0"
dependencies = [
"lazy_static",
"rbx_reflection",
@@ -316,7 +320,8 @@ dependencies = [
[[package]]
name = "rbx_types"
version = "1.8.0"
source = "git+https://github.com/krakow10/rbx-dom?rev=841643178680c9f3143422778f9c52f949b222b9#841643178680c9f3143422778f9c52f949b222b9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ca23bfd469d067d81ef14f65fe09aeddc25abcf576a889d1a7664fe021cf18c"
dependencies = [
"base64",
"bitflags",
@@ -330,7 +335,8 @@ dependencies = [
[[package]]
name = "rbx_xml"
version = "0.13.3"
source = "git+https://github.com/krakow10/rbx-dom?rev=841643178680c9f3143422778f9c52f949b222b9#841643178680c9f3143422778f9c52f949b222b9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8c03f95500961c32340791d1fabd4587f6873bdbff077ecca6ae32db7960dea"
dependencies = [
"base64",
"log",
@@ -414,7 +420,7 @@ dependencies = [
[[package]]
name = "strafesnet_common"
version = "0.1.0"
source = "git+https://git.itzana.me/StrafesNET/common?rev=093a54c527134ef7020a22a0f5778df8cba60228#093a54c527134ef7020a22a0f5778df8cba60228"
source = "git+https://git.itzana.me/StrafesNET/common?rev=fccb13bc6080ea6db94ef9175affd4aef1d9249d#fccb13bc6080ea6db94ef9175affd4aef1d9249d"
dependencies = [
"glam",
"id",
@@ -422,7 +428,7 @@ dependencies = [
[[package]]
name = "strafesnet_rbx_loader"
version = "0.2.0"
version = "0.1.0"
dependencies = [
"glam",
"lazy-regex",

View File

@@ -1,6 +1,6 @@
[package]
name = "strafesnet_rbx_loader"
version = "0.2.0"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -8,8 +8,8 @@ edition = "2021"
[dependencies]
glam = "0.25.0"
lazy-regex = "3.1.0"
rbx_binary = { git = "https://github.com/krakow10/rbx-dom", rev = "841643178680c9f3143422778f9c52f949b222b9" }
rbx_dom_weak = { git = "https://github.com/krakow10/rbx-dom", rev = "841643178680c9f3143422778f9c52f949b222b9" }
rbx_reflection_database = { git = "https://github.com/krakow10/rbx-dom", rev = "841643178680c9f3143422778f9c52f949b222b9" }
rbx_xml = { git = "https://github.com/krakow10/rbx-dom", rev = "841643178680c9f3143422778f9c52f949b222b9" }
strafesnet_common = { git = "https://git.itzana.me/StrafesNET/common", rev = "093a54c527134ef7020a22a0f5778df8cba60228" }
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 = "fccb13bc6080ea6db94ef9175affd4aef1d9249d" }

View File

@@ -3,34 +3,24 @@ use std::io::Read;
mod rbx;
mod primitives;
pub struct Dom(rbx_dom_weak::WeakDom);
#[derive(Debug)]
pub enum ReadError{
pub enum Error{
RbxBinary(rbx_binary::DecodeError),
RbxXml(rbx_xml::DecodeError),
Io(std::io::Error),
UnknownFileFormat,
}
impl std::fmt::Display for ReadError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for ReadError{}
pub fn read<R:Read>(input:R)->Result<Dom,ReadError>{
fn load_dom<R:Read>(input:R)->Result<rbx_dom_weak::WeakDom,Error>{
let mut buf=std::io::BufReader::new(input);
let peek=std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?;
let peek=std::io::BufRead::fill_buf(&mut buf).map_err(Error::Io)?;
match &peek[0..8]{
b"<roblox!"=>rbx_binary::from_reader(buf).map(Dom).map_err(ReadError::RbxBinary),
b"<roblox "=>rbx_xml::from_reader_default(buf).map(Dom).map_err(ReadError::RbxXml),
_=>Err(ReadError::UnknownFileFormat),
b"<roblox!"=>return rbx_binary::from_reader(buf).map_err(Error::RbxBinary),
b"<roblox "=>return rbx_xml::from_reader_default(buf).map_err(Error::RbxXml),
_=>Err(Error::UnknownFileFormat),
}
}
//ConvertError
pub fn convert<F:FnMut(Option<&str>)->strafesnet_common::model::RenderConfigId>(dom:&Dom,acquire_render_config_id:F)->rbx::PartialMap1{
rbx::convert(&dom.0,acquire_render_config_id)
pub fn read<R:Read,F:FnMut(&str)->Option<strafesnet_common::model::TextureId>>(input:R,acquire_id:F)->Result<strafesnet_common::map::CompleteMap,Error>{
Ok(rbx::convert(load_dom(input)?,acquire_id))
}

View File

@@ -207,6 +207,8 @@ impl 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)->Mesh{
let mut generated_pos=Vec::new();
let mut generated_tex=Vec::new();
@@ -215,7 +217,7 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->Mesh{
let mut generated_vertices=Vec::new();
let mut polygon_groups=Vec::new();
let mut graphics_groups=Vec::new();
let mut physics_group=IndexedPhysicsGroup::default();
let mut physics_groups=vec![IndexedPhysicsGroup::default()];
let mut transforms=Vec::new();
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (face_id,face_description) in face_descriptions.pairs(){
@@ -226,9 +228,9 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->Mesh{
//create new transform_index
let transform_index=transforms.len();
transforms.push(face_description.transform);
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex|
face_description.transform.transform_point2(tex)
));
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
generated_tex.push(face_description.transform.transform_point2(tex));
}
transform_index
} as u32;
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){
@@ -271,7 +273,7 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->Mesh{
render:face_description.render,
groups:vec![group_id],
});
physics_group.groups.push(group_id);
physics_groups[0].groups.push(group_id);
}
Mesh{
unique_pos:generated_pos,
@@ -281,7 +283,7 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->Mesh{
unique_vertices:generated_vertices,
polygon_groups,
graphics_groups,
physics_groups:vec![physics_group],
physics_groups,
}
}
//don't think too hard about the copy paste because this is all going into the map tool eventually...
@@ -328,7 +330,7 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
let mut generated_vertices=Vec::new();
let mut polygon_groups=Vec::new();
let mut graphics_groups=Vec::new();
let mut physics_group=IndexedPhysicsGroup::default();
let mut physics_groups=vec![IndexedPhysicsGroup::default()];
let mut transforms=Vec::new();
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (face_id,face_description) in face_descriptions.pairs(){
@@ -339,9 +341,9 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
//create new transform_index
let transform_index=transforms.len();
transforms.push(face_description.transform);
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex|
face_description.transform.transform_point2(tex)
));
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
generated_tex.push(face_description.transform.transform_point2(tex));
}
transform_index
} as u32;
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){
@@ -384,7 +386,7 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
render:face_description.render,
groups:vec![group_id],
});
physics_group.groups.push(group_id);
physics_groups[0].groups.push(group_id);
}
Mesh{
unique_pos:generated_pos,
@@ -394,7 +396,7 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
unique_vertices:generated_vertices,
polygon_groups,
graphics_groups,
physics_groups:vec![physics_group],
physics_groups,
}
}
@@ -439,7 +441,7 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
let mut generated_vertices=Vec::new();
let mut polygon_groups=Vec::new();
let mut graphics_groups=Vec::new();
let mut physics_group=IndexedPhysicsGroup::default();
let mut physics_groups=vec![IndexedPhysicsGroup::default()];
let mut transforms=Vec::new();
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (face_id,face_description) in face_descriptions.pairs(){
@@ -450,9 +452,9 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
//create new transform_index
let transform_index=transforms.len();
transforms.push(face_description.transform);
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex|
face_description.transform.transform_point2(tex)
));
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
generated_tex.push(face_description.transform.transform_point2(tex));
}
transform_index
} as u32;
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){
@@ -495,7 +497,7 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
render:face_description.render,
groups:vec![group_id],
});
physics_group.groups.push(group_id);
physics_groups[0].groups.push(group_id);
}
Mesh{
unique_pos:generated_pos,
@@ -505,6 +507,6 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
unique_vertices:generated_vertices,
polygon_groups,
graphics_groups,
physics_groups:vec![physics_group],
physics_groups,
}
}

View File

@@ -6,6 +6,7 @@ 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::model::RenderConfig;
use strafesnet_common::model::RenderConfigId;
use strafesnet_common::updatable::Updatable;
@@ -125,7 +126,7 @@ impl ModesBuilder{
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){
self.stages.entry(mode_id).or_insert(HashMap::new()).insert(stage_id,stage);//assert!(.is_none(),"Cannot replace existing 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));
@@ -220,7 +221,7 @@ fn get_attributes(object:&rbx_dom_weak::Instance,can_collide:bool,velocity:Plana
//the PhysicsModelId has to exist for it to be teleported to!
force_intersecting=true;
//this object is not special in strafe client, but the roblox mapping needs to be converted to model id
wormhole_id_to_out_model.insert(captures[2].parse::<u32>().unwrap(),model_id);//assert!(.is_none(),"Cannot have multiple WormholeOut with same id");
assert!(wormhole_id_to_out_model.insert(captures[2].parse::<u32>().unwrap(),model_id).is_none(),"Cannot have multiple WormholeOut with same id");
},
_=>(),
}
@@ -404,7 +405,7 @@ struct ModelOwnedAttributes{
color:model::Color4,//transparency is in here
transform:Planar64Affine3,
}
pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::WeakDom,mut acquire_render_config_id:F)->PartialMap1{
pub fn convert<F:FnMut(&str)->Option<model::TextureId>>(dom:rbx_dom_weak::WeakDom,mut acquire_id:F)->map::CompleteMap{
let mut modes_builder=ModesBuilder::default();
let mut models1=Vec::new();
@@ -417,8 +418,10 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
let mut wormhole_in_model_to_id=HashMap::new();
let mut wormhole_id_to_out_model=HashMap::new();
//just going to leave it like this for now instead of reworking the data structures for this whole thing
let textureless_render_group=acquire_render_config_id(None);
//TODO: some sort of thing like RobloxResources that describes where to get each resource
//this would be another dependency built for downloading resources to keep this one clean
let mut unique_render_groups=vec![RenderConfig::default()];
let textureless_render_group=RenderConfigId::new(0);
let mut object_refs=Vec::new();
let mut temp_objects=Vec::new();
@@ -500,7 +503,14 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
decal.properties.get("Color3"),
decal.properties.get("Transparency"),
) {
let render_id=acquire_render_config_id(Some(content.as_ref()));
if let Some(texture_id)=acquire_id(content.as_ref()){
//this is equivalent to a get_or_create pattern because there is a singular no-texture RenderId
//so RenderId==TextureId+1
//not the most failsafe code but this is just for the map tool lmao
if unique_render_groups.len()==texture_id.get() as usize+1{
unique_render_groups.push(RenderConfig::texture(texture_id));
};
let render_id=RenderConfigId::new(texture_id.get()+1);
let normal_id=normalid.to_u32();
if normal_id<6{
let (roblox_texture_color,roblox_texture_transform)=if decal.class=="Texture"{
@@ -524,7 +534,7 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
3=>(size.z,size.y),//left
4=>(size.x,size.z),//bottom
5=>(size.x,size.y),//front
_=>unreachable!(),
_=>panic!("unreachable"),
};
(
glam::vec4(decal_color3.r,decal_color3.g,decal_color3.b,1.0-*decal_transparency),
@@ -547,6 +557,7 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
}else{
println!("NormalId={} unsupported for shape={:?}",normal_id,shape);
}
}
}
}
}
@@ -601,7 +612,7 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
3=>primitives::CubeFace::Left,
4=>primitives::CubeFace::Bottom,
5=>primitives::CubeFace::Front,
_=>unreachable!(),
_=>panic!("unreachable"),
},
match roblox_face_description{
Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(),
@@ -620,7 +631,7 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
2=>primitives::WedgeFace::Back,
3=>primitives::WedgeFace::Left,
4=>primitives::WedgeFace::Bottom,
_=>unreachable!(),
_=>panic!("unreachable"),
},
match roblox_face_description{
Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(),
@@ -639,7 +650,7 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
2=>primitives::CornerWedgeFace::TopLeft,
3=>primitives::CornerWedgeFace::Bottom,
4=>primitives::CornerWedgeFace::Front,
_=>unreachable!(),
_=>panic!("unreachable"),
},
match roblox_face_description{
Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(),
@@ -700,45 +711,11 @@ pub fn convert<F:FnMut(Option<&str>)->model::RenderConfigId>(dom:&rbx_dom_weak::
attributes:attributes_id,
}
}).collect();
PartialMap1{
map::CompleteMap{
render_configs:unique_render_groups,//asset_id_from_texture_id.iter().map(|t|t.to_string()).collect(),
meshes,
models,
modes:modes_builder.build(),
attributes:unique_attributes,
}
}
pub struct PartialMap1{
meshes:Vec<model::Mesh>,
models:Vec<model::Model>,
modes:gameplay_modes::Modes,
attributes:Vec<strafesnet_common::gameplay_attributes::CollisionAttributes>,
}
impl PartialMap1{
pub fn add_render_configs_and_textures(
self,
render_configs:impl IntoIterator<Item=(model::RenderConfigId,model::RenderConfig)>,
textures:impl IntoIterator<Item=(model::TextureId,Vec<u8>)>,
)->map::CompleteMap{
let (textures,texture_id_map):(Vec<Vec<u8>>,HashMap<model::TextureId,model::TextureId>)
=textures.into_iter().enumerate().map(|(new_texture_id,(old_texture_id,texture))|{
(texture,(old_texture_id,model::TextureId::new(new_texture_id as u32)))
}).unzip();
let render_configs=render_configs.into_iter().map(|(render_config_id,mut render_config)|{
//this may generate duplicate no-texture render configs but idc
render_config.texture=render_config.texture.and_then(|texture_id|
texture_id_map.get(&texture_id).copied()
);
render_config
}).collect();
map::CompleteMap{
modes:self.modes,
attributes:self.attributes,
meshes:self.meshes,
models:self.models,
//the roblox legacy texture thing always works
textures,
render_configs,
}
}
}