wip: hash_str

This commit is contained in:
2025-05-03 22:11:58 -07:00
parent b46fb04a5d
commit 8ab910e18f
9 changed files with 90 additions and 102 deletions
lib

@ -21,19 +21,19 @@ pub mod data{
} }
} }
pub struct Model{ pub struct Model<'a>{
dom:WeakDom, dom:WeakDom<'a>,
} }
impl Model{ impl<'a> Model<'a>{
fn new(dom:WeakDom)->Self{ fn new(dom:WeakDom<'a>)->Self{
Self{dom} Self{dom}
} }
pub fn to_snf(&self,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{ pub fn to_snf(&self,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
to_snf(self,failure_mode) to_snf(self,failure_mode)
} }
} }
impl AsRef<WeakDom> for Model{ impl<'a> AsRef<WeakDom<'a>> for Model<'a>{
fn as_ref(&self)->&WeakDom{ fn as_ref(&self)->&WeakDom<'a>{
&self.dom &self.dom
} }
} }
@ -95,7 +95,7 @@ pub fn read<R:Read>(input:R)->Result<Model,ReadError>{
let mut buf=std::io::BufReader::new(input); 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(ReadError::Io)?;
match peek.get(0..8){ match peek.get(0..8){
Some(b"<roblox!")=>rbx_binary::from_reader(buf).map(Model::new).map_err(ReadError::RbxBinary), Some(b"<roblox!")=>rbx_binary::from_reader_default(buf).map(Model::new).map_err(ReadError::RbxBinary),
Some(b"<roblox ")=>rbx_xml::from_reader_default(buf).map(Model::new).map_err(ReadError::RbxXml), Some(b"<roblox ")=>rbx_xml::from_reader_default(buf).map(Model::new).map_err(ReadError::RbxXml),
_=>Err(ReadError::UnknownFileFormat), _=>Err(ReadError::UnknownFileFormat),
} }

@ -6,10 +6,7 @@ use strafesnet_deferred_loader::{loader::Loader,texture::Texture};
use crate::data::RobloxMeshBytes; use crate::data::RobloxMeshBytes;
use crate::rbx::RobloxPartDescription; use crate::rbx::RobloxPartDescription;
// disallow non-static lifetimes use rbx_dom_weak::hstr;
fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
rbx_dom_weak::ustr(s)
}
fn read_entire_file(path:impl AsRef<std::path::Path>)->Result<Vec<u8>,std::io::Error>{ fn read_entire_file(path:impl AsRef<std::path::Path>)->Result<Vec<u8>,std::io::Error>{
let mut file=std::fs::File::open(path)?; let mut file=std::fs::File::open(path)?;
@ -168,7 +165,7 @@ impl Loader for MeshLoader{
let RobloxAssetId(asset_id)=index.content.parse()?; let RobloxAssetId(asset_id)=index.content.parse()?;
let file_name=format!("unions/{}",asset_id); let file_name=format!("unions/{}",asset_id);
let data=read_entire_file(file_name)?; let data=read_entire_file(file_name)?;
let dom=rbx_binary::from_reader(std::io::Cursor::new(data))?; let dom=rbx_binary::from_reader_default(data.as_slice())?;
let &[referent]=dom.root().children()else{ let &[referent]=dom.root().children()else{
return Err(MeshError::OneChildPolicy); return Err(MeshError::OneChildPolicy);
}; };
@ -176,12 +173,12 @@ impl Loader for MeshLoader{
return Err(MeshError::MissingInstance); return Err(MeshError::MissingInstance);
}; };
if physics_data.is_empty(){ if physics_data.is_empty(){
if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get(&static_ustr("PhysicsData")){ if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get(hstr!("PhysicsData")){
physics_data=data.as_ref(); physics_data=data.as_ref();
} }
} }
if mesh_data.is_empty(){ if mesh_data.is_empty(){
if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get(&static_ustr("MeshData")){ if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get(hstr!("MeshData")){
mesh_data=data.as_ref(); mesh_data=data.as_ref();
} }
} }

@ -13,16 +13,13 @@ use strafesnet_deferred_loader::deferred_loader::{RenderConfigDeferredLoader,Mes
use strafesnet_deferred_loader::mesh::Meshes; use strafesnet_deferred_loader::mesh::Meshes;
use strafesnet_deferred_loader::texture::{RenderConfigs,Texture}; use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
// disallow non-static lifetimes use rbx_dom_weak::{hstr,HashStr};
fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
rbx_dom_weak::ustr(s)
}
fn recursive_collect_superclass( fn recursive_collect_superclass(
objects:&mut std::vec::Vec<rbx_dom_weak::types::Ref>, objects:&mut std::vec::Vec<rbx_dom_weak::types::Ref>,
dom:&rbx_dom_weak::WeakDom, dom:&rbx_dom_weak::WeakDom,
instance:&rbx_dom_weak::Instance, instance:&rbx_dom_weak::Instance,
superclass:&str superclass:&HashStr,
){ ){
let instance=instance; let instance=instance;
let db=rbx_reflection_database::get(); let db=rbx_reflection_database::get();
@ -31,7 +28,7 @@ fn recursive_collect_superclass(
}; };
objects.extend( objects.extend(
dom.descendants_of(instance.referent()).filter_map(|instance|{ dom.descendants_of(instance.referent()).filter_map(|instance|{
let class=db.classes.get(instance.class.as_str())?; let class=db.classes.get(instance.class)?;
db.has_superclass(class,superclass).then(||instance.referent()) db.has_superclass(class,superclass).then(||instance.referent())
}) })
); );
@ -410,7 +407,7 @@ fn get_texture_description<'a>(
//use the biggest one and cut it down later... //use the biggest one and cut it down later...
let mut part_texture_description=RobloxPartDescription::default(); let mut part_texture_description=RobloxPartDescription::default();
temp_objects.clear(); 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{ for &mut decal_ref in temp_objects{
let Some(decal)=dom.get_by_ref(decal_ref) else{ let Some(decal)=dom.get_by_ref(decal_ref) else{
println!("Decal get_by_ref failed"); println!("Decal get_by_ref failed");
@ -422,10 +419,10 @@ fn get_texture_description<'a>(
Some(rbx_dom_weak::types::Variant::Color3(decal_color3)), Some(rbx_dom_weak::types::Variant::Color3(decal_color3)),
Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)), Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)),
)=( )=(
decal.properties.get(&static_ustr("TextureContent")), decal.properties.get(hstr!("TextureContent")),
decal.properties.get(&static_ustr("Face")), decal.properties.get(hstr!("Face")),
decal.properties.get(&static_ustr("Color3")), decal.properties.get(hstr!("Color3")),
decal.properties.get(&static_ustr("Transparency")), decal.properties.get(hstr!("Transparency")),
)else{ )else{
println!("Decal is missing a required property"); println!("Decal is missing a required property");
continue; continue;
@ -447,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_u)),
Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_v)), Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_v)),
) = ( ) = (
decal.properties.get(&static_ustr("OffsetStudsU")), decal.properties.get(hstr!("OffsetStudsU")),
decal.properties.get(&static_ustr("OffsetStudsV")), decal.properties.get(hstr!("OffsetStudsV")),
decal.properties.get(&static_ustr("StudsPerTileU")), decal.properties.get(hstr!("StudsPerTileU")),
decal.properties.get(&static_ustr("StudsPerTileV")), decal.properties.get(hstr!("StudsPerTileV")),
) )
{ {
let (size_u,size_v)=match cube_face{ let (size_u,size_v)=match cube_face{
@ -537,7 +534,7 @@ pub fn convert<'a>(
let mut object_refs=Vec::new(); let mut object_refs=Vec::new();
let mut temp_objects=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 { for object_ref in object_refs {
if let Some(object)=dom.get_by_ref(object_ref){ if let Some(object)=dom.get_by_ref(object_ref){
if let ( if let (
@ -548,12 +545,12 @@ pub fn convert<'a>(
Some(rbx_dom_weak::types::Variant::Color3uint8(color3)), Some(rbx_dom_weak::types::Variant::Color3uint8(color3)),
Some(rbx_dom_weak::types::Variant::Bool(can_collide)), Some(rbx_dom_weak::types::Variant::Bool(can_collide)),
) = ( ) = (
object.properties.get(&static_ustr("CFrame")), object.properties.get(hstr!("CFrame")),
object.properties.get(&static_ustr("Size")), object.properties.get(hstr!("Size")),
object.properties.get(&static_ustr("Velocity")), object.properties.get(hstr!("Velocity")),
object.properties.get(&static_ustr("Transparency")), object.properties.get(hstr!("Transparency")),
object.properties.get(&static_ustr("Color")), object.properties.get(hstr!("Color")),
object.properties.get(&static_ustr("CanCollide")), object.properties.get(hstr!("CanCollide")),
) )
{ {
let model_transform=planar64_affine3_from_roblox(cf,size); let model_transform=planar64_affine3_from_roblox(cf,size);
@ -572,7 +569,7 @@ pub fn convert<'a>(
//TODO: also detect "CylinderMesh" etc here //TODO: also detect "CylinderMesh" etc here
let shape=match object.class.as_str(){ let shape=match object.class.as_str(){
"Part"=>if let Some(rbx_dom_weak::types::Variant::Enum(shape))=object.properties.get(&static_ustr("Shape")){ "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")) Shape::Primitive(shape.to_u32().try_into().expect("Funky roblox PartType"))
}else{ }else{
panic!("Part has no Shape!"); panic!("Part has no Shape!");
@ -646,9 +643,9 @@ pub fn convert<'a>(
Some(rbx_dom_weak::types::Variant::Content(texture_content)), Some(rbx_dom_weak::types::Variant::Content(texture_content)),
)=( )=(
// mesh must exist // mesh must exist
object.properties.get(&static_ustr("MeshContent")), object.properties.get(hstr!("MeshContent")),
// texture is allowed to be none // texture is allowed to be none
object.properties.get(&static_ustr("TextureContent")), object.properties.get(hstr!("TextureContent")),
){ ){
let mesh_asset_id=get_content_url(mesh_content).expect("MeshPart Mesh is not a Uri"); 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); let texture_asset_id=get_content_url(texture_content);
@ -663,13 +660,13 @@ pub fn convert<'a>(
let mut content=""; let mut content="";
let mut mesh_data:&[u8]=&[]; let mut mesh_data:&[u8]=&[];
let mut physics_data:&[u8]=&[]; let mut physics_data:&[u8]=&[];
if let Some(rbx_dom_weak::types::Variant::ContentId(asset_id))=object.properties.get(&static_ustr("AssetId")){ if let Some(rbx_dom_weak::types::Variant::ContentId(asset_id))=object.properties.get(hstr!("AssetId")){
content=asset_id.as_ref(); content=asset_id.as_ref();
} }
if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get(&static_ustr("MeshData")){ if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get(hstr!("MeshData")){
mesh_data=data.as_ref(); mesh_data=data.as_ref();
} }
if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get(&static_ustr("PhysicsData")){ if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get(hstr!("PhysicsData")){
physics_data=data.as_ref(); physics_data=data.as_ref();
} }
let part_texture_description=get_texture_description(&mut temp_objects,render_config_deferred_loader,dom,object,size); let part_texture_description=get_texture_description(&mut temp_objects,render_config_deferred_loader,dom,object,size);

@ -1,5 +1,4 @@
use crate::util::static_ustr; use rbx_dom_weak::{hstr,types::Ref,InstanceBuilder,WeakDom,UnhashedStr};
use rbx_dom_weak::{types::Ref,InstanceBuilder,WeakDom};
#[derive(Debug)] #[derive(Debug)]
pub enum ServicesError{ pub enum ServicesError{
@ -28,36 +27,36 @@ impl Services{
} }
} }
pub type LuaAppData=&'static mut WeakDom; pub type LuaAppData=&'static mut WeakDom<'static>;
pub struct Context{ pub struct Context<'a>{
pub(crate)dom:WeakDom, pub(crate)dom:WeakDom<'a>,
pub(crate)services:Services, pub(crate)services:Services,
} }
impl Context{ impl<'a> Context<'a>{
pub fn from_place(dom:WeakDom)->Result<Context,ServicesError>{ pub fn from_place(dom:WeakDom<'a>)->Result<Context<'a>,ServicesError>{
let services=Services::find_services(&dom)?; let services=Services::find_services(&dom)?;
Ok(Self{dom,services}) Ok(Self{dom,services})
} }
pub fn script_singleton(source:String)->(Context,crate::runner::instance::Instance){ pub fn script_singleton(source:String)->(Context<'a>,crate::runner::instance::Instance){
let script=InstanceBuilder::new("Script") let script=InstanceBuilder::new(hstr!("Script"))
.with_property("Source",rbx_types::Variant::String(source)); .with_property(hstr!("Source"),rbx_types::Variant::String(source));
let script_ref=script.referent(); let script_ref=script.referent();
let dom=WeakDom::new( let dom=WeakDom::new(
InstanceBuilder::new("DataModel") InstanceBuilder::new(hstr!("DataModel"))
.with_child(script) .with_child(script)
); );
let context=Self::from_model(dom); let context=Self::from_model(dom);
(context,crate::runner::instance::Instance::new_unchecked(script_ref)) (context,crate::runner::instance::Instance::new_unchecked(script_ref))
} }
/// Creates an iterator over all items of a particular class. /// Creates an iterator over all items of a particular class.
pub fn superclass_iter<'a>(&'a self,superclass:&'a str)->impl Iterator<Item=Ref>+'a{ pub fn superclass_iter<'b>(&'b self,superclass:&'b str)->impl Iterator<Item=Ref>+'b{
let db=rbx_reflection_database::get(); 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"); panic!("Invalid class");
}; };
self.dom.descendants().filter_map(|instance|{ self.dom.descendants().filter_map(|instance|{
let class=db.classes.get(instance.class.as_str())?; let class=db.classes.get(instance.class)?;
db.has_superclass(class,superclass).then(||instance.referent()) db.has_superclass(class,superclass).then(||instance.referent())
}) })
} }
@ -65,7 +64,7 @@ impl Context{
self.superclass_iter("Script") self.superclass_iter("Script")
.filter_map(|script_ref|{ .filter_map(|script_ref|{
let script=self.dom.get_by_ref(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(&static_ustr("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)); return Some(crate::runner::instance::Instance::new_unchecked(script_ref));
} }
None None
@ -73,17 +72,17 @@ impl Context{
.collect() .collect()
} }
pub fn from_model(mut dom:WeakDom)->Context{ pub fn from_model(mut dom:WeakDom<'a>)->Context<'a>{
//snapshot root instances //snapshot root instances
let children=dom.root().children().to_owned(); let children=dom.root().children().to_owned();
//insert services //insert services
let game=dom.root_ref(); let game=dom.root_ref();
let terrain_bldr=InstanceBuilder::new("Terrain"); let terrain_bldr=InstanceBuilder::new(hstr!("Terrain"));
let workspace=dom.insert(game, let workspace=dom.insert(game,
InstanceBuilder::new("Workspace") InstanceBuilder::new(hstr!("Workspace"))
//Set Workspace.Terrain property equal to Terrain //Set Workspace.Terrain property equal to Terrain
.with_property("Terrain",terrain_bldr.referent()) .with_property(hstr!("Terrain"),terrain_bldr.referent())
.with_child(terrain_bldr) .with_child(terrain_bldr)
); );
@ -96,18 +95,18 @@ impl Context{
//Lowercase and upper case workspace property! //Lowercase and upper case workspace property!
let game=dom.root_mut(); let game=dom.root_mut();
// TODO: DELETE THIS! // TODO: DELETE THIS!
game.properties.insert(static_ustr("workspace"),rbx_types::Variant::Ref(workspace)); game.properties.insert(hstr!("workspace"),rbx_types::Variant::Ref(workspace));
game.properties.insert(static_ustr("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}; let services=Services{game,workspace};
Self{dom,services} Self{dom,services}
} }
} }
impl AsRef<WeakDom> for Context{ impl<'a> AsRef<WeakDom<'a>> for Context<'a>{
fn as_ref(&self)->&WeakDom{ fn as_ref(&self)->&WeakDom<'a>{
&self.dom &self.dom
} }
} }

@ -1,4 +1,3 @@
mod util;
pub mod runner; pub mod runner;
pub mod context; pub mod context;
#[cfg(feature="run-service")] #[cfg(feature="run-service")]

@ -1,11 +1,13 @@
use rbx_dom_weak::{HashStr, UnhashedStr};
#[derive(Clone,Copy)] #[derive(Clone,Copy)]
pub struct EnumItem<'a>{ pub struct EnumItem<'a>{
name:Option<&'a str>, name:Option<&'a HashStr>,
value:u32, value:u32,
} }
impl<'a> EnumItem<'a>{ impl<'a> EnumItem<'a>{
fn known_name((name,&value):(&'a std::borrow::Cow<'a,str>,&u32))->Self{ fn known_name((name,&value):(&&'a HashStr,&u32))->Self{
Self{name:Some(name.as_ref()),value} Self{name:Some(name),value}
} }
} }
impl<'a> From<rbx_types::Enum> for EnumItem<'a>{ impl<'a> From<rbx_types::Enum> for EnumItem<'a>{
@ -38,7 +40,7 @@ pub struct Enums;
impl Enums{ impl Enums{
pub fn get(&self,index:&str)->Option<EnumItems<'static>>{ pub fn get(&self,index:&str)->Option<EnumItems<'static>>{
let db=rbx_reflection_database::get(); 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)] #[derive(Clone,Copy)]
@ -51,7 +53,7 @@ impl<'a> EnumItems<'a>{
self.ed.items.iter().find(|&(_,&v)|v==value).map(EnumItem::known_name) self.ed.items.iter().find(|&(_,&v)|v==value).map(EnumItem::known_name)
} }
pub fn from_name(&self,name:&str)->Option<EnumItem<'a>>{ 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>>{ pub fn from_enum(&self,enum_item:EnumItem)->Option<EnumItem<'a>>{
match enum_item.name{ 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)|{ methods.add_meta_function(mlua::MetaMethod::Index,|_,(this,val):(EnumItems,mlua::String)|{
let index=&*val.to_str()?; 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<'_>{ impl mlua::UserData for EnumItem<'_>{
fn add_fields<F:mlua::UserDataFields<Self>>(fields:&mut F){ 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)); fields.add_field_method_get("Value",|_,this|Ok(this.value));
} }
fn add_methods<M:mlua::UserDataMethods<Self>>(methods:&mut M){ fn add_methods<M:mlua::UserDataMethods<Self>>(methods:&mut M){

@ -2,9 +2,8 @@ use std::collections::{hash_map::Entry,HashMap};
use mlua::{FromLua,FromLuaMulti,IntoLua,IntoLuaMulti}; use mlua::{FromLua,FromLuaMulti,IntoLua,IntoLuaMulti};
use rbx_types::Ref; use rbx_types::Ref;
use rbx_dom_weak::{Ustr,InstanceBuilder,WeakDom}; use rbx_dom_weak::{hstr,HashStr,UnhashedStr,InstanceBuilder,WeakDom};
use crate::util::static_ustr;
use crate::runner::vector3::Vector3; use crate::runner::vector3::Vector3;
use crate::runner::number::Number; use crate::runner::number::Number;
@ -38,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{ pub fn class_is_a(class:&str,superclass:&str)->bool{
let db=rbx_reflection_database::get(); 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; return false;
}; };
db.has_superclass(class,superclass) db.has_superclass(class,superclass)
@ -57,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>{ pub fn get_name_source(lua:&mlua::Lua,script:Instance)->Result<(String,String),mlua::Error>{
dom_mut(lua,|dom|{ dom_mut(lua,|dom|{
let instance=script.get(dom)?; let instance=script.get(dom)?;
let source=match instance.properties.get(&static_ustr("Source")){ let source=match instance.properties.get(hstr!("Source")){
Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(), Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(),
_=>Err(mlua::Error::external("Missing script.Source"))?, _=>Err(mlua::Error::external("Missing script.Source"))?,
}; };
@ -65,32 +64,32 @@ pub fn get_name_source(lua:&mlua::Lua,script:Instance)->Result<(String,String),m
}) })
} }
pub fn find_first_child<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_child<'a>(dom:&'a rbx_dom_weak::WeakDom<'a>,instance:&rbx_dom_weak::Instance<'a>,name:&str)->Option<&'a rbx_dom_weak::Instance<'a>>{
instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.name==name) instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.name==name)
} }
pub fn find_first_descendant<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_descendant<'a>(dom:&'a rbx_dom_weak::WeakDom<'a>,instance:&rbx_dom_weak::Instance<'a>,name:&str)->Option<&'a rbx_dom_weak::Instance<'a>>{
dom.descendants_of(instance.referent()).find(|&inst|inst.name==name) dom.descendants_of(instance.referent()).find(|&inst|inst.name==name)
} }
pub fn find_first_child_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_child_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom<'a>,instance:&rbx_dom_weak::Instance<'a>,class:&str)->Option<&'a rbx_dom_weak::Instance<'a>>{
instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.class==class) instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.class==class)
} }
pub fn find_first_descendant_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_descendant_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom<'a>,instance:&rbx_dom_weak::Instance<'a>,class:&str)->Option<&'a rbx_dom_weak::Instance<'a>>{
dom.descendants_of(instance.referent()).find(|&inst|inst.class==class) dom.descendants_of(instance.referent()).find(|&inst|inst.class==class)
} }
pub fn find_first_child_which_is_a<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,superclass:&str)->Option<&'a rbx_dom_weak::Instance>{ 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 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|{ instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|{
db.classes.get(inst.class.as_str()).is_some_and(|descriptor|db.has_superclass(descriptor,superclass_descriptor)) 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,instance:&rbx_dom_weak::Instance,superclass:&str)->Option<&'a rbx_dom_weak::Instance>{ 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 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|{ dom.descendants_of(instance.referent()).find(|inst|{
db.classes.get(inst.class.as_str()).is_some_and(|descriptor|db.has_superclass(descriptor,superclass_descriptor)) db.classes.get(inst.class).is_some_and(|descriptor|db.has_superclass(descriptor,superclass_descriptor))
}) })
} }
@ -105,10 +104,10 @@ impl Instance{
pub fn new(referent:Ref)->Option<Self>{ pub fn new(referent:Ref)->Option<Self>{
referent.is_some().then_some(Self{referent}) referent.is_some().then_some(Self{referent})
} }
pub fn get<'a>(&self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ pub fn get<'a>(&self,dom:&'a WeakDom<'a>)->mlua::Result<&'a rbx_dom_weak::Instance<'a>>{
dom.get_by_ref(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing")) dom.get_by_ref(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing"))
} }
pub fn get_mut<'a>(&self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ pub fn get_mut<'a,'b>(&self,dom:&'a mut WeakDom<'b>)->mlua::Result<&'a mut rbx_dom_weak::Instance<'b>>{
dom.get_by_ref_mut(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing")) dom.get_by_ref_mut(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing"))
} }
} }
@ -150,7 +149,7 @@ impl mlua::UserData for Instance{
fields.add_field_method_get("ClassName",|lua,this|{ fields.add_field_method_get("ClassName",|lua,this|{
dom_mut(lua,|dom|{ dom_mut(lua,|dom|{
let instance=this.get(dom)?; let instance=this.get(dom)?;
Ok(instance.class.to_owned()) Ok(instance.class.as_str().to_owned())
}) })
}); });
} }
@ -283,7 +282,7 @@ impl mlua::UserData for Instance{
let instance=this.get(dom)?; let instance=this.get(dom)?;
//println!("__index t={} i={index:?}",instance.name); //println!("__index t={} i={index:?}",instance.name);
let db=rbx_reflection_database::get(); let db=rbx_reflection_database::get();
let class=db.classes.get(instance.class.as_str()).ok_or_else(||mlua::Error::runtime("Class missing"))?; let class=db.classes.get(instance.class).ok_or_else(||mlua::Error::runtime("Class missing"))?;
// Find existing property // Find existing property
// Interestingly, ustr can know ahead of time if // Interestingly, ustr can know ahead of time if
// a property does not exist in any runtime instance // a property does not exist in any runtime instance
@ -342,7 +341,7 @@ impl mlua::UserData for Instance{
dom_mut(lua,|dom|{ dom_mut(lua,|dom|{
let instance=this.get_mut(dom)?; let instance=this.get_mut(dom)?;
let db=rbx_reflection_database::get(); let db=rbx_reflection_database::get();
let class=db.classes.get(instance.class.as_str()).ok_or_else(||mlua::Error::runtime("Class missing"))?; let class=db.classes.get(instance.class).ok_or_else(||mlua::Error::runtime("Class missing"))?;
let property=db.superclasses_iter(class).find_map(|cls| let property=db.superclasses_iter(class).find_map(|cls|
cls.properties.get(index_str) cls.properties.get(index_str)
).ok_or_else(|| ).ok_or_else(||
@ -590,7 +589,7 @@ static VIRTUAL_PROPERTY_DATABASE:VPD=phf::phf_map!{
}; };
fn find_virtual_property( fn find_virtual_property(
properties:&rbx_dom_weak::UstrMap<rbx_types::Variant>, properties:&rbx_dom_weak::HashStrMap<rbx_types::Variant>,
class:&rbx_reflection::ClassDescriptor, class:&rbx_reflection::ClassDescriptor,
index:&str, index:&str,
)->Option<rbx_types::Variant>{ )->Option<rbx_types::Variant>{
@ -641,7 +640,7 @@ static LAZY_USER_DATA:LUD=phf::phf_map!{
fn get_or_create_userdata(instance:&mut rbx_dom_weak::Instance,lua:&mlua::Lua,index:&str)->mlua::Result<Option<mlua::AnyUserData>>{ fn get_or_create_userdata(instance:&mut rbx_dom_weak::Instance,lua:&mlua::Lua,index:&str)->mlua::Result<Option<mlua::AnyUserData>>{
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
let db=rbx_reflection_database::get(); let db=rbx_reflection_database::get();
let Some(class)=db.classes.get(instance.class.as_str())else{ let Some(class)=db.classes.get(instance.class)else{
return Ok(None) return Ok(None)
}; };
if let Some((&static_str,create_userdata))=db.superclasses_iter(class).find_map(|superclass| if let Some((&static_str,create_userdata))=db.superclasses_iter(class).find_map(|superclass|

@ -1,5 +1,4 @@
use crate::context::Context; use crate::context::Context;
use crate::util::static_ustr;
#[cfg(feature="run-service")] #[cfg(feature="run-service")]
use crate::scheduler::scheduler_mut; use crate::scheduler::scheduler_mut;
@ -59,7 +58,7 @@ impl Runner{
init(&runner.lua).map_err(Error::RustLua)?; init(&runner.lua).map_err(Error::RustLua)?;
Ok(runner) 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(); let globals=self.lua.globals();
globals.set("game",super::instance::Instance::new_unchecked(context.services.game)).map_err(Error::RustLua)?; globals.set("game",super::instance::Instance::new_unchecked(context.services.game)).map_err(Error::RustLua)?;
@ -68,8 +67,7 @@ impl Runner{
// SAFETY: This is not a &'static mut WeakDom, // SAFETY: This is not a &'static mut WeakDom,
// but as long as Runnable<'a> holds the lifetime of &'a mut Context // but as long as Runnable<'a> holds the lifetime of &'a mut Context
// it is a valid unique reference. // it is a valid unique reference.
let ptr=&mut context.dom as *mut rbx_dom_weak::WeakDom; self.lua.set_app_data::<crate::context::LuaAppData>(unsafe{core::mem::transmute(&mut context.dom)});
self.lua.set_app_data::<crate::context::LuaAppData>(unsafe{&mut*ptr});
#[cfg(feature="run-service")] #[cfg(feature="run-service")]
self.lua.set_app_data::<crate::scheduler::Scheduler>(crate::scheduler::Scheduler::default()); self.lua.set_app_data::<crate::scheduler::Scheduler>(crate::scheduler::Scheduler::default());
Ok(Runnable{ Ok(Runnable{

@ -1,3 +0,0 @@
pub fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
rbx_dom_weak::ustr(s)
}