Compare commits
2 Commits
rbx-dom_ra
...
hash_str
| Author | SHA1 | Date | |
|---|---|---|---|
|
e832fccacb
|
|||
|
8ab910e18f
|
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -46,6 +46,18 @@ dependencies = [
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash_macro"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e73c78bacfd5857793b9b6813ab94605bb1699de9915f3285472f6633748e773"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
@@ -61,6 +73,12 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.6.0"
|
||||
@@ -1251,12 +1269,27 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash_str"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb4f3e9ad2b19e6290ea4c648770a69ac4687c692a2a6175aaef2a398552da4"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash_macro",
|
||||
"bumpalo",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
@@ -3101,7 +3134,7 @@ name = "rbx_binary"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bumpalo",
|
||||
"hash_str",
|
||||
"log",
|
||||
"lz4",
|
||||
"profiling",
|
||||
@@ -3117,6 +3150,7 @@ name = "rbx_dom_weak"
|
||||
version = "3.0.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"hash_str",
|
||||
"rbx_types",
|
||||
"serde",
|
||||
]
|
||||
@@ -3135,7 +3169,7 @@ dependencies = [
|
||||
name = "rbx_reflection"
|
||||
version = "5.0.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"hash_str",
|
||||
"rbx_types",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
@@ -3170,6 +3204,7 @@ version = "1.0.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"base64 0.13.1",
|
||||
"hash_str",
|
||||
"log",
|
||||
"rbx_dom_weak",
|
||||
"rbx_reflection",
|
||||
|
||||
@@ -38,11 +38,11 @@ impl<'a> AsRef<WeakDom<'a>> for Model<'a>{
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Place<'a>{
|
||||
context:Context<'a>,
|
||||
pub struct Place{
|
||||
context:Context,
|
||||
}
|
||||
impl<'a> Place<'a>{
|
||||
pub fn new(dom:WeakDom<'a>)->Result<Self,roblox_emulator::context::ServicesError>{
|
||||
impl Place{
|
||||
pub fn new(dom:WeakDom)->Result<Self,roblox_emulator::context::ServicesError>{
|
||||
let context=Context::from_place(dom)?;
|
||||
Ok(Self{
|
||||
context,
|
||||
@@ -63,13 +63,13 @@ impl<'a> Place<'a>{
|
||||
to_snf(self,failure_mode)
|
||||
}
|
||||
}
|
||||
impl<'a> AsRef<WeakDom<'a>> for Place<'a>{
|
||||
fn as_ref(&self)->&WeakDom<'a>{
|
||||
impl AsRef<WeakDom> for Place{
|
||||
fn as_ref(&self)->&WeakDom{
|
||||
self.context.as_ref()
|
||||
}
|
||||
}
|
||||
impl<'a> From<Model<'a>> for Place<'a>{
|
||||
fn from(model:Model<'a>)->Self{
|
||||
impl From<Model> for Place{
|
||||
fn from(model:Model)->Self{
|
||||
let context=Context::from_model(model.dom);
|
||||
Self{
|
||||
context,
|
||||
@@ -91,7 +91,7 @@ impl std::fmt::Display for ReadError{
|
||||
}
|
||||
impl std::error::Error for ReadError{}
|
||||
|
||||
pub fn read<R:Read>(input:R)->Result<Model<'static>,ReadError>{
|
||||
pub fn read<R:Read>(input:R)->Result<Model,ReadError>{
|
||||
let mut buf=std::io::BufReader::new(input);
|
||||
let peek=std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?;
|
||||
match peek.get(0..8){
|
||||
@@ -123,7 +123,7 @@ impl From<loader::MeshError> for LoadError{
|
||||
}
|
||||
}
|
||||
|
||||
fn to_snf<'a>(dom:impl AsRef<WeakDom<'a>>,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
|
||||
fn to_snf(dom:impl AsRef<WeakDom>,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
|
||||
let dom=dom.as_ref();
|
||||
|
||||
let mut texture_deferred_loader=RenderConfigDeferredLoader::new();
|
||||
|
||||
@@ -6,6 +6,7 @@ use strafesnet_deferred_loader::{loader::Loader,texture::Texture};
|
||||
use crate::data::RobloxMeshBytes;
|
||||
use crate::rbx::RobloxPartDescription;
|
||||
|
||||
use rbx_dom_weak::hstr;
|
||||
|
||||
fn read_entire_file(path:impl AsRef<std::path::Path>)->Result<Vec<u8>,std::io::Error>{
|
||||
let mut file=std::fs::File::open(path)?;
|
||||
@@ -172,12 +173,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(hstr!("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(hstr!("MeshData")){
|
||||
mesh_data=data.as_ref();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,13 @@ use strafesnet_deferred_loader::deferred_loader::{RenderConfigDeferredLoader,Mes
|
||||
use strafesnet_deferred_loader::mesh::Meshes;
|
||||
use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
|
||||
|
||||
use rbx_dom_weak::{hstr,HashStr};
|
||||
|
||||
fn recursive_collect_superclass(
|
||||
objects:&mut std::vec::Vec<rbx_dom_weak::types::Ref>,
|
||||
dom:&rbx_dom_weak::WeakDom,
|
||||
instance:&rbx_dom_weak::Instance,
|
||||
superclass:&str
|
||||
superclass:&HashStr,
|
||||
){
|
||||
let instance=instance;
|
||||
let db=rbx_reflection_database::get();
|
||||
@@ -405,7 +407,7 @@ fn get_texture_description<'a>(
|
||||
//use the biggest one and cut it down later...
|
||||
let mut part_texture_description=RobloxPartDescription::default();
|
||||
temp_objects.clear();
|
||||
recursive_collect_superclass(temp_objects,&dom,object,"Decal");
|
||||
recursive_collect_superclass(temp_objects,&dom,object,hstr!("Decal"));
|
||||
for &mut decal_ref in temp_objects{
|
||||
let Some(decal)=dom.get_by_ref(decal_ref) else{
|
||||
println!("Decal get_by_ref failed");
|
||||
@@ -417,10 +419,10 @@ fn get_texture_description<'a>(
|
||||
Some(rbx_dom_weak::types::Variant::Color3(decal_color3)),
|
||||
Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)),
|
||||
)=(
|
||||
decal.properties.get("TextureContent"),
|
||||
decal.properties.get("Face"),
|
||||
decal.properties.get("Color3"),
|
||||
decal.properties.get("Transparency"),
|
||||
decal.properties.get(hstr!("TextureContent")),
|
||||
decal.properties.get(hstr!("Face")),
|
||||
decal.properties.get(hstr!("Color3")),
|
||||
decal.properties.get(hstr!("Transparency")),
|
||||
)else{
|
||||
println!("Decal is missing a required property");
|
||||
continue;
|
||||
@@ -442,10 +444,10 @@ fn get_texture_description<'a>(
|
||||
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"),
|
||||
decal.properties.get(hstr!("OffsetStudsU")),
|
||||
decal.properties.get(hstr!("OffsetStudsV")),
|
||||
decal.properties.get(hstr!("StudsPerTileU")),
|
||||
decal.properties.get(hstr!("StudsPerTileV")),
|
||||
)
|
||||
{
|
||||
let (size_u,size_v)=match cube_face{
|
||||
@@ -532,7 +534,7 @@ pub fn convert<'a>(
|
||||
|
||||
let mut object_refs=Vec::new();
|
||||
let mut temp_objects=Vec::new();
|
||||
recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart");
|
||||
recursive_collect_superclass(&mut object_refs, &dom, dom.root(),hstr!("BasePart"));
|
||||
for object_ref in object_refs {
|
||||
if let Some(object)=dom.get_by_ref(object_ref){
|
||||
if let (
|
||||
@@ -543,12 +545,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(hstr!("CFrame")),
|
||||
object.properties.get(hstr!("Size")),
|
||||
object.properties.get(hstr!("Velocity")),
|
||||
object.properties.get(hstr!("Transparency")),
|
||||
object.properties.get(hstr!("Color")),
|
||||
object.properties.get(hstr!("CanCollide")),
|
||||
)
|
||||
{
|
||||
let model_transform=planar64_affine3_from_roblox(cf,size);
|
||||
@@ -566,8 +568,8 @@ pub fn convert<'a>(
|
||||
}
|
||||
|
||||
//TODO: also detect "CylinderMesh" etc here
|
||||
let shape=match object.class{
|
||||
"Part"=>if let Some(rbx_dom_weak::types::Variant::Enum(shape))=object.properties.get("Shape"){
|
||||
let shape=match object.class.as_str(){
|
||||
"Part"=>if let Some(rbx_dom_weak::types::Variant::Enum(shape))=object.properties.get(hstr!("Shape")){
|
||||
Shape::Primitive(shape.to_u32().try_into().expect("Funky roblox PartType"))
|
||||
}else{
|
||||
panic!("Part has no Shape!");
|
||||
@@ -641,9 +643,9 @@ pub fn convert<'a>(
|
||||
Some(rbx_dom_weak::types::Variant::Content(texture_content)),
|
||||
)=(
|
||||
// mesh must exist
|
||||
object.properties.get("MeshContent"),
|
||||
object.properties.get(hstr!("MeshContent")),
|
||||
// texture is allowed to be none
|
||||
object.properties.get("TextureContent"),
|
||||
object.properties.get(hstr!("TextureContent")),
|
||||
){
|
||||
let mesh_asset_id=get_content_url(mesh_content).expect("MeshPart Mesh is not a Uri");
|
||||
let texture_asset_id=get_content_url(texture_content);
|
||||
@@ -658,13 +660,13 @@ 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::ContentId(asset_id))=object.properties.get("AssetId"){
|
||||
if let Some(rbx_dom_weak::types::Variant::ContentId(asset_id))=object.properties.get(hstr!("AssetId")){
|
||||
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(hstr!("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(hstr!("PhysicsData")){
|
||||
physics_data=data.as_ref();
|
||||
}
|
||||
let part_texture_description=get_texture_description(&mut temp_objects,render_config_deferred_loader,dom,object,size);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rbx_dom_weak::{types::Ref,InstanceBuilder,WeakDom};
|
||||
use rbx_dom_weak::{hstr,types::Ref,InstanceBuilder,WeakDom,UnhashedStr};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ServicesError{
|
||||
@@ -39,11 +39,11 @@ impl<'a> Context<'a>{
|
||||
Ok(Self{dom,services})
|
||||
}
|
||||
pub fn script_singleton(source:String)->(Context<'a>,crate::runner::instance::Instance){
|
||||
let script=InstanceBuilder::new("Script")
|
||||
.with_property("Source",rbx_types::Variant::String(source));
|
||||
let script=InstanceBuilder::new(hstr!("Script"))
|
||||
.with_property(hstr!("Source"),rbx_types::Variant::String(source));
|
||||
let script_ref=script.referent();
|
||||
let dom=WeakDom::new(
|
||||
InstanceBuilder::new("DataModel")
|
||||
InstanceBuilder::new(hstr!("DataModel"))
|
||||
.with_child(script)
|
||||
);
|
||||
let context=Self::from_model(dom);
|
||||
@@ -52,7 +52,7 @@ impl<'a> Context<'a>{
|
||||
/// Creates an iterator over all items of a particular class.
|
||||
pub fn superclass_iter<'b>(&'b self,superclass:&'b str)->impl Iterator<Item=Ref>+'b{
|
||||
let db=rbx_reflection_database::get();
|
||||
let Some(superclass)=db.classes.get(superclass)else{
|
||||
let Some(superclass)=db.classes.get(UnhashedStr::from_ref(superclass))else{
|
||||
panic!("Invalid class");
|
||||
};
|
||||
self.dom.descendants().filter_map(|instance|{
|
||||
@@ -64,7 +64,7 @@ impl<'a> Context<'a>{
|
||||
self.superclass_iter("Script")
|
||||
.filter_map(|script_ref|{
|
||||
let script=self.dom.get_by_ref(script_ref)?;
|
||||
if let None|Some(rbx_dom_weak::types::Variant::Bool(false))=script.properties.get("Disabled"){
|
||||
if let None|Some(rbx_dom_weak::types::Variant::Bool(false))=script.properties.get(hstr!("Disabled")){
|
||||
return Some(crate::runner::instance::Instance::new_unchecked(script_ref));
|
||||
}
|
||||
None
|
||||
@@ -78,11 +78,11 @@ impl<'a> Context<'a>{
|
||||
|
||||
//insert services
|
||||
let game=dom.root_ref();
|
||||
let terrain_bldr=InstanceBuilder::new("Terrain");
|
||||
let terrain_bldr=InstanceBuilder::new(hstr!("Terrain"));
|
||||
let workspace=dom.insert(game,
|
||||
InstanceBuilder::new("Workspace")
|
||||
InstanceBuilder::new(hstr!("Workspace"))
|
||||
//Set Workspace.Terrain property equal to Terrain
|
||||
.with_property("Terrain",terrain_bldr.referent())
|
||||
.with_property(hstr!("Terrain"),terrain_bldr.referent())
|
||||
.with_child(terrain_bldr)
|
||||
);
|
||||
|
||||
@@ -95,10 +95,10 @@ impl<'a> Context<'a>{
|
||||
//Lowercase and upper case workspace property!
|
||||
let game=dom.root_mut();
|
||||
// TODO: DELETE THIS!
|
||||
game.properties.insert("workspace",rbx_types::Variant::Ref(workspace));
|
||||
game.properties.insert("Workspace",rbx_types::Variant::Ref(workspace));
|
||||
game.properties.insert(hstr!("workspace"),rbx_types::Variant::Ref(workspace));
|
||||
game.properties.insert(hstr!("Workspace"),rbx_types::Variant::Ref(workspace));
|
||||
}
|
||||
dom.insert(game,InstanceBuilder::new("Lighting"));
|
||||
dom.insert(game,InstanceBuilder::new(hstr!("Lighting")));
|
||||
|
||||
let services=Services{game,workspace};
|
||||
Self{dom,services}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use rbx_dom_weak::{HashStr, UnhashedStr};
|
||||
|
||||
#[derive(Clone,Copy)]
|
||||
pub struct EnumItem<'a>{
|
||||
name:Option<&'a str>,
|
||||
name:Option<&'a HashStr>,
|
||||
value:u32,
|
||||
}
|
||||
impl<'a> EnumItem<'a>{
|
||||
fn known_name((name,&value):(&&'a str,&u32))->Self{
|
||||
fn known_name((name,&value):(&&'a HashStr,&u32))->Self{
|
||||
Self{name:Some(name),value}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +40,7 @@ pub struct Enums;
|
||||
impl Enums{
|
||||
pub fn get(&self,index:&str)->Option<EnumItems<'static>>{
|
||||
let db=rbx_reflection_database::get();
|
||||
db.enums.get(index).map(|ed|EnumItems{ed})
|
||||
db.enums.get(UnhashedStr::from_ref(index)).map(|ed|EnumItems{ed})
|
||||
}
|
||||
}
|
||||
#[derive(Clone,Copy)]
|
||||
@@ -51,7 +53,7 @@ impl<'a> EnumItems<'a>{
|
||||
self.ed.items.iter().find(|&(_,&v)|v==value).map(EnumItem::known_name)
|
||||
}
|
||||
pub fn from_name(&self,name:&str)->Option<EnumItem<'a>>{
|
||||
self.ed.items.get_key_value(name).map(EnumItem::known_name)
|
||||
self.ed.items.get_key_value(UnhashedStr::from_ref(name)).map(EnumItem::known_name)
|
||||
}
|
||||
pub fn from_enum(&self,enum_item:EnumItem)->Option<EnumItem<'a>>{
|
||||
match enum_item.name{
|
||||
@@ -105,7 +107,7 @@ impl mlua::UserData for EnumItems<'static>{
|
||||
});
|
||||
methods.add_meta_function(mlua::MetaMethod::Index,|_,(this,val):(EnumItems,mlua::String)|{
|
||||
let index=&*val.to_str()?;
|
||||
Ok(this.ed.items.get_key_value(index).map(EnumItem::known_name))
|
||||
Ok(this.ed.items.get_key_value(UnhashedStr::from_ref(index)).map(EnumItem::known_name))
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -124,7 +126,7 @@ type_from_lua_userdata!(Enums);
|
||||
|
||||
impl mlua::UserData for EnumItem<'_>{
|
||||
fn add_fields<F:mlua::UserDataFields<Self>>(fields:&mut F){
|
||||
fields.add_field_method_get("Name",|_,this|Ok(this.name));
|
||||
fields.add_field_method_get("Name",|_,this|Ok(this.name.map(|s|s.as_str())));
|
||||
fields.add_field_method_get("Value",|_,this|Ok(this.value));
|
||||
}
|
||||
fn add_methods<M:mlua::UserDataMethods<Self>>(methods:&mut M){
|
||||
|
||||
@@ -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::{hstr,HashStr,UnhashedStr,InstanceBuilder,WeakDom};
|
||||
|
||||
use crate::runner::vector3::Vector3;
|
||||
use crate::runner::number::Number;
|
||||
@@ -18,12 +18,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
|
||||
lua.create_function(|lua,(class_name,parent):(mlua::String,Option<Instance>)|{
|
||||
let class_name_str=&*class_name.to_str()?;
|
||||
let parent_ref=parent.map_or(Ref::none(),|instance|instance.referent);
|
||||
let db=rbx_reflection_database::get();
|
||||
let Some((known_class_name,_))=db.classes.get_key_value(class_name_str)else{
|
||||
return Err(mlua::Error::runtime("Unknown ClassName"));
|
||||
};
|
||||
dom_mut(lua,|dom|{
|
||||
Ok(Instance::new_unchecked(dom.insert(parent_ref,InstanceBuilder::new(known_class_name))))
|
||||
Ok(Instance::new_unchecked(dom.insert(parent_ref,InstanceBuilder::new(class_name_str))))
|
||||
})
|
||||
})?
|
||||
)?;
|
||||
@@ -41,7 +37,7 @@ pub fn dom_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result<T>
|
||||
|
||||
pub fn class_is_a(class:&str,superclass:&str)->bool{
|
||||
let db=rbx_reflection_database::get();
|
||||
let (Some(class),Some(superclass))=(db.classes.get(class),db.classes.get(superclass))else{
|
||||
let (Some(class),Some(superclass))=(db.classes.get(UnhashedStr::from_ref(class)),db.classes.get(UnhashedStr::from_ref(superclass)))else{
|
||||
return false;
|
||||
};
|
||||
db.has_superclass(class,superclass)
|
||||
@@ -60,7 +56,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(hstr!("Source")){
|
||||
Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(),
|
||||
_=>Err(mlua::Error::external("Missing script.Source"))?,
|
||||
};
|
||||
@@ -84,14 +80,14 @@ pub fn find_first_descendant_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom<'a>,inst
|
||||
|
||||
pub fn find_first_child_which_is_a<'a>(dom:&'a rbx_dom_weak::WeakDom<'a>,instance:&rbx_dom_weak::Instance<'a>,superclass:&str)->Option<&'a rbx_dom_weak::Instance<'a>>{
|
||||
let db=rbx_reflection_database::get();
|
||||
let superclass_descriptor=db.classes.get(superclass)?;
|
||||
let superclass_descriptor=db.classes.get(UnhashedStr::from_ref(superclass))?;
|
||||
instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|{
|
||||
db.classes.get(inst.class).is_some_and(|descriptor|db.has_superclass(descriptor,superclass_descriptor))
|
||||
})
|
||||
}
|
||||
pub fn find_first_descendant_which_is_a<'a>(dom:&'a rbx_dom_weak::WeakDom<'a>,instance:&rbx_dom_weak::Instance<'a>,superclass:&str)->Option<&'a rbx_dom_weak::Instance<'a>>{
|
||||
let db=rbx_reflection_database::get();
|
||||
let superclass_descriptor=db.classes.get(superclass)?;
|
||||
let superclass_descriptor=db.classes.get(UnhashedStr::from_ref(superclass))?;
|
||||
dom.descendants_of(instance.referent()).find(|inst|{
|
||||
db.classes.get(inst.class).is_some_and(|descriptor|db.has_superclass(descriptor,superclass_descriptor))
|
||||
})
|
||||
@@ -153,7 +149,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.to_owned())
|
||||
Ok(instance.class.as_str().to_owned())
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -259,7 +255,7 @@ impl mlua::UserData for Instance{
|
||||
fn is_a(lua:&mlua::Lua,this:&Instance,classname:mlua::String)->mlua::Result<bool>{
|
||||
dom_mut(lua,|dom|{
|
||||
let instance=this.get(dom)?;
|
||||
Ok(class_is_a(instance.class,&*classname.to_str()?))
|
||||
Ok(class_is_a(instance.class.as_str(),&*classname.to_str()?))
|
||||
})
|
||||
}
|
||||
methods.add_method("isA",is_a);
|
||||
@@ -288,7 +284,12 @@ impl mlua::UserData for Instance{
|
||||
let db=rbx_reflection_database::get();
|
||||
let class=db.classes.get(instance.class).ok_or_else(||mlua::Error::runtime("Class missing"))?;
|
||||
// Find existing property
|
||||
match instance.properties.get(index_str).cloned()
|
||||
// Interestingly, ustr can know ahead of time if
|
||||
// a property does not exist in any runtime instance
|
||||
match Ustr::from_existing(index_str)
|
||||
.and_then(|index_ustr|
|
||||
instance.properties.get(&index_ustr).cloned()
|
||||
)
|
||||
//Find default value
|
||||
.or_else(||db.find_default_property(class,index_str).cloned())
|
||||
//Find virtual property
|
||||
@@ -341,8 +342,8 @@ impl mlua::UserData for Instance{
|
||||
let instance=this.get_mut(dom)?;
|
||||
let db=rbx_reflection_database::get();
|
||||
let class=db.classes.get(instance.class).ok_or_else(||mlua::Error::runtime("Class missing"))?;
|
||||
let (prop_name,property)=db.superclasses_iter(class).find_map(|cls|
|
||||
cls.properties.get_key_value(index_str)
|
||||
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))
|
||||
)?;
|
||||
@@ -427,7 +428,10 @@ impl mlua::UserData for Instance{
|
||||
},
|
||||
other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))),
|
||||
};
|
||||
instance.properties.insert(prop_name,value);
|
||||
// the index is known to be a real property at this point
|
||||
// allow creating a permanent ustr (memory leak)
|
||||
let index_ustr=rbx_dom_weak::ustr(index_str);
|
||||
instance.properties.insert(index_ustr,value);
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
@@ -452,27 +456,21 @@ type CFD=phf::Map<&'static str,// Class name
|
||||
ClassFunctionPointer
|
||||
>
|
||||
>;
|
||||
const SERVICES:phf::Map<&'static str,()> =phf::phf_map!{
|
||||
"Lighting"=>(),
|
||||
"RunService"=>(),
|
||||
"Players"=>(),
|
||||
"Workspace"=>(),
|
||||
"MaterialService"=>(),
|
||||
"TweenService"=>(),
|
||||
};
|
||||
const GET_SERVICE:ClassFunctionPointer=cf!(|lua,_this,service:mlua::String|{
|
||||
dom_mut(lua,|dom|{
|
||||
//dom.root_ref()==this.referent ?
|
||||
let service=&*service.to_str()?;
|
||||
let Some(known_service)=SERVICES.get_key(service)else{
|
||||
return Err(mlua::Error::runtime(format!("Service '{service}' not supported")));
|
||||
};
|
||||
let referent=find_first_child_of_class(dom,dom.root(),known_service)
|
||||
.map(|instance|instance.referent())
|
||||
.unwrap_or_else(||
|
||||
dom.insert(dom.root_ref(),InstanceBuilder::new(known_service))
|
||||
);
|
||||
Ok(Instance::new_unchecked(referent))
|
||||
match service{
|
||||
"Lighting"|"RunService"|"Players"|"Workspace"|"MaterialService"|"TweenService"=>{
|
||||
let referent=find_first_child_of_class(dom,dom.root(),service)
|
||||
.map(|instance|instance.referent())
|
||||
.unwrap_or_else(||
|
||||
dom.insert(dom.root_ref(),InstanceBuilder::new(service))
|
||||
);
|
||||
Ok(Instance::new_unchecked(referent))
|
||||
},
|
||||
other=>Err(mlua::Error::runtime(format!("Service '{other}' not supported"))),
|
||||
}
|
||||
})
|
||||
});
|
||||
const GET_PLAYERS:ClassFunctionPointer=cf!(|_lua,_this,()|->mlua::Result<_>{
|
||||
@@ -561,7 +559,7 @@ fn class_methods_store_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut ClassMethodsS
|
||||
/// A virtual property pointer definition shorthand.
|
||||
type VirtualPropertyFunctionPointer=fn(&rbx_types::Variant)->Option<rbx_types::Variant>;
|
||||
const fn vpp(
|
||||
property:&'static str,
|
||||
property:&'static HashStr,
|
||||
pointer:VirtualPropertyFunctionPointer,
|
||||
)->VirtualProperty{
|
||||
VirtualProperty{
|
||||
@@ -570,7 +568,7 @@ const fn vpp(
|
||||
}
|
||||
}
|
||||
struct VirtualProperty{
|
||||
property:&'static str,// Source property name
|
||||
property:&'static HashStr,// Source property name
|
||||
pointer:VirtualPropertyFunctionPointer,
|
||||
}
|
||||
type VPD=phf::Map<&'static str,// Class name
|
||||
@@ -578,9 +576,10 @@ type VPD=phf::Map<&'static str,// Class name
|
||||
VirtualProperty
|
||||
>
|
||||
>;
|
||||
static CFRAME:&HashStr=hstr!("CFrame");
|
||||
static VIRTUAL_PROPERTY_DATABASE:VPD=phf::phf_map!{
|
||||
"BasePart"=>phf::phf_map!{
|
||||
"Position"=>vpp("CFrame",|c:&rbx_types::Variant|{
|
||||
"Position"=>vpp(CFRAME,|c:&rbx_types::Variant|{
|
||||
let c=match c{
|
||||
rbx_types::Variant::CFrame(c)=>c,
|
||||
_=>return None,//fail silently and ungracefully
|
||||
@@ -591,7 +590,7 @@ static VIRTUAL_PROPERTY_DATABASE:VPD=phf::phf_map!{
|
||||
};
|
||||
|
||||
fn find_virtual_property(
|
||||
properties:&rbx_dom_weak::AHashMap<&str,rbx_types::Variant>,
|
||||
properties:&rbx_dom_weak::HashStrMap<rbx_types::Variant>,
|
||||
class:&rbx_reflection::ClassDescriptor,
|
||||
index:&str,
|
||||
)->Option<rbx_types::Variant>{
|
||||
@@ -645,16 +644,15 @@ fn get_or_create_userdata(instance:&mut rbx_dom_weak::Instance,lua:&mlua::Lua,in
|
||||
let Some(class)=db.classes.get(instance.class)else{
|
||||
return Ok(None)
|
||||
};
|
||||
if let Some((&static_str,create_userdata))=db.superclasses_iter(class).find_map(|superclass|
|
||||
if let Some((hstr,create_userdata))=db.superclasses_iter(class).find_map(|superclass|
|
||||
// find pair (class,index)
|
||||
LAZY_USER_DATA.get(&superclass.name)
|
||||
.and_then(|map|map.get_entry(index))
|
||||
.and_then(|map|map.get(index)).map(|f|(superclass.name,f))
|
||||
){
|
||||
panic!();
|
||||
// return Ok(Some(match instance.userdata.entry(static_str){
|
||||
// Entry::Occupied(entry)=>entry.get().clone(),
|
||||
// Entry::Vacant(entry)=>entry.insert(create_userdata(lua)?).clone(),
|
||||
// }));
|
||||
return Ok(Some(match instance.userdata.entry(hstr){
|
||||
Entry::Occupied(entry)=>entry.get().clone(),
|
||||
Entry::Vacant(entry)=>entry.insert(create_userdata(lua)?).clone(),
|
||||
}));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ impl Runner{
|
||||
init(&runner.lua).map_err(Error::RustLua)?;
|
||||
Ok(runner)
|
||||
}
|
||||
pub fn runnable_context<'a>(self,context:&'a mut Context)->Result<Runnable<'a>,Error>{
|
||||
pub fn runnable_context<'a>(self,context:&'a mut Context<'a>)->Result<Runnable<'a>,Error>{
|
||||
{
|
||||
let globals=self.lua.globals();
|
||||
globals.set("game",super::instance::Instance::new_unchecked(context.services.game)).map_err(Error::RustLua)?;
|
||||
|
||||
@@ -8,6 +8,11 @@ use strafesnet_deferred_loader::deferred_loader::LoadFailureMode;
|
||||
use rbxassetid::RobloxAssetId;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
// disallow non-static lifetimes
|
||||
fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
|
||||
rbx_dom_weak::ustr(s)
|
||||
}
|
||||
|
||||
const DOWNLOAD_LIMIT:usize=16;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
@@ -51,13 +56,13 @@ enum LoadDomError{
|
||||
Xml(rbx_xml::DecodeError),
|
||||
UnknownFormat,
|
||||
}
|
||||
fn load_dom<R:Read+Seek>(mut input:R)->Result<rbx_dom_weak::WeakDom<'static>,LoadDomError>{
|
||||
fn load_dom<R:Read+Seek>(mut input:R)->Result<rbx_dom_weak::WeakDom,LoadDomError>{
|
||||
let mut first_8=[0u8;8];
|
||||
input.read_exact(&mut first_8).map_err(LoadDomError::IO)?;
|
||||
input.rewind().map_err(LoadDomError::IO)?;
|
||||
match &first_8{
|
||||
b"<roblox!"=>rbx_binary::from_reader_default(input).map_err(LoadDomError::Binary),
|
||||
b"<roblox "=>rbx_xml::from_reader_default(input).map_err(LoadDomError::Xml),
|
||||
b"<roblox!"=>rbx_binary::from_reader(input).map_err(LoadDomError::Binary),
|
||||
b"<roblox "=>rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()).map_err(LoadDomError::Xml),
|
||||
_=>Err(LoadDomError::UnknownFormat),
|
||||
}
|
||||
}
|
||||
@@ -103,8 +108,8 @@ WrapLayer.ReferenceMeshContent
|
||||
*/
|
||||
|
||||
fn accumulate_content(content_list:&mut HashSet<RobloxAssetId>,object:&Instance,property:&'static str){
|
||||
let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get(property)else{
|
||||
println!("property={} does not exist for class={}",property,object.class);
|
||||
let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get(&static_ustr(property))else{
|
||||
println!("property={} does not exist for class={}",property,object.class.as_str());
|
||||
return;
|
||||
};
|
||||
let rbx_dom_weak::types::ContentType::Uri(uri)=content.value()else{
|
||||
@@ -118,8 +123,8 @@ fn accumulate_content(content_list:&mut HashSet<RobloxAssetId>,object:&Instance,
|
||||
content_list.insert(asset_id);
|
||||
}
|
||||
fn accumulate_content_id(content_list:&mut HashSet<RobloxAssetId>,object:&Instance,property:&'static str){
|
||||
let Some(rbx_dom_weak::types::Variant::ContentId(content))=object.properties.get(property)else{
|
||||
println!("property={} does not exist for class={}",property,object.class);
|
||||
let Some(rbx_dom_weak::types::Variant::ContentId(content))=object.properties.get(&static_ustr(property))else{
|
||||
println!("property={} does not exist for class={}",property,object.class.as_str());
|
||||
return;
|
||||
};
|
||||
let Ok(asset_id)=content.as_str().parse()else{
|
||||
@@ -142,7 +147,7 @@ struct UniqueAssets{
|
||||
}
|
||||
impl UniqueAssets{
|
||||
fn collect(&mut self,object:&Instance){
|
||||
match object.class{
|
||||
match object.class.as_str(){
|
||||
"Beam"=>accumulate_content_id(&mut self.textures,object,"Texture"),
|
||||
"Decal"=>accumulate_content(&mut self.textures,object,"TextureContent"),
|
||||
"Texture"=>accumulate_content(&mut self.textures,object,"TextureContent"),
|
||||
|
||||
@@ -28,7 +28,7 @@ impl std::error::Error for ReadError{}
|
||||
|
||||
pub enum ReadFormat{
|
||||
#[cfg(feature="roblox")]
|
||||
Roblox(strafesnet_rbx_loader::Model<'static>),
|
||||
Roblox(strafesnet_rbx_loader::Model),
|
||||
#[cfg(feature="source")]
|
||||
Source(strafesnet_bsp_loader::Bsp),
|
||||
#[cfg(feature="snf")]
|
||||
|
||||
Reference in New Issue
Block a user