diff --git a/Cargo.lock b/Cargo.lock index 374d63a..1f823cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3098,10 +3098,11 @@ dependencies = [ [[package]] name = "rbx_binary" -version = "0.7.4" -source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" -checksum = "18b401155b93f7151217bf51e36bdfa7bddcaf5f0d26b563c9ac3b08a3701c27" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9573fee5e073d7b303f475c285197fdc8179468de66ca60ee115a58fbac99296" dependencies = [ + "ahash", "log", "lz4", "profiling", @@ -3109,16 +3110,19 @@ dependencies = [ "rbx_reflection", "rbx_reflection_database", "thiserror 1.0.69", + "zstd", ] [[package]] name = "rbx_dom_weak" -version = "2.9.0" -source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" -checksum = "2a6b916687c98aaea36f9c03e80906bfafab057bebee248628c8c04def807f43" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04425cf6e9376e5486f4fb35906c120d1b1b45618a490318cf563fab1fa230a9" dependencies = [ + "ahash", "rbx_types", "serde", + "ustr", ] [[package]] @@ -3133,9 +3137,9 @@ dependencies = [ [[package]] name = "rbx_reflection" -version = "4.7.0" -source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" -checksum = "c1b43fe592a4ce6fe54eb215fb82735efbb516d2cc045a94e3dc0234ff293620" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6d0d62baa613556b058a5f94a53b01cf0ccde0ea327ce03056e335b982e77e" dependencies = [ "rbx_types", "serde", @@ -3144,9 +3148,9 @@ dependencies = [ [[package]] name = "rbx_reflection_database" -version = "0.2.12+roblox-638" -source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" -checksum = "2e772bb9e1bc0ebe65d338f876d1bb1ea22e15a8f9a82e8245028010c2fea3c9" +version = "1.0.1+roblox-666" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea11f26cfddc57a136781baed2e68eda5a3aa0735152d1562d65b1909c8d65d" dependencies = [ "lazy_static", "rbx_reflection", @@ -3156,9 +3160,9 @@ dependencies = [ [[package]] name = "rbx_types" -version = "1.10.0" -source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" -checksum = "d7a390c44034fa448c53bd0983dfc2d70d8d6b2f65be4f164d4bec8b6a2a2d09" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4fdde46493def107e5f923d82e813dec9b3eef52c2f75fbad3a716023eda2" dependencies = [ "base64 0.13.1", "bitflags 1.3.2", @@ -3171,10 +3175,11 @@ dependencies = [ [[package]] name = "rbx_xml" -version = "0.13.3" -source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" -checksum = "d6d1a15f58a1e4b4f578abe6eb5e1461cb16eea82fb4a147d5995c9b79f08d1f" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb623833c31cc43bbdaeb32f5e91db8ecd63fc46e438d0d268baf9e61539cf1c" dependencies = [ + "ahash", "base64 0.13.1", "log", "rbx_dom_weak", @@ -4309,6 +4314,19 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "ustr" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18b19e258aa08450f93369cf56dd78063586adf19e92a75b338a800f799a0208" +dependencies = [ + "ahash", + "byteorder 1.5.0", + "lazy_static", + "parking_lot", + "serde", +] + [[package]] name = "utf16_iter" version = "1.0.5" @@ -5560,6 +5578,34 @@ dependencies = [ "lzma", ] +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "zune-core" version = "0.4.12" diff --git a/lib/rbx_loader/Cargo.toml b/lib/rbx_loader/Cargo.toml index 2c61dac..9356193 100644 --- a/lib/rbx_loader/Cargo.toml +++ b/lib/rbx_loader/Cargo.toml @@ -13,11 +13,11 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"] bytemuck = "1.14.3" glam = "0.30.0" lazy-regex = "3.1.0" -rbx_binary = { version = "0.7.4", registry = "strafesnet" } -rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } +rbx_binary = "1.0.0" +rbx_dom_weak = "3.0.0" rbx_mesh = "0.3.1" -rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } -rbx_xml = { version = "0.13.3", registry = "strafesnet" } +rbx_reflection_database = "1.0.0" +rbx_xml = "1.0.0" rbxassetid = { version = "0.1.0", path = "../rbxassetid", registry = "strafesnet" } roblox_emulator = { version = "0.4.7", path = "../roblox_emulator", registry = "strafesnet" } strafesnet_common = { version = "0.6.0", path = "../common", registry = "strafesnet" } diff --git a/lib/rbx_loader/src/loader.rs b/lib/rbx_loader/src/loader.rs index db86258..9593652 100644 --- a/lib/rbx_loader/src/loader.rs +++ b/lib/rbx_loader/src/loader.rs @@ -1,4 +1,5 @@ use std::io::Read; +use rbx_dom_weak::ustr; use rbxassetid::{RobloxAssetId,RobloxAssetIdParseErr}; use strafesnet_common::model::Mesh; use strafesnet_deferred_loader::{loader::Loader,texture::Texture}; @@ -171,12 +172,12 @@ impl Loader for MeshLoader{ return Err(MeshError::MissingInstance); }; if physics_data.is_empty(){ - if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get("PhysicsData"){ + if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get(&ustr("PhysicsData")){ physics_data=data.as_ref(); } } if mesh_data.is_empty(){ - if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get("MeshData"){ + if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get(&ustr("MeshData")){ mesh_data=data.as_ref(); } } diff --git a/lib/rbx_loader/src/rbx.rs b/lib/rbx_loader/src/rbx.rs index f420e5b..d2d8d58 100644 --- a/lib/rbx_loader/src/rbx.rs +++ b/lib/rbx_loader/src/rbx.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use crate::loader::MeshIndex; use crate::primitives::{self,CubeFace,CubeFaceDescription,WedgeFaceDescription,CornerWedgeFaceDescription,FaceDescription,Primitives}; +use rbx_dom_weak::ustr; use strafesnet_common::aabb::Aabb; use strafesnet_common::map; use strafesnet_common::model; @@ -389,6 +390,11 @@ enum RobloxBasePartDescription{ Wedge(RobloxWedgeDescription), CornerWedge(RobloxCornerWedgeDescription), } + +// TODO: initialize all ustrs in a top level struct thrown around as a reference +// struct UstrKludge{ +// } + fn get_texture_description<'a>( temp_objects:&mut Vec<rbx_dom_weak::types::Ref>, render_config_deferred_loader:&mut RenderConfigDeferredLoader<&'a str>, @@ -401,68 +407,73 @@ fn get_texture_description<'a>( temp_objects.clear(); recursive_collect_superclass(temp_objects,&dom,object,"Decal"); for &mut decal_ref in temp_objects{ - if let Some(decal)=dom.get_by_ref(decal_ref){ - if let ( + let Some(decal)=dom.get_by_ref(decal_ref) else{ + continue; + }; + let ( Some(rbx_dom_weak::types::Variant::Content(content)), Some(rbx_dom_weak::types::Variant::Enum(normalid)), Some(rbx_dom_weak::types::Variant::Color3(decal_color3)), Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)), - ) = ( - decal.properties.get("Texture"), - decal.properties.get("Face"), - decal.properties.get("Color3"), - decal.properties.get("Transparency"), - ) { - let render_id=render_config_deferred_loader.acquire_render_config_id(Some(content.as_ref())); - if let Ok(cube_face)=normalid.to_u32().try_into(){ - let (roblox_texture_color,roblox_texture_transform)=if decal.class=="Texture"{ - //generate tranform - if let ( - Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_u)), - Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_v)), - Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_u)), - Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_v)), - ) = ( - decal.properties.get("OffsetStudsU"), - decal.properties.get("OffsetStudsV"), - decal.properties.get("StudsPerTileU"), - decal.properties.get("StudsPerTileV"), - ) - { - let (size_u,size_v)=match cube_face{ - CubeFace::Right=>(size.z,size.y),//right - CubeFace::Top=>(size.x,size.z),//top - CubeFace::Back=>(size.x,size.y),//back - CubeFace::Left=>(size.z,size.y),//left - CubeFace::Bottom=>(size.x,size.z),//bottom - CubeFace::Front=>(size.x,size.y),//front - }; - ( - glam::vec4(decal_color3.r,decal_color3.g,decal_color3.b,1.0-*decal_transparency), - RobloxTextureTransform{ - offset_studs_u, - offset_studs_v, - studs_per_tile_u, - studs_per_tile_v, - size_u, - size_v, - } - ) - }else{ - (glam::Vec4::ONE,RobloxTextureTransform::identity()) - } - }else{ - (glam::Vec4::ONE,RobloxTextureTransform::identity()) + )=( + decal.properties.get(&ustr("Texture")), + decal.properties.get(&ustr("Face")), + decal.properties.get(&ustr("Color3")), + decal.properties.get(&ustr("Transparency")), + )else{ + continue; + }; + let rbx_dom_weak::types::ContentType::Uri(content)=content.value() else{ + continue; + }; + let render_id=render_config_deferred_loader.acquire_render_config_id(Some(content.as_ref())); + if let Ok(cube_face)=normalid.to_u32().try_into(){ + let (roblox_texture_color,roblox_texture_transform)=if decal.class=="Texture"{ + //generate tranform + if let ( + Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_u)), + Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_v)), + Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_u)), + Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_v)), + ) = ( + decal.properties.get(&ustr("OffsetStudsU")), + decal.properties.get(&ustr("OffsetStudsV")), + decal.properties.get(&ustr("StudsPerTileU")), + decal.properties.get(&ustr("StudsPerTileV")), + ) + { + let (size_u,size_v)=match cube_face{ + CubeFace::Right=>(size.z,size.y),//right + CubeFace::Top=>(size.x,size.z),//top + CubeFace::Back=>(size.x,size.y),//back + CubeFace::Left=>(size.z,size.y),//left + CubeFace::Bottom=>(size.x,size.z),//bottom + CubeFace::Front=>(size.x,size.y),//front }; - part_texture_description[cube_face]=Some(RobloxFaceTextureDescription{ - render:render_id, - color:roblox_texture_color, - transform:roblox_texture_transform, - }); + ( + glam::vec4(decal_color3.r,decal_color3.g,decal_color3.b,1.0-*decal_transparency), + RobloxTextureTransform{ + offset_studs_u, + offset_studs_v, + studs_per_tile_u, + studs_per_tile_v, + size_u, + size_v, + } + ) }else{ - println!("NormalId is invalid"); + (glam::Vec4::ONE,RobloxTextureTransform::identity()) } - } + }else{ + (glam::Vec4::ONE,RobloxTextureTransform::identity()) + }; + part_texture_description[cube_face]=Some(RobloxFaceTextureDescription{ + render:render_id, + color:roblox_texture_color, + transform:roblox_texture_transform, + }); + }else{ + println!("NormalId is invalid"); } } part_texture_description @@ -529,12 +540,12 @@ pub fn convert<'a>( Some(rbx_dom_weak::types::Variant::Color3uint8(color3)), Some(rbx_dom_weak::types::Variant::Bool(can_collide)), ) = ( - object.properties.get("CFrame"), - object.properties.get("Size"), - object.properties.get("Velocity"), - object.properties.get("Transparency"), - object.properties.get("Color"), - object.properties.get("CanCollide"), + object.properties.get(&ustr("CFrame")), + object.properties.get(&ustr("Size")), + object.properties.get(&ustr("Velocity")), + object.properties.get(&ustr("Transparency")), + object.properties.get(&ustr("Color")), + object.properties.get(&ustr("CanCollide")), ) { let model_transform=planar64_affine3_from_roblox(cf,size); @@ -553,7 +564,7 @@ pub fn convert<'a>( //TODO: also detect "CylinderMesh" etc here let shape=match object.class.as_str(){ - "Part"=>if let Some(rbx_dom_weak::types::Variant::Enum(shape))=object.properties.get("Shape"){ + "Part"=>if let Some(rbx_dom_weak::types::Variant::Enum(shape))=object.properties.get(&ustr("Shape")){ Shape::Primitive(shape.to_u32().try_into().expect("Funky roblox PartType")) }else{ panic!("Part has no Shape!"); @@ -626,13 +637,23 @@ pub fn convert<'a>( Some(rbx_dom_weak::types::Variant::Content(mesh_asset_id)), Some(rbx_dom_weak::types::Variant::Content(texture_asset_id)), )=( - object.properties.get("MeshId"), - object.properties.get("TextureID"), + object.properties.get(&ustr("MeshId")), + object.properties.get(&ustr("TextureID")), ){ - ( - MeshAvailability::DeferredMesh(render_config_deferred_loader.acquire_render_config_id(Some(texture_asset_id.as_ref()))), - mesh_deferred_loader.acquire_mesh_id(MeshIndex::file_mesh(mesh_asset_id.as_ref())), - ) + if let ( + rbx_dom_weak::types::ContentType::Uri(mesh_asset_id), + rbx_dom_weak::types::ContentType::Uri(texture_asset_id) + )=( + mesh_asset_id.value(), + texture_asset_id.value(), + ){ + ( + MeshAvailability::DeferredMesh(render_config_deferred_loader.acquire_render_config_id(Some(texture_asset_id.as_ref()))), + mesh_deferred_loader.acquire_mesh_id(MeshIndex::file_mesh(mesh_asset_id.as_ref())), + ) + }else{ + panic!("Content is not Uri"); + } }else{ panic!("Mesh has no Mesh or Texture"); }, @@ -640,13 +661,15 @@ pub fn convert<'a>( let mut content=""; let mut mesh_data:&[u8]=&[]; let mut physics_data:&[u8]=&[]; - if let Some(rbx_dom_weak::types::Variant::Content(asset_id))=object.properties.get("AssetId"){ - content=asset_id.as_ref(); + if let Some(rbx_dom_weak::types::Variant::Content(asset_id))=object.properties.get(&ustr("AssetId")){ + if let rbx_dom_weak::types::ContentType::Uri(asset_id)=asset_id.value(){ + content=asset_id.as_ref(); + } } - if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("MeshData"){ + if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get(&ustr("MeshData")){ mesh_data=data.as_ref(); } - if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("PhysicsData"){ + if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get(&ustr("PhysicsData")){ physics_data=data.as_ref(); } let part_texture_description=get_texture_description(&mut temp_objects,render_config_deferred_loader,dom,object,size); diff --git a/lib/roblox_emulator/Cargo.toml b/lib/roblox_emulator/Cargo.toml index a6c8d55..d5b83b4 100644 --- a/lib/roblox_emulator/Cargo.toml +++ b/lib/roblox_emulator/Cargo.toml @@ -15,7 +15,7 @@ run-service=[] glam = "0.30.0" mlua = { version = "0.10.1", features = ["luau"] } phf = { version = "0.11.2", features = ["macros"] } -rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } -rbx_reflection = { version = "4.7.0", registry = "strafesnet" } -rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } -rbx_types = { version = "1.10.0", registry = "strafesnet" } +rbx_dom_weak = "3.0.0" +rbx_reflection = "5.0.0" +rbx_reflection_database = "1.0.0" +rbx_types = "2.0.0" diff --git a/lib/roblox_emulator/src/context.rs b/lib/roblox_emulator/src/context.rs index 92b1424..59ade4a 100644 --- a/lib/roblox_emulator/src/context.rs +++ b/lib/roblox_emulator/src/context.rs @@ -1,4 +1,4 @@ -use rbx_dom_weak::{types::Ref,InstanceBuilder,WeakDom}; +use rbx_dom_weak::{types::Ref,ustr,InstanceBuilder,WeakDom}; pub fn class_is_a(class:&str,superclass:&str)->bool{ class==superclass @@ -70,8 +70,8 @@ impl Context{ { //Lowercase and upper case workspace property! let game=self.dom.root_mut(); - game.properties.insert("workspace".to_owned(),rbx_types::Variant::Ref(workspace)); - game.properties.insert("Workspace".to_owned(),rbx_types::Variant::Ref(workspace)); + game.properties.insert(ustr("workspace"),rbx_types::Variant::Ref(workspace)); + game.properties.insert(ustr("Workspace"),rbx_types::Variant::Ref(workspace)); } self.dom.insert(game,InstanceBuilder::new("Lighting")); diff --git a/lib/roblox_emulator/src/runner/instance/instance.rs b/lib/roblox_emulator/src/runner/instance/instance.rs index e0e524d..dee6044 100644 --- a/lib/roblox_emulator/src/runner/instance/instance.rs +++ b/lib/roblox_emulator/src/runner/instance/instance.rs @@ -2,7 +2,7 @@ use std::collections::{hash_map::Entry,HashMap}; use mlua::{FromLua,FromLuaMulti,IntoLua,IntoLuaMulti}; use rbx_types::Ref; -use rbx_dom_weak::{InstanceBuilder,WeakDom}; +use rbx_dom_weak::{ustr,Ustr,InstanceBuilder,WeakDom}; use crate::runner::vector3::Vector3; @@ -58,7 +58,7 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S pub fn get_name_source(lua:&mlua::Lua,script:Instance)->Result<(String,String),mlua::Error>{ dom_mut(lua,|dom|{ let instance=script.get(dom)?; - let source=match instance.properties.get("Source"){ + let source=match instance.properties.get(&ustr("Source")){ Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(), _=>Err(mlua::Error::external("Missing script.Source"))?, }; @@ -97,25 +97,6 @@ impl Instance{ } type_from_lua_userdata!(Instance); -//TODO: update rbx_reflection and use dom.superclasses_iter -pub struct SuperClassIter<'a> { - database: &'a rbx_reflection::ReflectionDatabase<'a>, - descriptor: Option<&'a rbx_reflection::ClassDescriptor<'a>>, -} -impl<'a> SuperClassIter<'a> { - fn next_descriptor(&self) -> Option<&'a rbx_reflection::ClassDescriptor<'a>> { - let superclass = self.descriptor?.superclass.as_ref()?; - self.database.classes.get(superclass) - } -} -impl<'a> Iterator for SuperClassIter<'a> { - type Item = &'a rbx_reflection::ClassDescriptor<'a>; - fn next(&mut self) -> Option<Self::Item> { - let next_descriptor = self.next_descriptor(); - std::mem::replace(&mut self.descriptor, next_descriptor) - } -} - impl mlua::UserData for Instance{ fn add_fields<F:mlua::UserDataFields<Self>>(fields:&mut F){ fields.add_field_method_get("Parent",|lua,this|{ @@ -148,7 +129,7 @@ impl mlua::UserData for Instance{ fields.add_field_method_get("ClassName",|lua,this|{ dom_mut(lua,|dom|{ let instance=this.get(dom)?; - Ok(instance.class.clone()) + Ok(instance.class.to_owned()) }) }); } @@ -227,26 +208,21 @@ impl mlua::UserData for Instance{ }); methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(Instance,mlua::String)|{ let index_str=&*index.to_str()?; + let index_ustr=ustr(index_str); dom_mut(lua,|dom|{ let instance=this.get(dom)?; //println!("__index t={} i={index:?}",instance.name); let db=rbx_reflection_database::get(); let class=db.classes.get(instance.class.as_str()).ok_or_else(||mlua::Error::runtime("Class missing"))?; //Find existing property - match instance.properties.get(index_str) + match instance.properties.get(&index_ustr) .cloned() //Find default value .or_else(||db.find_default_property(class,index_str).cloned()) //Find virtual property - .or_else(||{ - SuperClassIter{ - database:db, - descriptor:Some(class), - } - .find_map(|class| - find_virtual_property(&instance.properties,class,index_str) - ) - }) + .or_else(||db.superclasses_iter(class).find_map(|class| + find_virtual_property(&instance.properties,class,&index_ustr) + )) { Some(rbx_types::Variant::Int32(val))=>return val.into_lua(lua), Some(rbx_types::Variant::Int64(val))=>return val.into_lua(lua), @@ -260,13 +236,9 @@ impl mlua::UserData for Instance{ } //find a function with a matching name if let Some(function)=class_methods_store_mut(lua,|cf|{ - let mut iter=SuperClassIter{ - database:db, - descriptor:Some(class), - }; - iter.find_map(|class|{ + db.superclasses_iter(class).find_map(|class|{ let mut class_methods=cf.get_or_create_class_methods(&class.name)?; - class_methods.get_or_create_function(lua,index_str) + class_methods.get_or_create_function(lua,&index_str) .transpose() }).transpose() })?{ @@ -294,21 +266,22 @@ impl mlua::UserData for Instance{ let instance=this.get_mut(dom)?; //println!("__newindex t={} i={index:?} v={value:?}",instance.name); let index_str=&*index.to_str()?; + let index_ustr=ustr(index_str); let db=rbx_reflection_database::get(); let class=db.classes.get(instance.class.as_str()).ok_or_else(||mlua::Error::runtime("Class missing"))?; - let mut iter=SuperClassIter{ - database:db, - descriptor:Some(class), - }; - let property=iter.find_map(|cls|cls.properties.get(index_str)).ok_or_else(||mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; + let property=db.superclasses_iter(class).find_map(|cls| + cls.properties.get(index_str) + ).ok_or_else(|| + mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)) + )?; match &property.data_type{ rbx_reflection::DataType::Value(rbx_types::VariantType::Vector3)=>{ let typed_value:Vector3=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected Userdata"))?.borrow()?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); + instance.properties.insert(index_ustr,rbx_types::Variant::Vector3(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Float32)=>{ let typed_value:f32=coerce_float32(&value).ok_or_else(||mlua::Error::runtime("Expected f32"))?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); + instance.properties.insert(index_ustr,rbx_types::Variant::Float32(typed_value)); }, rbx_reflection::DataType::Enum(enum_name)=>{ let typed_value=match &value{ @@ -324,27 +297,27 @@ impl mlua::UserData for Instance{ }, _=>Err(mlua::Error::runtime("Expected Enum")), }?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value)); + instance.properties.insert(index_ustr,rbx_types::Variant::Enum(typed_value)); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Color3)=>{ let typed_value:crate::runner::color3::Color3=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected Color3"))?.borrow()?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); + instance.properties.insert(index_ustr,rbx_types::Variant::Color3(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Bool)=>{ let typed_value=value.as_boolean().ok_or_else(||mlua::Error::runtime("Expected boolean"))?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Bool(typed_value)); + instance.properties.insert(index_ustr,rbx_types::Variant::Bool(typed_value)); }, rbx_reflection::DataType::Value(rbx_types::VariantType::String)=>{ let typed_value=value.as_str().ok_or_else(||mlua::Error::runtime("Expected boolean"))?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned())); + instance.properties.insert(index_ustr,rbx_types::Variant::String(typed_value.to_owned())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::NumberSequence)=>{ let typed_value:crate::runner::number_sequence::NumberSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::NumberSequence(typed_value.into())); + instance.properties.insert(index_ustr,rbx_types::Variant::NumberSequence(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence)=>{ let typed_value:crate::runner::color_sequence::ColorSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected ColorSequence"))?.borrow()?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::ColorSequence(typed_value.into())); + instance.properties.insert(index_ustr,rbx_types::Variant::ColorSequence(typed_value.into())); }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), } @@ -480,16 +453,16 @@ static VIRTUAL_PROPERTY_DATABASE:VPD=phf::phf_map!{ }; fn find_virtual_property( - properties:&HashMap<String,rbx_types::Variant>, + properties:&rbx_dom_weak::UstrMap<rbx_types::Variant>, class:&rbx_reflection::ClassDescriptor, - index:&str + index:&Ustr, )->Option<rbx_types::Variant>{ //Find virtual property let class_virtual_properties=VIRTUAL_PROPERTY_DATABASE.get(&class.name)?; let virtual_property=class_virtual_properties.get(index)?; //Get source property - let variant=properties.get(virtual_property.property)?; + let variant=properties.get(&ustr(virtual_property.property))?; //Transform Source property with provided function (virtual_property.pointer)(variant) diff --git a/map-tool/Cargo.toml b/map-tool/Cargo.toml index 87b0e46..ae8645e 100644 --- a/map-tool/Cargo.toml +++ b/map-tool/Cargo.toml @@ -14,10 +14,10 @@ image = "0.25.2" image_dds = "0.7.1" lazy-regex = "3.1.0" rbx_asset = { version = "0.4.4", registry = "strafesnet" } -rbx_binary = { version = "0.7.4", registry = "strafesnet" } -rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } -rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } -rbx_xml = { version = "0.13.3", registry = "strafesnet" } +rbx_binary = "1.0.0" +rbx_dom_weak = "3.0.0" +rbx_reflection_database = "1.0.0" +rbx_xml = "1.0.0" rbxassetid = { version = "0.1.0", registry = "strafesnet" } strafesnet_bsp_loader = { version = "0.3.0", path = "../lib/bsp_loader", registry = "strafesnet" } strafesnet_deferred_loader = { version = "0.5.0", path = "../lib/deferred_loader", registry = "strafesnet" } diff --git a/map-tool/src/roblox.rs b/map-tool/src/roblox.rs index a62b1eb..5cb4d0c 100644 --- a/map-tool/src/roblox.rs +++ b/map-tool/src/roblox.rs @@ -3,7 +3,7 @@ use std::io::{Cursor,Read,Seek}; use std::collections::HashSet; use clap::{Args,Subcommand}; use anyhow::Result as AResult; -use rbx_dom_weak::Instance; +use rbx_dom_weak::{ustr,Instance}; use strafesnet_deferred_loader::deferred_loader::LoadFailureMode; use rbxassetid::RobloxAssetId; use tokio::io::AsyncReadExt; @@ -89,16 +89,19 @@ SurfaceAppearance.RoughnessMap SurfaceAppearance.TexturePack */ fn accumulate_content_id(content_list:&mut HashSet<RobloxAssetId>,object:&Instance,property:&str){ - if let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get(property){ - let url:&str=content.as_ref(); - if let Ok(asset_id)=url.parse(){ - content_list.insert(asset_id); - }else{ - println!("Content failed to parse into AssetID: {:?}",content); - } - }else{ + let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get(&ustr(property)) else{ println!("property={} does not exist for class={}",property,object.class.as_str()); - } + return; + }; + let rbx_dom_weak::types::ContentType::Uri(content)=content.value()else{ + println!("Content is not Uri"); + return; + }; + let Ok(asset_id)=content.parse()else{ + println!("Content failed to parse into AssetID: {:?}",content); + return; + }; + content_list.insert(asset_id); } async fn read_entire_file(path:impl AsRef<Path>)->Result<Cursor<Vec<u8>>,std::io::Error>{ let mut file=tokio::fs::File::open(path).await?;