diff --git a/BinaryFormat/Chunks/PROP.cs b/BinaryFormat/Chunks/PROP.cs index 8108ce2..e622502 100644 --- a/BinaryFormat/Chunks/PROP.cs +++ b/BinaryFormat/Chunks/PROP.cs @@ -6,6 +6,7 @@ using System.Text; using RobloxFiles.Enums; using RobloxFiles.DataTypes; +using System.Diagnostics; namespace RobloxFiles.BinaryFormat.Chunks { @@ -571,7 +572,6 @@ namespace RobloxFiles.BinaryFormat.Chunks else if (prop.Type != Type) throw new Exception($"Property {Name} is not using the correct type in {instance.GetFullName()}!"); - prop.CurrentWriter = writer; props.Add(prop); } @@ -628,7 +628,12 @@ namespace RobloxFiles.BinaryFormat.Chunks writer.WriteFloats(floats); break; case PropertyType.Double: - props.ForEach(prop => prop.WriteValue()); + props.ForEach(prop => + { + double value = prop.CastValue(); + writer.Write(BinaryRobloxFileWriter.GetBytes(value)); + }); + break; case PropertyType.UDim: var UDim_Scales = new List(); @@ -689,7 +694,12 @@ namespace RobloxFiles.BinaryFormat.Chunks break; case PropertyType.Faces: case PropertyType.Axes: - props.ForEach(prop => prop.WriteValue()); + props.ForEach(prop => + { + byte value = prop.CastValue(); + writer.Write(value); + }); + break; case PropertyType.BrickColor: var BrickColorIds = new List(); @@ -1003,6 +1013,13 @@ namespace RobloxFiles.BinaryFormat.Chunks props.ForEach(prop => { var shared = prop.CastValue(); + + if (shared == null) + { + byte[] empty = Array.Empty(); + shared = SharedString.FromBuffer(empty); + } + string key = shared.Key; if (!sstr.Lookup.ContainsKey(key)) diff --git a/DataTypes/SharedString.cs b/DataTypes/SharedString.cs index 0550d2c..760ae8b 100644 --- a/DataTypes/SharedString.cs +++ b/DataTypes/SharedString.cs @@ -1,6 +1,7 @@ using System; using System.Text; using System.Collections.Generic; +using System.Collections.Concurrent; using Konscious.Security.Cryptography; namespace RobloxFiles.DataTypes @@ -15,7 +16,7 @@ namespace RobloxFiles.DataTypes public class SharedString { - private static Dictionary Lookup = new Dictionary(); + private static ConcurrentDictionary Lookup = new ConcurrentDictionary(); public string Key { get; internal set; } public string ComputedKey { get; internal set; } @@ -29,12 +30,15 @@ namespace RobloxFiles.DataTypes internal static void Register(string key, byte[] buffer) { - Lookup.Add(key, buffer); + if (Lookup.ContainsKey(key)) + return; + + Lookup.TryAdd(key, buffer); } private SharedString(byte[] buffer) { - using (HMACBlake2B blake2B = new HMACBlake2B(16 * 8)) + using (var blake2B = new HMACBlake2B(16 * 8)) { byte[] hash = blake2B.ComputeHash(buffer); ComputedKey = Convert.ToBase64String(hash); diff --git a/Generated/Classes.cs b/Generated/Classes.cs index 4b7345d..c8c1229 100644 --- a/Generated/Classes.cs +++ b/Generated/Classes.cs @@ -2252,7 +2252,7 @@ namespace RobloxFiles public ModelLevelOfDetail LevelOfDetail = ModelLevelOfDetail.Automatic; public CFrame ModelInPrimary = new CFrame(); public CFrame ModelMeshCFrame = new CFrame(); - public byte[] ModelMeshData = Array.Empty(); + public SharedString ModelMeshData; public Vector3 ModelMeshSize = new Vector3(); public BasePart PrimaryPart; } diff --git a/RobloxFile.cs b/RobloxFile.cs index 852cd09..cbb0bdc 100644 --- a/RobloxFile.cs +++ b/RobloxFile.cs @@ -42,6 +42,7 @@ namespace RobloxFiles } } + string lead = Encoding.UTF8.GetString(buffer, 0, 100); throw new Exception("Unrecognized header!"); } diff --git a/RobloxFileFormat.csproj b/RobloxFileFormat.csproj index 333feb3..b3211ca 100644 --- a/RobloxFileFormat.csproj +++ b/RobloxFileFormat.csproj @@ -48,6 +48,7 @@ prompt 1 MinimumRecommendedRules.ruleset + x64 diff --git a/RobloxFileFormat.dll b/RobloxFileFormat.dll index b625642..f0c6bad 100644 Binary files a/RobloxFileFormat.dll and b/RobloxFileFormat.dll differ diff --git a/Tree/Property.cs b/Tree/Property.cs index a3b54fe..3e6ffb7 100644 --- a/Tree/Property.cs +++ b/Tree/Property.cs @@ -56,11 +56,9 @@ namespace RobloxFiles public byte[] RawBuffer { get; internal set; } internal object RawValue; - internal BinaryRobloxFileWriter CurrentWriter; internal static BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase; - internal static MemberTypes FieldOrProperty = MemberTypes.Field | MemberTypes.Property; - + // !! FIXME: Map typeof(ProtectedString) to PropertyType.ProtectedString when binary files are allowed to read it. public static readonly IReadOnlyDictionary Types = new Dictionary() { @@ -329,16 +327,5 @@ namespace RobloxFiles return (T)result; } - - internal void WriteValue() where T : struct - { - if (CurrentWriter == null) - throw new Exception("Property.CurrentWriter must be set to use WriteValue"); - - T value = CastValue(); - byte[] bytes = BinaryRobloxFileWriter.GetBytes(value); - - CurrentWriter.Write(bytes); - } } } \ No newline at end of file