diff --git a/DataTypes/NumberSequenceKeypoint.cs b/DataTypes/NumberSequenceKeypoint.cs index acc5b57..04f0620 100644 --- a/DataTypes/NumberSequenceKeypoint.cs +++ b/DataTypes/NumberSequenceKeypoint.cs @@ -18,13 +18,6 @@ Envelope = envelope; } - internal NumberSequenceKeypoint(Attribute attr) - { - Envelope = attr.ReadFloat(); - Time = attr.ReadFloat(); - Value = attr.ReadFloat(); - } - public override int GetHashCode() { int hash = Time.GetHashCode() diff --git a/DataTypes/PhysicalProperties.cs b/DataTypes/PhysicalProperties.cs index 1225ae1..ecf5889 100644 --- a/DataTypes/PhysicalProperties.cs +++ b/DataTypes/PhysicalProperties.cs @@ -37,16 +37,6 @@ namespace RobloxFiles.DataTypes ElasticityWeight = elasticityWeight; } - internal PhysicalProperties(Attribute attr) - { - Density = attr.ReadFloat(); - Friction = attr.ReadFloat(); - Elasticity = attr.ReadFloat(); - - FrictionWeight = attr.ReadFloat(); - ElasticityWeight = attr.ReadFloat(); - } - public override int GetHashCode() { int hash = Density.GetHashCode() diff --git a/DataTypes/Region3int16.cs b/DataTypes/Region3int16.cs index 198ca75..d2d1964 100644 --- a/DataTypes/Region3int16.cs +++ b/DataTypes/Region3int16.cs @@ -11,12 +11,6 @@ Max = max ?? new Vector3int16(); } - internal Region3int16(Attribute attr) - { - Min = new Vector3int16(attr); - Max = new Vector3int16(attr); - } - public override int GetHashCode() { int hash = Min.GetHashCode() diff --git a/DataTypes/Vector2int16.cs b/DataTypes/Vector2int16.cs index 23eb9a4..f24134f 100644 --- a/DataTypes/Vector2int16.cs +++ b/DataTypes/Vector2int16.cs @@ -19,12 +19,6 @@ namespace RobloxFiles.DataTypes Y = (short)y; } - internal Vector2int16(Attribute attr) - { - X = attr.ReadShort(); - Y = attr.ReadShort(); - } - private delegate Vector2int16 Operator(Vector2int16 a, Vector2int16 b); private static Vector2int16 upcastShortOp(Vector2int16 vec, short num, Operator upcast) diff --git a/DataTypes/Vector3int16.cs b/DataTypes/Vector3int16.cs index 1851956..9bb978f 100644 --- a/DataTypes/Vector3int16.cs +++ b/DataTypes/Vector3int16.cs @@ -25,13 +25,6 @@ namespace RobloxFiles.DataTypes Z = (short)z; } - internal Vector3int16(Attribute attr) - { - X = attr.ReadShort(); - Y = attr.ReadShort(); - Z = attr.ReadShort(); - } - private delegate Vector3int16 Operator(Vector3int16 a, Vector3int16 b); private static Vector3int16 upcastShortOp(Vector3int16 vec, short num, Operator upcast) diff --git a/Interfaces/IAttributeToken.cs b/Interfaces/IAttributeToken.cs index 3956ac5..00e7999 100644 --- a/Interfaces/IAttributeToken.cs +++ b/Interfaces/IAttributeToken.cs @@ -4,7 +4,7 @@ { AttributeType AttributeType { get; } - T ReadAttribute(Attribute attribute); - void WriteAttribute(Attribute attribute, T value); + T ReadAttribute(RbxAttribute attribute); + void WriteAttribute(RbxAttribute attribute, T value); } } diff --git a/RobloxFileFormat.dll b/RobloxFileFormat.dll index d2a8680..bf7ab8d 100644 Binary files a/RobloxFileFormat.dll and b/RobloxFileFormat.dll differ diff --git a/Tokens/Boolean.cs b/Tokens/Boolean.cs index 36b5456..5fe8b4a 100644 --- a/Tokens/Boolean.cs +++ b/Tokens/Boolean.cs @@ -8,8 +8,8 @@ namespace RobloxFiles.Tokens public string XmlPropertyToken => "bool"; public AttributeType AttributeType => AttributeType.Bool; - public bool ReadAttribute(Attribute attr) => attr.ReadBool(); - public void WriteAttribute(Attribute attr, bool value) => attr.WriteBool(value); + public bool ReadAttribute(RbxAttribute attr) => attr.ReadBool(); + public void WriteAttribute(RbxAttribute attr, bool value) => attr.WriteBool(value); public bool ReadProperty(Property prop, XmlNode token) { diff --git a/Tokens/BrickColor.cs b/Tokens/BrickColor.cs index 1c91428..6099d9b 100644 --- a/Tokens/BrickColor.cs +++ b/Tokens/BrickColor.cs @@ -12,8 +12,8 @@ namespace RobloxFiles.Tokens public string XmlPropertyToken => "BrickColor"; public AttributeType AttributeType => AttributeType.BrickColor; - public BrickColor ReadAttribute(Attribute attr) => attr.ReadInt(); - public void WriteAttribute(Attribute attr, BrickColor value) => attr.WriteInt(value.Number); + public BrickColor ReadAttribute(RbxAttribute attr) => attr.ReadInt(); + public void WriteAttribute(RbxAttribute attr, BrickColor value) => attr.WriteInt(value.Number); public bool ReadProperty(Property prop, XmlNode token) { diff --git a/Tokens/Color3.cs b/Tokens/Color3.cs index 6a18b9a..ecba62e 100644 --- a/Tokens/Color3.cs +++ b/Tokens/Color3.cs @@ -10,10 +10,10 @@ namespace RobloxFiles.Tokens private readonly string[] XmlFields = new string[3] { "R", "G", "B" }; public AttributeType AttributeType => AttributeType.Color3; - public Color3 ReadAttribute(Attribute attr) => ReadColor3(attr); - public void WriteAttribute(Attribute attr, Color3 value) => WriteColor3(attr, value); + public Color3 ReadAttribute(RbxAttribute attr) => ReadColor3(attr); + public void WriteAttribute(RbxAttribute attr, Color3 value) => WriteColor3(attr, value); - public static Color3 ReadColor3(Attribute attr) + public static Color3 ReadColor3(RbxAttribute attr) { float r = attr.ReadFloat(), g = attr.ReadFloat(), @@ -22,7 +22,7 @@ namespace RobloxFiles.Tokens return new Color3(r, g, b); } - public static void WriteColor3(Attribute attr, Color3 value) + public static void WriteColor3(RbxAttribute attr, Color3 value) { attr.WriteFloat(value.R); attr.WriteFloat(value.G); diff --git a/Tokens/ColorSequence.cs b/Tokens/ColorSequence.cs index 3c0475c..a96a6e6 100644 --- a/Tokens/ColorSequence.cs +++ b/Tokens/ColorSequence.cs @@ -52,7 +52,7 @@ namespace RobloxFiles.Tokens node.InnerText = value.ToString() + ' '; } - public ColorSequence ReadAttribute(Attribute attr) + public ColorSequence ReadAttribute(RbxAttribute attr) { int numKeys = attr.ReadInt(); var keypoints = new ColorSequenceKeypoint[numKeys]; @@ -69,7 +69,7 @@ namespace RobloxFiles.Tokens return new ColorSequence(keypoints); } - public void WriteAttribute(Attribute attr, ColorSequence value) + public void WriteAttribute(RbxAttribute attr, ColorSequence value) { attr.WriteInt(value.Keypoints.Length); diff --git a/Tokens/Double.cs b/Tokens/Double.cs index c4c88e3..73ea91f 100644 --- a/Tokens/Double.cs +++ b/Tokens/Double.cs @@ -8,8 +8,8 @@ namespace RobloxFiles.Tokens public string XmlPropertyToken => "double"; public AttributeType AttributeType => AttributeType.Double; - public double ReadAttribute(Attribute attr) => attr.ReadDouble(); - public void WriteAttribute(Attribute attr, double value) => attr.WriteDouble(value); + public double ReadAttribute(RbxAttribute attr) => attr.ReadDouble(); + public void WriteAttribute(RbxAttribute attr, double value) => attr.WriteDouble(value); public bool ReadProperty(Property prop, XmlNode token) { diff --git a/Tokens/Float.cs b/Tokens/Float.cs index b41994c..2821f47 100644 --- a/Tokens/Float.cs +++ b/Tokens/Float.cs @@ -8,8 +8,8 @@ namespace RobloxFiles.Tokens public string XmlPropertyToken => "float"; public AttributeType AttributeType => AttributeType.Float; - public float ReadAttribute(Attribute attr) => attr.ReadFloat(); - public void WriteAttribute(Attribute attr, float value) => attr.WriteFloat(value); + public float ReadAttribute(RbxAttribute attr) => attr.ReadFloat(); + public void WriteAttribute(RbxAttribute attr, float value) => attr.WriteFloat(value); public bool ReadProperty(Property prop, XmlNode token) { diff --git a/Tokens/NumberRange.cs b/Tokens/NumberRange.cs index a7951e1..cd1d780 100644 --- a/Tokens/NumberRange.cs +++ b/Tokens/NumberRange.cs @@ -40,7 +40,7 @@ namespace RobloxFiles.Tokens node.InnerText = value.ToString() + ' '; } - public NumberRange ReadAttribute(Attribute attr) + public NumberRange ReadAttribute(RbxAttribute attr) { float min = attr.ReadFloat(); float max = attr.ReadFloat(); @@ -48,7 +48,7 @@ namespace RobloxFiles.Tokens return new NumberRange(min, max); } - public void WriteAttribute(Attribute attr, NumberRange value) + public void WriteAttribute(RbxAttribute attr, NumberRange value) { attr.WriteFloat(value.Min); attr.WriteFloat(value.Max); diff --git a/Tokens/NumberSequence.cs b/Tokens/NumberSequence.cs index 3fd3eba..01c5ff9 100644 --- a/Tokens/NumberSequence.cs +++ b/Tokens/NumberSequence.cs @@ -49,7 +49,7 @@ namespace RobloxFiles.Tokens node.InnerText = value.ToString() + ' '; } - public NumberSequence ReadAttribute(Attribute attr) + public NumberSequence ReadAttribute(RbxAttribute attr) { int numKeys = attr.ReadInt(); var keypoints = new NumberSequenceKeypoint[numKeys]; @@ -66,7 +66,7 @@ namespace RobloxFiles.Tokens return new NumberSequence(keypoints); } - public void WriteAttribute(Attribute attr, NumberSequence value) + public void WriteAttribute(RbxAttribute attr, NumberSequence value) { attr.WriteInt(value.Keypoints.Length); diff --git a/Tokens/Rect.cs b/Tokens/Rect.cs index 2af4868..635cd3b 100644 --- a/Tokens/Rect.cs +++ b/Tokens/Rect.cs @@ -51,7 +51,7 @@ namespace RobloxFiles.Tokens node.AppendChild(max); } - public Rect ReadAttribute(Attribute attr) + public Rect ReadAttribute(RbxAttribute attr) { Vector2 min = Vector2Token.ReadVector2(attr); Vector2 max = Vector2Token.ReadVector2(attr); @@ -59,7 +59,7 @@ namespace RobloxFiles.Tokens return new Rect(min, max); } - public void WriteAttribute(Attribute attr, Rect value) + public void WriteAttribute(RbxAttribute attr, Rect value) { Vector2Token.WriteVector2(attr, value.Min); Vector2Token.WriteVector2(attr, value.Max); diff --git a/Tokens/String.cs b/Tokens/String.cs index 82a8c3d..50a510f 100644 --- a/Tokens/String.cs +++ b/Tokens/String.cs @@ -7,8 +7,8 @@ namespace RobloxFiles.Tokens public string XmlPropertyToken => "string"; public AttributeType AttributeType => AttributeType.String; - public string ReadAttribute(Attribute attr) => attr.ReadString(); - public void WriteAttribute(Attribute attr, string value) => attr.WriteString(value); + public string ReadAttribute(RbxAttribute attr) => attr.ReadString(); + public void WriteAttribute(RbxAttribute attr, string value) => attr.WriteString(value); public bool ReadProperty(Property prop, XmlNode token) { diff --git a/Tokens/UDim.cs b/Tokens/UDim.cs index e56f35f..9b80c1c 100644 --- a/Tokens/UDim.cs +++ b/Tokens/UDim.cs @@ -9,8 +9,8 @@ namespace RobloxFiles.Tokens public string XmlPropertyToken => "UDim"; public AttributeType AttributeType => AttributeType.UDim; - public UDim ReadAttribute(Attribute attr) => ReadUDim(attr); - public void WriteAttribute(Attribute attr, UDim value) => WriteUDim(attr, value); + public UDim ReadAttribute(RbxAttribute attr) => ReadUDim(attr); + public void WriteAttribute(RbxAttribute attr, UDim value) => WriteUDim(attr, value); public static UDim ReadUDim(XmlNode token, string prefix = "") { @@ -41,7 +41,7 @@ namespace RobloxFiles.Tokens node.AppendChild(offset); } - public static UDim ReadUDim(Attribute attr) + public static UDim ReadUDim(RbxAttribute attr) { float scale = attr.ReadFloat(); int offset = attr.ReadInt(); @@ -49,7 +49,7 @@ namespace RobloxFiles.Tokens return new UDim(scale, offset); } - public static void WriteUDim(Attribute attr, UDim value) + public static void WriteUDim(RbxAttribute attr, UDim value) { float scale = value.Scale; attr.WriteFloat(scale); diff --git a/Tokens/UDim2.cs b/Tokens/UDim2.cs index 7f350fc..27fe6a8 100644 --- a/Tokens/UDim2.cs +++ b/Tokens/UDim2.cs @@ -8,7 +8,7 @@ namespace RobloxFiles.Tokens public string XmlPropertyToken => "UDim2"; public AttributeType AttributeType => AttributeType.UDim2; - public UDim2 ReadAttribute(Attribute attr) + public UDim2 ReadAttribute(RbxAttribute attr) { UDim x = UDimToken.ReadUDim(attr); UDim y = UDimToken.ReadUDim(attr); @@ -16,7 +16,7 @@ namespace RobloxFiles.Tokens return new UDim2(x, y); } - public void WriteAttribute(Attribute attr, UDim2 value) + public void WriteAttribute(RbxAttribute attr, UDim2 value) { UDimToken.WriteUDim(attr, value.X); UDimToken.WriteUDim(attr, value.Y); diff --git a/Tokens/Vector2.cs b/Tokens/Vector2.cs index 572a679..ffd389b 100644 --- a/Tokens/Vector2.cs +++ b/Tokens/Vector2.cs @@ -9,8 +9,8 @@ namespace RobloxFiles.Tokens private static readonly string[] XmlCoords = new string[2] { "X", "Y" }; public AttributeType AttributeType => AttributeType.Vector2; - public Vector2 ReadAttribute(Attribute attr) => ReadVector2(attr); - public void WriteAttribute(Attribute attr, Vector2 value) => WriteVector2(attr, value); + public Vector2 ReadAttribute(RbxAttribute attr) => ReadVector2(attr); + public void WriteAttribute(RbxAttribute attr, Vector2 value) => WriteVector2(attr, value); public static Vector2 ReadVector2(XmlNode token) { @@ -46,7 +46,7 @@ namespace RobloxFiles.Tokens node.AppendChild(y); } - public static Vector2 ReadVector2(Attribute attr) + public static Vector2 ReadVector2(RbxAttribute attr) { float x = attr.ReadFloat(), y = attr.ReadFloat(); @@ -54,7 +54,7 @@ namespace RobloxFiles.Tokens return new Vector2(x, y); } - public static void WriteVector2(Attribute attr, Vector2 value) + public static void WriteVector2(RbxAttribute attr, Vector2 value) { attr.WriteFloat(value.X); attr.WriteFloat(value.Y); diff --git a/Tokens/Vector3.cs b/Tokens/Vector3.cs index c3f179a..591b5e4 100644 --- a/Tokens/Vector3.cs +++ b/Tokens/Vector3.cs @@ -9,8 +9,8 @@ namespace RobloxFiles.Tokens private static readonly string[] XmlCoords = new string[3] { "X", "Y", "Z" }; public AttributeType AttributeType => AttributeType.Vector3; - public Vector3 ReadAttribute(Attribute attr) => ReadVector3(attr); - public void WriteAttribute(Attribute attr, Vector3 value) => WriteVector3(attr, value); + public Vector3 ReadAttribute(RbxAttribute attr) => ReadVector3(attr); + public void WriteAttribute(RbxAttribute attr, Vector3 value) => WriteVector3(attr, value); public static Vector3 ReadVector3(XmlNode token) { @@ -49,7 +49,7 @@ namespace RobloxFiles.Tokens node.AppendChild(z); } - public static Vector3 ReadVector3(Attribute attr) + public static Vector3 ReadVector3(RbxAttribute attr) { float x = attr.ReadFloat(), y = attr.ReadFloat(), @@ -58,7 +58,7 @@ namespace RobloxFiles.Tokens return new Vector3(x, y, z); } - public static void WriteVector3(Attribute attr, Vector3 value) + public static void WriteVector3(RbxAttribute attr, Vector3 value) { attr.WriteFloat(value.X); attr.WriteFloat(value.Y); diff --git a/Tree/Attributes.cs b/Tree/Attributes.cs index 380c065..2da020d 100644 --- a/Tree/Attributes.cs +++ b/Tree/Attributes.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.Serialization; using System.Text; namespace RobloxFiles @@ -45,7 +46,7 @@ namespace RobloxFiles // Region3int16 = 32 } - public class Attribute : IDisposable + public class RbxAttribute : IDisposable { private static readonly IReadOnlyDictionary AttributeSupport; private static readonly IReadOnlyDictionary SupportedTypes; @@ -70,20 +71,20 @@ namespace RobloxFiles Writer = support.GetMethod("WriteAttribute"); } - public object ReadAttribute(Attribute attr) + public object ReadAttribute(RbxAttribute attr) { var args = new object[1] { attr }; return Reader.Invoke(Token, args); } - public void WriteAttribute(Attribute attr, object value) + public void WriteAttribute(RbxAttribute attr, object value) { var args = new object[2] { attr, value }; Writer.Invoke(Token, args); } } - static Attribute() + static RbxAttribute() { var attributeSupport = new Dictionary(); var supportedTypes = new Dictionary(); @@ -193,19 +194,19 @@ namespace RobloxFiles Writer = null; } - internal Attribute(BinaryReader reader) + internal RbxAttribute(BinaryReader reader) { Reader = reader; Read(); } - internal Attribute(MemoryStream stream) + internal RbxAttribute(MemoryStream stream) { Reader = new BinaryReader(stream); Read(); } - internal Attribute(object value) + internal RbxAttribute(object value) { Type type = value.GetType(); @@ -217,44 +218,31 @@ namespace RobloxFiles } } - public class Attributes : SortedDictionary + public class RbxAttributes : SortedDictionary { - private void Initialize(BinaryReader reader) + internal void Load(byte[] buffer) { - Stream stream = reader.BaseStream; + Clear(); - if (stream.Length - stream.Position < 4) + if (buffer == null || buffer.Length < 4) // Not enough room to read the entry count, possibly empty? return; - int numEntries = reader.ReadInt32(); - - for (int i = 0; i < numEntries; i++) + using (var input = new MemoryStream(buffer)) + using (var reader = new BinaryReader(input)) { - string key = reader.ReadString(true); - var attribute = new Attribute(reader); - Add(key, attribute); + int numEntries = reader.ReadInt32(); + + for (int i = 0; i < numEntries; i++) + { + string key = reader.ReadString(true); + var attribute = new RbxAttribute(reader); + Add(key, attribute); + } } } - public Attributes() : base() - { - } - - internal Attributes(BinaryReader reader) - { - Initialize(reader); - } - - internal Attributes(MemoryStream stream) - { - using (var reader = new BinaryReader(stream)) - Initialize(reader); - - stream.Dispose(); - } - - internal byte[] Serialize() + internal byte[] Save() { if (Count == 0) return Array.Empty(); diff --git a/Tree/Instance.cs b/Tree/Instance.cs index 401289b..cd3ed77 100644 --- a/Tree/Instance.cs +++ b/Tree/Instance.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.IO; using System.Linq; using System.Reflection; using System.Text; @@ -61,26 +59,16 @@ namespace RobloxFiles public bool Destroyed { get; internal set; } /// A hashset of CollectionService tags assigned to this Instance. - public HashSet Tags { get; } = new HashSet(); + public readonly HashSet Tags = new HashSet(); - /// The attributes defined for this Instance. - private Attributes AttributesImpl = new Attributes(); - /// The public readonly access point of the attributes on this Instance. - public IReadOnlyDictionary Attributes => AttributesImpl; + public readonly RbxAttributes Attributes = new RbxAttributes(); /// The internal serialized data of this Instance's attributes internal byte[] AttributesSerialize { - get - { - return AttributesImpl?.Serialize() ?? Array.Empty(); - } - set - { - var data = new MemoryStream(value); - AttributesImpl = new Attributes(data); - } + get => Attributes.Save(); + set => Attributes.Load(value); } /// @@ -134,7 +122,7 @@ namespace RobloxFiles /// True if the attribute could be read and the out value was set, false otherwise. public bool GetAttribute(string key, out T value) { - if (AttributesImpl.TryGetValue(key, out Attribute attr)) + if (Attributes.TryGetValue(key, out RbxAttribute attr)) { if (attr.Value is T result) { @@ -161,13 +149,16 @@ namespace RobloxFiles if (key.Length > 100) return false; - Type type = value.GetType(); - - if (!Attribute.SupportsType(type)) + if (key.StartsWith("RBX", StringComparison.InvariantCulture)) return false; - var attr = new Attribute(value); - AttributesImpl[key] = attr; + Type type = value.GetType(); + + if (!RbxAttribute.SupportsType(type)) + return false; + + var attr = new RbxAttribute(value); + Attributes[key] = attr; return true; } @@ -474,8 +465,8 @@ namespace RobloxFiles Parent = null; ParentLocked = true; - Tags?.Clear(); - AttributesImpl?.Clear(); + Tags.Clear(); + Attributes.Clear(); while (Children.Any()) {