update rbx-dom

This commit is contained in:
Quaternions 2025-04-14 21:12:45 -07:00
parent cb31c847d5
commit 3bdf0a27bb
Signed by: Quaternions
GPG Key ID: D0DF5964F79AC131
9 changed files with 217 additions and 171 deletions
Cargo.lock
lib
rbx_loader
roblox_emulator
map-tool

82
Cargo.lock generated

@ -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"

@ -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" }

@ -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();
}
}

@ -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);

@ -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"

@ -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"));

@ -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)

@ -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" }

@ -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?;