diff --git a/CHANGELOG.md b/CHANGELOG.md index 9116635..cf5fc68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed attributes not being set properly if the instance has an empty attributes property - Fixed error messages for reading & writing roblox files not containing the full error message - Fixed crash when trying to access an instance reference property that points to a destroyed instance - Fixed crash when trying to save instances that contain unsupported attribute types diff --git a/packages/lib-roblox/src/instance/mod.rs b/packages/lib-roblox/src/instance/mod.rs index b7e480d..3213af9 100644 --- a/packages/lib-roblox/src/instance/mod.rs +++ b/packages/lib-roblox/src/instance/mod.rs @@ -7,7 +7,9 @@ use std::{ use mlua::prelude::*; use once_cell::sync::Lazy; use rbx_dom_weak::{ - types::{Ref as DomRef, Variant as DomValue, VariantType as DomType}, + types::{ + Attributes as DomAttributes, Ref as DomRef, Variant as DomValue, VariantType as DomType, + }, Instance as DomInstance, InstanceBuilder as DomInstanceBuilder, WeakDom, }; @@ -24,6 +26,9 @@ use crate::{ pub(crate) mod collection_service; pub(crate) mod data_model; +const PROPERTY_NAME_ATTRIBUTES: &str = "Attributes"; +const PROPERTY_NAME_TAGS: &str = "Tags"; + static INTERNAL_DOM: Lazy> = Lazy::new(|| RwLock::new(WeakDom::new(DomInstanceBuilder::new("ROOT")))); @@ -465,7 +470,9 @@ impl Instance { let inst = dom .get_by_ref(self.dom_ref) .expect("Failed to find instance in document"); - if let Some(DomValue::Attributes(attributes)) = inst.properties.get("Attributes") { + if let Some(DomValue::Attributes(attributes)) = + inst.properties.get(PROPERTY_NAME_ATTRIBUTES) + { attributes.get(name.as_ref()).cloned() } else { None @@ -486,7 +493,9 @@ impl Instance { let inst = dom .get_by_ref(self.dom_ref) .expect("Failed to find instance in document"); - if let Some(DomValue::Attributes(attributes)) = inst.properties.get("Attributes") { + if let Some(DomValue::Attributes(attributes)) = + inst.properties.get(PROPERTY_NAME_ATTRIBUTES) + { attributes.clone().into_iter().collect() } else { BTreeMap::new() @@ -507,8 +516,17 @@ impl Instance { let inst = dom .get_by_ref_mut(self.dom_ref) .expect("Failed to find instance in document"); - if let Some(DomValue::Attributes(attributes)) = inst.properties.get_mut("Attributes") { + if let Some(DomValue::Attributes(attributes)) = + inst.properties.get_mut(PROPERTY_NAME_ATTRIBUTES) + { attributes.insert(name.as_ref().to_string(), value); + } else { + let mut attributes = DomAttributes::new(); + attributes.insert(name.as_ref().to_string(), value); + inst.properties.insert( + PROPERTY_NAME_ATTRIBUTES.to_string(), + DomValue::Attributes(attributes), + ); } } @@ -526,11 +544,11 @@ impl Instance { let inst = dom .get_by_ref_mut(self.dom_ref) .expect("Failed to find instance in document"); - if let Some(DomValue::Tags(tags)) = inst.properties.get_mut("Tags") { + if let Some(DomValue::Tags(tags)) = inst.properties.get_mut(PROPERTY_NAME_TAGS) { tags.push(name.as_ref()); } else { inst.properties.insert( - "Tags".to_string(), + PROPERTY_NAME_TAGS.to_string(), DomValue::Tags(vec![name.as_ref().to_string()].into()), ); } @@ -550,7 +568,7 @@ impl Instance { let inst = dom .get_by_ref(self.dom_ref) .expect("Failed to find instance in document"); - if let Some(DomValue::Tags(tags)) = inst.properties.get("Tags") { + if let Some(DomValue::Tags(tags)) = inst.properties.get(PROPERTY_NAME_TAGS) { tags.iter().map(ToString::to_string).collect() } else { Vec::new() @@ -571,7 +589,7 @@ impl Instance { let inst = dom .get_by_ref(self.dom_ref) .expect("Failed to find instance in document"); - if let Some(DomValue::Tags(tags)) = inst.properties.get("Tags") { + if let Some(DomValue::Tags(tags)) = inst.properties.get(PROPERTY_NAME_TAGS) { let name = name.as_ref(); tags.iter().any(|tag| tag == name) } else { @@ -593,12 +611,14 @@ impl Instance { let inst = dom .get_by_ref_mut(self.dom_ref) .expect("Failed to find instance in document"); - if let Some(DomValue::Tags(tags)) = inst.properties.get_mut("Tags") { + if let Some(DomValue::Tags(tags)) = inst.properties.get_mut(PROPERTY_NAME_TAGS) { let name = name.as_ref(); let mut new_tags = tags.iter().map(ToString::to_string).collect::>(); new_tags.retain(|tag| tag != name); - inst.properties - .insert("Tags".to_string(), DomValue::Tags(new_tags.into())); + inst.properties.insert( + PROPERTY_NAME_TAGS.to_string(), + DomValue::Tags(new_tags.into()), + ); } } diff --git a/tests/roblox/instance/attributes.luau b/tests/roblox/instance/attributes.luau index 0796e20..926bb34 100644 --- a/tests/roblox/instance/attributes.luau +++ b/tests/roblox/instance/attributes.luau @@ -88,6 +88,12 @@ for name, value in ATTRS_EXPECTED do end end +-- Setting attributes on a new empty instance should work + +local folder = Instance.new("Folder") +folder:SetAttribute("Foo", "Bar") +assert(folder:GetAttribute("Foo") == "Bar") + -- Writing files with modified attributes should work local game = Instance.new("DataModel")