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