General Misc Patches

This commit is contained in:
CloneTrooper1019 2020-08-17 20:12:24 -05:00
parent 297426bdb5
commit f4899b4ce6
18 changed files with 267 additions and 47 deletions

View File

@ -29,8 +29,8 @@ namespace RobloxFiles.BinaryFormat.Chunks
byte[] data = reader.ReadBuffer(); byte[] data = reader.ReadBuffer();
SharedString value = SharedString.FromBuffer(data); SharedString value = SharedString.FromBuffer(data);
Lookup.Add(key, id); Lookup[key] = id;
Strings.Add(id, value); Strings[id] = value;
} }
file.SSTR = this; file.SSTR = this;

View File

@ -170,6 +170,25 @@ namespace RobloxFiles.DataTypes
} }
} }
public override bool Equals(object obj)
{
if (obj is CFrame)
{
CFrame other = obj as CFrame;
float[] a = GetComponents();
float[] b = other.GetComponents();
for (int i = 0; i < 12; i++)
if (!a[i].FuzzyEquals(b[i]))
return false;
return true;
}
return base.Equals(obj);
}
public static CFrame operator +(CFrame a, Vector3 b) public static CFrame operator +(CFrame a, Vector3 b)
{ {
float[] ac = a.GetComponents(); float[] ac = a.GetComponents();

View File

@ -14,6 +14,15 @@ namespace RobloxFiles.DataTypes
B = b; B = b;
} }
public override int GetHashCode()
{
int r = R.GetHashCode(),
g = G.GetHashCode(),
b = B.GetHashCode();
return (r ^ g ^ b);
}
internal Color3(Attribute attr) internal Color3(Attribute attr)
{ {
R = attr.readFloat(); R = attr.readFloat();

View File

@ -16,6 +16,11 @@
B = b; B = b;
} }
public override int GetHashCode()
{
return (R << 24) | (G << 8) | B;
}
public static implicit operator Color3(Color3uint8 color) public static implicit operator Color3(Color3uint8 color)
{ {
float r = color.R / 255f; float r = color.R / 255f;

View File

@ -21,10 +21,11 @@ namespace RobloxFiles.DataTypes
public ColorSequence(Color3 c0, Color3 c1) public ColorSequence(Color3 c0, Color3 c1)
{ {
ColorSequenceKeypoint a = new ColorSequenceKeypoint(0, c0); Keypoints = new ColorSequenceKeypoint[2]
ColorSequenceKeypoint b = new ColorSequenceKeypoint(1, c1); {
new ColorSequenceKeypoint(0, c0),
Keypoints = new ColorSequenceKeypoint[2] { a, b }; new ColorSequenceKeypoint(1, c1)
};
} }
public ColorSequence(ColorSequenceKeypoint[] keypoints) public ColorSequence(ColorSequenceKeypoint[] keypoints)

View File

@ -3,12 +3,13 @@
public class ColorSequenceKeypoint public class ColorSequenceKeypoint
{ {
public readonly float Time; public readonly float Time;
public readonly Color3 Value; public readonly Color3uint8 Value;
public readonly int Envelope; public readonly int Envelope;
public override string ToString() public override string ToString()
{ {
return $"{Time} {Value.R} {Value.G} {Value.B} {Envelope}"; Color3 Color = Value;
return $"{Time} {Color.R} {Color.G} {Color.B} {Envelope}";
} }
public ColorSequenceKeypoint(float time, Color3 value, int envelope = 0) public ColorSequenceKeypoint(float time, Color3 value, int envelope = 0)

View File

@ -59,7 +59,7 @@ namespace RobloxFiles.DataTypes
public static SharedString FromBuffer(byte[] buffer) public static SharedString FromBuffer(byte[] buffer)
{ {
return new SharedString(buffer); return new SharedString(buffer ?? Array.Empty<byte>());
} }
public static SharedString FromString(string value) public static SharedString FromString(string value)

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Text;
using RobloxFiles.Enums; using RobloxFiles.Enums;
namespace RobloxFiles.DataTypes namespace RobloxFiles.DataTypes
@ -65,6 +66,36 @@ namespace RobloxFiles.DataTypes
return new Vector3(coords); return new Vector3(coords);
} }
public override bool Equals(object obj)
{
if (obj is Vector3)
{
Vector3 other = obj as Vector3;
if (!X.FuzzyEquals(other.X))
return false;
if (!Y.FuzzyEquals(other.Y))
return false;
if (!Z.FuzzyEquals(other.Z))
return false;
return true;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
int x = X.GetHashCode(),
y = Y.GetHashCode(),
z = Z.GetHashCode();
return x ^ y ^ z;
}
private delegate Vector3 Operator(Vector3 a, Vector3 b); private delegate Vector3 Operator(Vector3 a, Vector3 b);
private static Vector3 upcastFloatOp(Vector3 vec, float num, Operator upcast) private static Vector3 upcastFloatOp(Vector3 vec, float num, Operator upcast)

View File

@ -2251,7 +2251,9 @@ namespace RobloxFiles
{ {
public ModelLevelOfDetail LevelOfDetail = ModelLevelOfDetail.Automatic; public ModelLevelOfDetail LevelOfDetail = ModelLevelOfDetail.Automatic;
public CFrame ModelInPrimary = new CFrame(); public CFrame ModelInPrimary = new CFrame();
public CFrame ModelMeshCFrame = new CFrame();
public byte[] ModelMeshData = Array.Empty<byte>(); public byte[] ModelMeshData = Array.Empty<byte>();
public Vector3 ModelMeshSize = new Vector3();
public BasePart PrimaryPart; public BasePart PrimaryPart;
} }

View File

@ -121,6 +121,7 @@
<Compile Include="DataTypes\UDim2.cs" /> <Compile Include="DataTypes\UDim2.cs" />
<Compile Include="DataTypes\Vector2.cs" /> <Compile Include="DataTypes\Vector2.cs" />
<Compile Include="DataTypes\Vector3.cs" /> <Compile Include="DataTypes\Vector3.cs" />
<Compile Include="Utility\DefaultProperty.cs" />
<Compile Include="Utility\Formatting.cs" /> <Compile Include="Utility\Formatting.cs" />
<Compile Include="Utility\FontUtility.cs" /> <Compile Include="Utility\FontUtility.cs" />
<Compile Include="Utility\ImplicitMember.cs" /> <Compile Include="Utility\ImplicitMember.cs" />

Binary file not shown.

View File

@ -530,11 +530,44 @@ namespace RobloxFiles
if (fieldName.EndsWith("_")) if (fieldName.EndsWith("_"))
fieldName = instType.Name; fieldName = instType.Name;
string xmlToken = fieldType.Name;
if (fieldType.IsEnum)
xmlToken = "token";
switch (xmlToken)
{
case "String":
case "Double":
xmlToken = xmlToken.ToLowerInvariant();
break;
case "Boolean":
xmlToken = "bool";
break;
case "Single":
xmlToken = "float";
break;
case "Int32":
xmlToken = "int";
break;
case "Int64":
xmlToken = "int64";
break;
case "Rect":
xmlToken = "Rect2D";
break;
case "CFrame":
xmlToken = "CoordinateFrame";
break;
default: break;
}
if (!props.ContainsKey(fieldName)) if (!props.ContainsKey(fieldName))
{ {
Property newProp = new Property() Property newProp = new Property()
{ {
Value = field.GetValue(this), Value = field.GetValue(this),
XmlToken = xmlToken,
Name = fieldName, Name = fieldName,
Type = propType, Type = propType,
Instance = this Instance = this
@ -546,6 +579,7 @@ namespace RobloxFiles
{ {
Property prop = props[fieldName]; Property prop = props[fieldName];
prop.Value = field.GetValue(this); prop.Value = field.GetValue(this);
prop.XmlToken = xmlToken;
prop.Type = propType; prop.Type = propType;
} }
} }

View File

@ -100,35 +100,45 @@ namespace RobloxFiles
private void ImproviseRawBuffer() private void ImproviseRawBuffer()
{ {
if (RawValue is SharedString) if (RawValue is byte[])
{
var sharedString = CastValue<SharedString>();
RawBuffer = sharedString.SharedValue;
return;
}
else if (RawValue is ProtectedString)
{
var protectedString = CastValue<ProtectedString>();
RawBuffer = protectedString.RawBuffer;
return;
}
else if (RawValue is byte[])
{ {
RawBuffer = RawValue as byte[]; RawBuffer = RawValue as byte[];
return; return;
} }
if (RawValue is SharedString)
{
var sharedString = CastValue<SharedString>();
if (sharedString != null)
{
RawBuffer = sharedString.SharedValue;
return;
}
}
if (RawValue is ProtectedString)
{
var protectedString = CastValue<ProtectedString>();
if (protectedString != null)
{
RawBuffer = protectedString.RawBuffer;
return;
}
}
switch (Type) switch (Type)
{ {
case PropertyType.Int: case PropertyType.Int:
RawBuffer = BitConverter.GetBytes((int)Value); RawBuffer = BitConverter.GetBytes((int)Value);
break; break;
case PropertyType.Int64:
RawBuffer = BitConverter.GetBytes((long)Value);
break;
case PropertyType.Bool: case PropertyType.Bool:
RawBuffer = BitConverter.GetBytes((bool)Value); RawBuffer = BitConverter.GetBytes((bool)Value);
break; break;
case PropertyType.Int64:
RawBuffer = BitConverter.GetBytes((long)Value);
break;
case PropertyType.Float: case PropertyType.Float:
RawBuffer = BitConverter.GetBytes((float)Value); RawBuffer = BitConverter.GetBytes((float)Value);
break; break;

View File

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace RobloxFiles.Utility
{
static class DefaultProperty
{
private static Dictionary<string, Instance> ClassMap;
private static HashSet<Instance> Refreshed = new HashSet<Instance>();
static DefaultProperty()
{
var Instance = typeof(Instance);
var assembly = Assembly.GetExecutingAssembly();
var classes = assembly.GetTypes()
.Where(type => !type.IsAbstract && Instance.IsAssignableFrom(type))
.Select(type => Activator.CreateInstance(type))
.Cast<Instance>();
ClassMap = classes.ToDictionary(inst => inst.ClassName);
}
public static object Get(string className, string propName)
{
if (!ClassMap.ContainsKey(className))
return null;
Instance inst = ClassMap[className];
if (!Refreshed.Contains(inst))
{
inst.RefreshProperties();
Refreshed.Add(inst);
}
var props = inst.Properties;
if (!props.ContainsKey(propName))
return null;
var prop = props[propName];
return prop.Value;
}
public static object Get(Instance inst, string propName)
{
return Get(inst.ClassName, propName);
}
public static object Get(Instance inst, Property prop)
{
return Get(inst.ClassName, prop.Name);
}
public static object Get(string className, Property prop)
{
return Get(className, prop.Name);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Text;
using System.Xml; using System.Xml;
using RobloxFiles.DataTypes; using RobloxFiles.DataTypes;
using RobloxFiles.Utility;
using RobloxFiles.XmlFormat.PropertyTokens; using RobloxFiles.XmlFormat.PropertyTokens;
namespace RobloxFiles.XmlFormat namespace RobloxFiles.XmlFormat
@ -41,12 +42,11 @@ namespace RobloxFiles.XmlFormat
internal static void RecordInstances(XmlRobloxFile file, Instance inst) internal static void RecordInstances(XmlRobloxFile file, Instance inst)
{ {
inst.Referent = "RBX" + file.RefCounter++;
foreach (Instance child in inst.GetChildren()) foreach (Instance child in inst.GetChildren())
RecordInstances(file, child); RecordInstances(file, child);
if (inst.Referent == null || inst.Referent.Length < 35)
inst.Referent = CreateReferent();
file.Instances.Add(inst.Referent, inst); file.Instances.Add(inst.Referent, inst);
} }
@ -100,15 +100,21 @@ namespace RobloxFiles.XmlFormat
if (prop.Type == PropertyType.SharedString) if (prop.Type == PropertyType.SharedString)
{ {
SharedString value = prop.CastValue<SharedString>(); SharedString str = prop.CastValue<SharedString>();
if (value.ComputedKey == null) if (str == null)
{ {
var newShared = SharedString.FromBuffer(value.SharedValue); byte[] value = prop.CastValue<byte[]>();
value.Key = newShared.ComputedKey; str = SharedString.FromBuffer(value);
} }
file.SharedStrings.Add(value.Key); if (str.ComputedKey == null)
{
var newShared = SharedString.FromBuffer(str.SharedValue);
str.Key = newShared.ComputedKey;
}
file.SharedStrings.Add(str.Key);
} }
XmlElement propElement = doc.CreateElement(propType); XmlElement propElement = doc.CreateElement(propType);
@ -148,12 +154,43 @@ namespace RobloxFiles.XmlFormat
foreach (string propName in orderedKeys) foreach (string propName in orderedKeys)
{ {
Property prop = props[propName]; Property prop = props[propName];
XmlNode propNode = WriteProperty(prop, doc, file); bool isDefault = false;
if (propNode == null) object a = DefaultProperty.Get(instance, prop);
continue; object b = prop.Value;
propsNode.AppendChild(propNode); if (a is float)
{
float f0 = (float)a,
f1 = (float)b;
isDefault = f0.FuzzyEquals(f1);
}
else if (a is double)
{
double d0 = (double)a,
d1 = (double)b;
isDefault = d0.FuzzyEquals(d1);
}
else if (b != null)
{
isDefault = b.Equals(a);
}
else if (a == b)
{
isDefault = true;
}
if (!isDefault)
{
XmlNode propNode = WriteProperty(prop, doc, file);
if (propNode == null)
continue;
propsNode.AppendChild(propNode);
}
} }
foreach (Instance child in instance.GetChildren()) foreach (Instance child in instance.GetChildren())

View File

@ -18,16 +18,20 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node) public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
{ {
var value = prop.CastValue<SharedString>(); var value = prop.Value as SharedString;
string key = value.Key;
if (value.ComputedKey == null) if (value != null)
{ {
var newShared = SharedString.FromBuffer(value.SharedValue); string key = value.Key;
key = newShared.ComputedKey;
}
node.InnerText = key; if (value.ComputedKey == null)
{
var newShared = SharedString.FromBuffer(value.SharedValue);
key = newShared.ComputedKey;
}
node.InnerText = key;
}
} }
} }
} }

View File

@ -20,6 +20,7 @@ namespace RobloxFiles
private Dictionary<string, string> RawMetadata = new Dictionary<string, string>(); private Dictionary<string, string> RawMetadata = new Dictionary<string, string>();
public Dictionary<string, string> Metadata => RawMetadata; public Dictionary<string, string> Metadata => RawMetadata;
internal int RefCounter = 0;
public XmlRobloxFile() public XmlRobloxFile()
{ {
@ -126,6 +127,7 @@ namespace RobloxFiles
roblox.SetAttribute("version", "4"); roblox.SetAttribute("version", "4");
doc.AppendChild(roblox); doc.AppendChild(roblox);
RefCounter = 0;
Instances.Clear(); Instances.Clear();
SharedStrings.Clear(); SharedStrings.Clear();

View File

@ -4,5 +4,6 @@
<package id="Fody" version="6.2.0" targetFramework="net472" developmentDependency="true" /> <package id="Fody" version="6.2.0" targetFramework="net472" developmentDependency="true" />
<package id="Konscious.Security.Cryptography.Blake2" version="1.0.9" targetFramework="net472" /> <package id="Konscious.Security.Cryptography.Blake2" version="1.0.9" targetFramework="net472" />
<package id="lz4net" version="1.0.15.93" targetFramework="net452" /> <package id="lz4net" version="1.0.15.93" targetFramework="net452" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" /> <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
</packages> </packages>