Add support for Attributes!
This commit is contained in:
parent
81d901cbcd
commit
83dd0af8d2
@ -6,9 +6,11 @@ namespace RobloxFiles.DataTypes
|
||||
{
|
||||
public class CFrame
|
||||
{
|
||||
private float m11 = 1, m12, m13, m14;
|
||||
private float m21, m22 = 1, m23, m24;
|
||||
private float m31, m32, m33 = 1, m34;
|
||||
private float m14, m24, m34;
|
||||
|
||||
private readonly float m11 = 1, m12, m13;
|
||||
private readonly float m21, m22 = 1, m23;
|
||||
private readonly float m31, m32, m33 = 1;
|
||||
|
||||
private const float m41 = 0, m42 = 0, m43 = 0, m44 = 1;
|
||||
|
||||
@ -160,49 +162,17 @@ namespace RobloxFiles.DataTypes
|
||||
m31 = comp[9]; m32 = comp[10]; m33 = comp[11];
|
||||
}
|
||||
|
||||
private void InitFromMatrix(Vector3 pos, Vector3 vX, Vector3 vY, Vector3 vZ = null)
|
||||
public CFrame(Vector3 pos, Vector3 vX, Vector3 vY, Vector3 vZ = null)
|
||||
{
|
||||
Contract.Requires(pos != null && vX != null && vY != null);
|
||||
|
||||
if (vZ == null)
|
||||
vZ = vX.Cross(vY);
|
||||
|
||||
m14 = pos.X; m24 = pos.Y; m34 = pos.Z;
|
||||
m11 = vX.X; m12 = vX.Y; m13 = vX.Z;
|
||||
m21 = vY.X; m22 = vY.Y; m23 = vY.Z;
|
||||
m31 = vZ.X; m32 = vZ.Y; m33 = vZ.Z;
|
||||
}
|
||||
|
||||
public CFrame(Vector3 pos, Vector3 vX, Vector3 vY, Vector3 vZ = null)
|
||||
{
|
||||
Contract.Requires(pos != null && vX != null && vY != null);
|
||||
InitFromMatrix(pos, vX, vY, vZ);
|
||||
}
|
||||
|
||||
internal CFrame(Attribute attr)
|
||||
{
|
||||
Vector3 pos = new Vector3(attr);
|
||||
byte rawOrientId = attr.ReadByte();
|
||||
|
||||
if (rawOrientId > 0)
|
||||
{
|
||||
// Make sure this value is in a safe range.
|
||||
int orientId = (rawOrientId - 1) % 36;
|
||||
|
||||
NormalId xColumn = (NormalId)(orientId / 6);
|
||||
Vector3 vX = Vector3.FromNormalId(xColumn);
|
||||
|
||||
NormalId yColumn = (NormalId)(orientId % 6);
|
||||
Vector3 vY = Vector3.FromNormalId(yColumn);
|
||||
|
||||
InitFromMatrix(pos, vX, vY);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 vX = new Vector3(attr),
|
||||
vY = new Vector3(attr),
|
||||
vZ = new Vector3(attr);
|
||||
|
||||
InitFromMatrix(pos, vX, vY, vZ);
|
||||
}
|
||||
m11 = vX.X; m12 = vX.Y; m13 = vX.Z;
|
||||
m21 = vY.X; m22 = vY.Y; m23 = vY.Z;
|
||||
m31 = vZ.X; m32 = vZ.Y; m33 = vZ.Z;
|
||||
}
|
||||
|
||||
public static CFrame operator +(CFrame a, Vector3 b)
|
||||
|
@ -40,13 +40,6 @@ namespace RobloxFiles.DataTypes
|
||||
return true;
|
||||
}
|
||||
|
||||
internal Color3(Attribute attr)
|
||||
{
|
||||
R = attr.ReadFloat();
|
||||
G = attr.ReadFloat();
|
||||
B = attr.ReadFloat();
|
||||
}
|
||||
|
||||
public static Color3 FromRGB(uint r = 0, uint g = 0, uint b = 0)
|
||||
{
|
||||
return new Color3(r / 255f, g / 255f, b / 255f);
|
||||
|
@ -86,16 +86,5 @@ namespace RobloxFiles.DataTypes
|
||||
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
|
||||
public ColorSequence(Attribute attr)
|
||||
{
|
||||
int numKeys = attr.ReadInt();
|
||||
var keypoints = new ColorSequenceKeypoint[numKeys];
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
keypoints[i] = new ColorSequenceKeypoint(attr);
|
||||
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,6 @@
|
||||
Envelope = envelope;
|
||||
}
|
||||
|
||||
internal ColorSequenceKeypoint(Attribute attr)
|
||||
{
|
||||
Envelope = attr.ReadInt();
|
||||
Time = attr.ReadFloat();
|
||||
Value = new Color3(attr);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = Time.GetHashCode()
|
||||
|
@ -25,10 +25,6 @@ namespace RobloxFiles.DataTypes
|
||||
Max = max;
|
||||
}
|
||||
|
||||
internal NumberRange(Attribute attr) : this(attr.ReadFloat(), attr.ReadFloat())
|
||||
{
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Min.GetHashCode() ^ Max.GetHashCode();
|
||||
|
@ -52,17 +52,6 @@ namespace RobloxFiles.DataTypes
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
|
||||
public NumberSequence(Attribute attr)
|
||||
{
|
||||
int numKeys = attr.ReadInt();
|
||||
var keypoints = new NumberSequenceKeypoint[numKeys];
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
keypoints[i] = new NumberSequenceKeypoint(attr);
|
||||
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 0;
|
||||
|
@ -28,12 +28,6 @@
|
||||
Direction = direction ?? new Vector3();
|
||||
}
|
||||
|
||||
internal Ray(Attribute attr)
|
||||
{
|
||||
Origin = new Vector3(attr);
|
||||
Direction = new Vector3(attr);
|
||||
}
|
||||
|
||||
public Vector3 ClosestPoint(Vector3 point)
|
||||
{
|
||||
Vector3 result = Origin;
|
||||
|
@ -22,12 +22,6 @@
|
||||
Max = new Vector2(maxX, maxY);
|
||||
}
|
||||
|
||||
internal Rect(Attribute attr)
|
||||
{
|
||||
Min = new Vector2(attr);
|
||||
Max = new Vector2(attr);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = Min.GetHashCode()
|
||||
|
@ -17,12 +17,6 @@ namespace RobloxFiles.DataTypes
|
||||
Max = max;
|
||||
}
|
||||
|
||||
internal Region3(Attribute attr)
|
||||
{
|
||||
Min = new Vector3(attr);
|
||||
Max = new Vector3(attr);
|
||||
}
|
||||
|
||||
public Region3 ExpandToGrid(float resolution)
|
||||
{
|
||||
Vector3 emin = new Vector3
|
||||
|
@ -13,12 +13,6 @@
|
||||
Offset = offset;
|
||||
}
|
||||
|
||||
internal UDim(Attribute attr)
|
||||
{
|
||||
Scale = attr.ReadFloat();
|
||||
Offset = attr.ReadInt();
|
||||
}
|
||||
|
||||
public static UDim operator+(UDim a, UDim b)
|
||||
{
|
||||
return new UDim(a.Scale + b.Scale, a.Offset + b.Offset);
|
||||
|
@ -20,12 +20,6 @@
|
||||
Y = y;
|
||||
}
|
||||
|
||||
internal UDim2(Attribute attr)
|
||||
{
|
||||
X = new UDim(attr);
|
||||
Y = new UDim(attr);
|
||||
}
|
||||
|
||||
public UDim2 Lerp(UDim2 other, float alpha)
|
||||
{
|
||||
float scaleX = X.Scale + ((other.X.Scale - X.Scale) * alpha);
|
||||
|
@ -29,27 +29,21 @@ namespace RobloxFiles.DataTypes
|
||||
Y = y;
|
||||
}
|
||||
|
||||
internal Vector2(float[] coords)
|
||||
public Vector2(params float[] coords)
|
||||
{
|
||||
X = coords.Length > 0 ? coords[0] : 0;
|
||||
Y = coords.Length > 1 ? coords[1] : 0;
|
||||
}
|
||||
|
||||
internal Vector2(Attribute attr)
|
||||
{
|
||||
X = attr.ReadFloat();
|
||||
Y = attr.ReadFloat();
|
||||
}
|
||||
|
||||
private delegate Vector2 Operator(Vector2 a, Vector2 b);
|
||||
|
||||
private static Vector2 upcastFloatOp(Vector2 vec, float num, Operator upcast)
|
||||
private static Vector2 UpcastFloatOp(Vector2 vec, float num, Operator upcast)
|
||||
{
|
||||
Vector2 numVec = new Vector2(num, num);
|
||||
return upcast(vec, numVec);
|
||||
}
|
||||
|
||||
private static Vector2 upcastFloatOp(float num, Vector2 vec, Operator upcast)
|
||||
private static Vector2 UpcastFloatOp(float num, Vector2 vec, Operator upcast)
|
||||
{
|
||||
Vector2 numVec = new Vector2(num, num);
|
||||
return upcast(numVec, vec);
|
||||
@ -61,20 +55,20 @@ namespace RobloxFiles.DataTypes
|
||||
private static readonly Operator div = new Operator((a, b) => new Vector2(a.X / b.X, a.Y / b.Y));
|
||||
|
||||
public static Vector2 operator +(Vector2 a, Vector2 b) => add(a, b);
|
||||
public static Vector2 operator +(Vector2 v, float n) => upcastFloatOp(v, n, add);
|
||||
public static Vector2 operator +(float n, Vector2 v) => upcastFloatOp(n, v, add);
|
||||
public static Vector2 operator +(Vector2 v, float n) => UpcastFloatOp(v, n, add);
|
||||
public static Vector2 operator +(float n, Vector2 v) => UpcastFloatOp(n, v, add);
|
||||
|
||||
public static Vector2 operator -(Vector2 a, Vector2 b) => sub(a, b);
|
||||
public static Vector2 operator -(Vector2 v, float n) => upcastFloatOp(v, n, sub);
|
||||
public static Vector2 operator -(float n, Vector2 v) => upcastFloatOp(n, v, sub);
|
||||
public static Vector2 operator -(Vector2 v, float n) => UpcastFloatOp(v, n, sub);
|
||||
public static Vector2 operator -(float n, Vector2 v) => UpcastFloatOp(n, v, sub);
|
||||
|
||||
public static Vector2 operator *(Vector2 a, Vector2 b) => mul(a, b);
|
||||
public static Vector2 operator *(Vector2 v, float n) => upcastFloatOp(v, n, mul);
|
||||
public static Vector2 operator *(float n, Vector2 v) => upcastFloatOp(n, v, mul);
|
||||
public static Vector2 operator *(Vector2 v, float n) => UpcastFloatOp(v, n, mul);
|
||||
public static Vector2 operator *(float n, Vector2 v) => UpcastFloatOp(n, v, mul);
|
||||
|
||||
public static Vector2 operator /(Vector2 a, Vector2 b) => div(a, b);
|
||||
public static Vector2 operator /(Vector2 v, float n) => upcastFloatOp(v, n, div);
|
||||
public static Vector2 operator /(float n, Vector2 v) => upcastFloatOp(n, v, div);
|
||||
public static Vector2 operator /(Vector2 v, float n) => UpcastFloatOp(v, n, div);
|
||||
public static Vector2 operator /(float n, Vector2 v) => UpcastFloatOp(n, v, div);
|
||||
|
||||
public static Vector2 operator -(Vector2 v)
|
||||
{
|
||||
|
@ -32,20 +32,13 @@ namespace RobloxFiles.DataTypes
|
||||
Z = z;
|
||||
}
|
||||
|
||||
public Vector3(float[] coords)
|
||||
public Vector3(params float[] coords)
|
||||
{
|
||||
X = coords.Length > 0 ? coords[0] : 0;
|
||||
Y = coords.Length > 1 ? coords[1] : 0;
|
||||
Z = coords.Length > 2 ? coords[2] : 0;
|
||||
}
|
||||
|
||||
internal Vector3(Attribute attr)
|
||||
{
|
||||
X = attr.ReadFloat();
|
||||
Y = attr.ReadFloat();
|
||||
Z = attr.ReadFloat();
|
||||
}
|
||||
|
||||
public static Vector3 FromAxis(Axis axis)
|
||||
{
|
||||
float[] coords = new float[3] { 0f, 0f, 0f };
|
||||
@ -68,13 +61,13 @@ namespace RobloxFiles.DataTypes
|
||||
|
||||
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)
|
||||
{
|
||||
Vector3 numVec = new Vector3(num, num, num);
|
||||
return upcast(vec, numVec);
|
||||
}
|
||||
|
||||
private static Vector3 upcastFloatOp(float num, Vector3 vec, Operator upcast)
|
||||
private static Vector3 UpcastFloatOp(float num, Vector3 vec, Operator upcast)
|
||||
{
|
||||
Vector3 numVec = new Vector3(num, num, num);
|
||||
return upcast(numVec, vec);
|
||||
@ -86,30 +79,30 @@ namespace RobloxFiles.DataTypes
|
||||
private static readonly Operator div = new Operator((a, b) => new Vector3(a.X / b.X, a.Y / b.Y, a.Z / b.Z));
|
||||
|
||||
public static Vector3 operator +(Vector3 a, Vector3 b) => add(a, b);
|
||||
public static Vector3 operator +(Vector3 v, float n) => upcastFloatOp(v, n, add);
|
||||
public static Vector3 operator +(float n, Vector3 v) => upcastFloatOp(n, v, add);
|
||||
public static Vector3 operator +(Vector3 v, float n) => UpcastFloatOp(v, n, add);
|
||||
public static Vector3 operator +(float n, Vector3 v) => UpcastFloatOp(n, v, add);
|
||||
|
||||
public static Vector3 operator -(Vector3 a, Vector3 b) => sub(a, b);
|
||||
public static Vector3 operator -(Vector3 v, float n) => upcastFloatOp(v, n, sub);
|
||||
public static Vector3 operator -(float n, Vector3 v) => upcastFloatOp(n, v, sub);
|
||||
public static Vector3 operator -(Vector3 v, float n) => UpcastFloatOp(v, n, sub);
|
||||
public static Vector3 operator -(float n, Vector3 v) => UpcastFloatOp(n, v, sub);
|
||||
|
||||
public static Vector3 operator *(Vector3 a, Vector3 b) => mul(a, b);
|
||||
public static Vector3 operator *(Vector3 v, float n) => upcastFloatOp(v, n, mul);
|
||||
public static Vector3 operator *(float n, Vector3 v) => upcastFloatOp(n, v, mul);
|
||||
public static Vector3 operator *(Vector3 v, float n) => UpcastFloatOp(v, n, mul);
|
||||
public static Vector3 operator *(float n, Vector3 v) => UpcastFloatOp(n, v, mul);
|
||||
|
||||
public static Vector3 operator /(Vector3 a, Vector3 b) => div(a, b);
|
||||
public static Vector3 operator /(Vector3 v, float n) => upcastFloatOp(v, n, div);
|
||||
public static Vector3 operator /(float n, Vector3 v) => upcastFloatOp(n, v, div);
|
||||
public static Vector3 operator /(Vector3 v, float n) => UpcastFloatOp(v, n, div);
|
||||
public static Vector3 operator /(float n, Vector3 v) => UpcastFloatOp(n, v, div);
|
||||
|
||||
public static Vector3 operator -(Vector3 v)
|
||||
{
|
||||
return new Vector3(-v.X, -v.Y, -v.Z);
|
||||
}
|
||||
|
||||
public static Vector3 Zero => new Vector3(0, 0, 0);
|
||||
public static Vector3 Right => new Vector3(1, 0, 0);
|
||||
public static Vector3 Up => new Vector3(0, 1, 0);
|
||||
public static Vector3 Back => new Vector3(0, 0, 1);
|
||||
public static readonly Vector3 Zero = new Vector3(0, 0, 0);
|
||||
public static readonly Vector3 Right = new Vector3(1, 0, 0);
|
||||
public static readonly Vector3 Up = new Vector3(0, 1, 0);
|
||||
public static readonly Vector3 Back = new Vector3(0, 0, 1);
|
||||
|
||||
public float Dot(Vector3 other)
|
||||
{
|
||||
|
10
Interfaces/IAttributeToken.cs
Normal file
10
Interfaces/IAttributeToken.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace RobloxFiles
|
||||
{
|
||||
public interface IAttributeToken<T>
|
||||
{
|
||||
AttributeType AttributeType { get; }
|
||||
|
||||
T ReadAttribute(Attribute attribute);
|
||||
void WriteAttribute(Attribute attribute, T value);
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
using System.Xml;
|
||||
|
||||
namespace RobloxFiles.XmlFormat
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public interface IXmlPropertyToken
|
||||
{
|
||||
string Token { get; }
|
||||
string XmlPropertyToken { get; }
|
||||
|
||||
bool ReadProperty(Property prop, XmlNode token);
|
||||
void WriteProperty(Property prop, XmlDocument doc, XmlNode node);
|
||||
|
@ -97,6 +97,7 @@
|
||||
<Compile Include="Interfaces\IBinaryFileChunk.cs" />
|
||||
<Compile Include="Generated\Classes.cs" />
|
||||
<Compile Include="Generated\Enums.cs" />
|
||||
<Compile Include="Interfaces\IAttributeToken.cs" />
|
||||
<Compile Include="Tree\Attributes.cs" />
|
||||
<Compile Include="Tree\Property.cs" />
|
||||
<Compile Include="Tree\Instance.cs" />
|
||||
@ -130,39 +131,39 @@
|
||||
<Compile Include="Utility\MaterialInfo.cs" />
|
||||
<Compile Include="DataTypes\Quaternion.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\SharedString.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\ProtectedString.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Vector3int16.cs" />
|
||||
<Compile Include="XmlFormat\IO\XmlFileWriter.cs" />
|
||||
<Compile Include="Tokens\SharedString.cs" />
|
||||
<Compile Include="Tokens\ProtectedString.cs" />
|
||||
<Compile Include="Tokens\Vector3int16.cs" />
|
||||
<Compile Include="XmlFormat\XmlFileWriter.cs" />
|
||||
<Compile Include="XmlFormat\XmlPropertyTokens.cs" />
|
||||
<Compile Include="XmlFormat\IO\XmlFileReader.cs" />
|
||||
<Compile Include="XmlFormat\XmlFileReader.cs" />
|
||||
<Compile Include="XmlFormat\XmlRobloxFile.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Axes.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\BinaryString.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Boolean.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\BrickColor.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\CFrame.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Content.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Color3.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Color3uint8.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\ColorSequence.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Double.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Enum.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Faces.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Float.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Int.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Int64.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\NumberRange.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\NumberSequence.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\PhysicalProperties.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Ray.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Rect.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Ref.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\String.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\UDim.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\UDim2.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Vector2.cs" />
|
||||
<Compile Include="XmlFormat\Tokens\Vector3.cs" />
|
||||
<Compile Include="Tokens\Axes.cs" />
|
||||
<Compile Include="Tokens\BinaryString.cs" />
|
||||
<Compile Include="Tokens\Boolean.cs" />
|
||||
<Compile Include="Tokens\BrickColor.cs" />
|
||||
<Compile Include="Tokens\CFrame.cs" />
|
||||
<Compile Include="Tokens\Content.cs" />
|
||||
<Compile Include="Tokens\Color3.cs" />
|
||||
<Compile Include="Tokens\Color3uint8.cs" />
|
||||
<Compile Include="Tokens\ColorSequence.cs" />
|
||||
<Compile Include="Tokens\Double.cs" />
|
||||
<Compile Include="Tokens\Enum.cs" />
|
||||
<Compile Include="Tokens\Faces.cs" />
|
||||
<Compile Include="Tokens\Float.cs" />
|
||||
<Compile Include="Tokens\Int.cs" />
|
||||
<Compile Include="Tokens\Int64.cs" />
|
||||
<Compile Include="Tokens\NumberRange.cs" />
|
||||
<Compile Include="Tokens\NumberSequence.cs" />
|
||||
<Compile Include="Tokens\PhysicalProperties.cs" />
|
||||
<Compile Include="Tokens\Ray.cs" />
|
||||
<Compile Include="Tokens\Rect.cs" />
|
||||
<Compile Include="Tokens\Ref.cs" />
|
||||
<Compile Include="Tokens\String.cs" />
|
||||
<Compile Include="Tokens\UDim.cs" />
|
||||
<Compile Include="Tokens\UDim2.cs" />
|
||||
<Compile Include="Tokens\Vector2.cs" />
|
||||
<Compile Include="Tokens\Vector3.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
|
||||
|
Binary file not shown.
@ -1,11 +1,13 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class AxesToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "Axes";
|
||||
public string XmlPropertyToken => "Axes";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class BinaryStringToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "BinaryString";
|
||||
public string XmlPropertyToken => "BinaryString";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,10 +1,15 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class BoolToken : IXmlPropertyToken
|
||||
public class BoolToken : IXmlPropertyToken, IAttributeToken<bool>
|
||||
{
|
||||
public string Token => "bool";
|
||||
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 ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,16 +1,20 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class BrickColorToken : IXmlPropertyToken
|
||||
public class BrickColorToken : IXmlPropertyToken, IAttributeToken<BrickColor>
|
||||
{
|
||||
public string Token => "BrickColor";
|
||||
// ^ This is a lie: The token is actually int, but that would cause a name collision.
|
||||
// Since BrickColors are written as ints, the IntToken class will try to redirect
|
||||
// to this handler if it believes that its representing a BrickColor.
|
||||
// This is a lie: The token is actually int, but that would cause a name collision.
|
||||
// Since BrickColors are written as ints, the IntToken class will try to redirect
|
||||
// to this handler if it believes that its representing a BrickColor.
|
||||
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 bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
if (XmlPropertyTokens.ReadPropertyGeneric(token, out int value))
|
@ -1,12 +1,12 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class CFrameToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "CoordinateFrame; CFrame";
|
||||
private static string[] Coords = new string[12] { "X", "Y", "Z", "R00", "R01", "R02", "R10", "R11", "R12", "R20", "R21", "R22"};
|
||||
public string XmlPropertyToken => "CoordinateFrame; CFrame";
|
||||
private static readonly string[] Coords = new string[12] { "X", "Y", "Z", "R00", "R01", "R02", "R10", "R11", "R12", "R20", "R21", "R22"};
|
||||
|
||||
public static CFrame ReadCFrame(XmlNode token)
|
||||
{
|
@ -1,22 +1,42 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class Color3Token : IXmlPropertyToken
|
||||
public class Color3Token : IXmlPropertyToken, IAttributeToken<Color3>
|
||||
{
|
||||
public string Token => "Color3";
|
||||
private readonly string[] Fields = new string[3] { "R", "G", "B" };
|
||||
public string XmlPropertyToken => "Color3";
|
||||
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 static Color3 ReadColor3(Attribute attr)
|
||||
{
|
||||
float r = attr.ReadFloat(),
|
||||
g = attr.ReadFloat(),
|
||||
b = attr.ReadFloat();
|
||||
|
||||
return new Color3(r, g, b);
|
||||
}
|
||||
|
||||
public static void WriteColor3(Attribute attr, Color3 value)
|
||||
{
|
||||
attr.WriteFloat(value.R);
|
||||
attr.WriteFloat(value.G);
|
||||
attr.WriteFloat(value.B);
|
||||
}
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
bool success = true;
|
||||
float[] fields = new float[Fields.Length];
|
||||
float[] fields = new float[XmlFields.Length];
|
||||
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
string key = Fields[i];
|
||||
string key = XmlFields[i];
|
||||
|
||||
try
|
||||
{
|
||||
@ -64,7 +84,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
string field = Fields[i];
|
||||
string field = XmlFields[i];
|
||||
float value = rgb[i];
|
||||
|
||||
XmlElement channel = doc.CreateElement(field);
|
@ -1,13 +1,13 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.XmlFormat;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class Color3uint8Token : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "Color3uint8";
|
||||
public string XmlPropertyToken => "Color3uint8";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,11 +1,12 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class ColorSequenceToken : IXmlPropertyToken
|
||||
public class ColorSequenceToken : IXmlPropertyToken, IAttributeToken<ColorSequence>
|
||||
{
|
||||
public string Token => "ColorSequence";
|
||||
public string XmlPropertyToken => "ColorSequence";
|
||||
public AttributeType AttributeType => AttributeType.ColorSequence;
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
@ -19,7 +20,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
{
|
||||
try
|
||||
{
|
||||
ColorSequenceKeypoint[] keypoints = new ColorSequenceKeypoint[length / 5];
|
||||
var keypoints = new ColorSequenceKeypoint[length / 5];
|
||||
|
||||
for (int i = 0; i < length; i += 5)
|
||||
{
|
||||
@ -50,5 +51,35 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
ColorSequence value = prop.CastValue<ColorSequence>();
|
||||
node.InnerText = value.ToString() + ' ';
|
||||
}
|
||||
|
||||
public ColorSequence ReadAttribute(Attribute attr)
|
||||
{
|
||||
int numKeys = attr.ReadInt();
|
||||
var keypoints = new ColorSequenceKeypoint[numKeys];
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
{
|
||||
int envelope = attr.ReadInt();
|
||||
float time = attr.ReadFloat();
|
||||
|
||||
Color3 value = Color3Token.ReadColor3(attr);
|
||||
keypoints[i] = new ColorSequenceKeypoint(time, value, envelope);
|
||||
}
|
||||
|
||||
return new ColorSequence(keypoints);
|
||||
}
|
||||
|
||||
public void WriteAttribute(Attribute attr, ColorSequence value)
|
||||
{
|
||||
attr.WriteInt(value.Keypoints.Length);
|
||||
|
||||
foreach (var keypoint in value.Keypoints)
|
||||
{
|
||||
attr.WriteInt(keypoint.Envelope);
|
||||
attr.WriteFloat(keypoint.Time);
|
||||
|
||||
Color3Token.WriteColor3(attr, keypoint.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,11 +3,11 @@ using System.Xml;
|
||||
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class ContentToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "Content";
|
||||
public string XmlPropertyToken => "Content";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,10 +1,15 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class DoubleToken : IXmlPropertyToken
|
||||
public class DoubleToken : IXmlPropertyToken, IAttributeToken<double>
|
||||
{
|
||||
public string Token => "double";
|
||||
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 bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -3,11 +3,13 @@ using System.Diagnostics.Contracts;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class EnumToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "token";
|
||||
public string XmlPropertyToken => "token";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,12 +1,14 @@
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class FacesToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "Faces";
|
||||
public string XmlPropertyToken => "Faces";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,10 +1,15 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class FloatToken : IXmlPropertyToken
|
||||
public class FloatToken : IXmlPropertyToken, IAttributeToken<float>
|
||||
{
|
||||
public string Token => "float";
|
||||
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 bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,10 +1,11 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class IntToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "int";
|
||||
public string XmlPropertyToken => "int";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,10 +1,11 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class Int64Token : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "int64";
|
||||
public string XmlPropertyToken => "int64";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -2,11 +2,12 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class NumberRangeToken : IXmlPropertyToken
|
||||
public class NumberRangeToken : IXmlPropertyToken, IAttributeToken<NumberRange>
|
||||
{
|
||||
public string Token => "NumberRange";
|
||||
public string XmlPropertyToken => "NumberRange";
|
||||
public AttributeType AttributeType => AttributeType.NumberRange;
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
@ -38,5 +39,19 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
NumberRange value = prop.CastValue<NumberRange>();
|
||||
node.InnerText = value.ToString() + ' ';
|
||||
}
|
||||
|
||||
public NumberRange ReadAttribute(Attribute attr)
|
||||
{
|
||||
float min = attr.ReadFloat();
|
||||
float max = attr.ReadFloat();
|
||||
|
||||
return new NumberRange(min, max);
|
||||
}
|
||||
|
||||
public void WriteAttribute(Attribute attr, NumberRange value)
|
||||
{
|
||||
attr.WriteFloat(value.Min);
|
||||
attr.WriteFloat(value.Max);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class NumberSequenceToken : IXmlPropertyToken
|
||||
public class NumberSequenceToken : IXmlPropertyToken, IAttributeToken<NumberSequence>
|
||||
{
|
||||
public string Token => "NumberSequence";
|
||||
public string XmlPropertyToken => "NumberSequence";
|
||||
public AttributeType AttributeType => AttributeType.NumberSequence;
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
@ -47,5 +48,34 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
NumberSequence value = prop.CastValue<NumberSequence>();
|
||||
node.InnerText = value.ToString() + ' ';
|
||||
}
|
||||
|
||||
public NumberSequence ReadAttribute(Attribute attr)
|
||||
{
|
||||
int numKeys = attr.ReadInt();
|
||||
var keypoints = new NumberSequenceKeypoint[numKeys];
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
{
|
||||
float envelope = attr.ReadInt(),
|
||||
time = attr.ReadFloat(),
|
||||
value = attr.ReadFloat();
|
||||
|
||||
keypoints[i] = new NumberSequenceKeypoint(time, value, envelope);
|
||||
}
|
||||
|
||||
return new NumberSequence(keypoints);
|
||||
}
|
||||
|
||||
public void WriteAttribute(Attribute attr, NumberSequence value)
|
||||
{
|
||||
attr.WriteInt(value.Keypoints.Length);
|
||||
|
||||
foreach (var keypoint in value.Keypoints)
|
||||
{
|
||||
attr.WriteFloat(keypoint.Envelope);
|
||||
attr.WriteFloat(keypoint.Time);
|
||||
attr.WriteFloat(keypoint.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class PhysicalPropertiesToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "PhysicalProperties";
|
||||
public string XmlPropertyToken => "PhysicalProperties";
|
||||
|
||||
private Func<string, T> createReader<T>(Func<string, T> parse, XmlNode token) where T : struct
|
||||
private static Func<string, T> CreateReader<T>(Func<string, T> parse, XmlNode token) where T : struct
|
||||
{
|
||||
return new Func<string, T>(key =>
|
||||
{
|
||||
@ -20,8 +20,8 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
var readBool = createReader(bool.Parse, token);
|
||||
var readFloat = createReader(Formatting.ParseFloat, token);
|
||||
var readBool = CreateReader(bool.Parse, token);
|
||||
var readFloat = CreateReader(Formatting.ParseFloat, token);
|
||||
|
||||
try
|
||||
{
|
@ -1,12 +1,14 @@
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.XmlFormat;
|
||||
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class ProtectedStringToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "ProtectedString";
|
||||
public string XmlPropertyToken => "ProtectedString";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -2,12 +2,12 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class RayToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "Ray";
|
||||
private static string[] Fields = new string[2] { "origin", "direction" };
|
||||
public string XmlPropertyToken => "Ray";
|
||||
private static readonly string[] Fields = new string[2] { "origin", "direction" };
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -2,22 +2,23 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class RectToken : IXmlPropertyToken
|
||||
public class RectToken : IXmlPropertyToken, IAttributeToken<Rect>
|
||||
{
|
||||
public string Token => "Rect2D";
|
||||
private static string[] Fields = new string[2] { "min", "max" };
|
||||
|
||||
public string XmlPropertyToken => "Rect2D";
|
||||
public AttributeType AttributeType => AttributeType.Rect;
|
||||
private static readonly string[] XmlFields = new string[2] { "min", "max" };
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
try
|
||||
{
|
||||
Vector2[] read = new Vector2[Fields.Length];
|
||||
Vector2[] read = new Vector2[XmlFields.Length];
|
||||
|
||||
for (int i = 0; i < read.Length; i++)
|
||||
{
|
||||
string field = Fields[i];
|
||||
string field = XmlFields[i];
|
||||
var fieldToken = token[field];
|
||||
read[i] = Vector2Token.ReadVector2(fieldToken);
|
||||
}
|
||||
@ -49,5 +50,19 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
Vector2Token.WriteVector2(doc, max, rect.Max);
|
||||
node.AppendChild(max);
|
||||
}
|
||||
|
||||
public Rect ReadAttribute(Attribute attr)
|
||||
{
|
||||
Vector2 min = Vector2Token.ReadVector2(attr);
|
||||
Vector2 max = Vector2Token.ReadVector2(attr);
|
||||
|
||||
return new Rect(min, max);
|
||||
}
|
||||
|
||||
public void WriteAttribute(Attribute attr, Rect value)
|
||||
{
|
||||
Vector2Token.WriteVector2(attr, value.Min);
|
||||
Vector2Token.WriteVector2(attr, value.Max);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
using System.Xml;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class RefToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "Ref";
|
||||
public string XmlPropertyToken => "Ref";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -1,11 +1,11 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class SharedStringToken : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "SharedString";
|
||||
public string XmlPropertyToken => "SharedString";
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
@ -18,9 +18,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
|
||||
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||
{
|
||||
var value = prop.Value as SharedString;
|
||||
|
||||
if (value != null)
|
||||
if (prop.Value is SharedString value)
|
||||
{
|
||||
string key = value.Key;
|
||||
|
@ -1,10 +1,14 @@
|
||||
using System.Xml;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class StringToken : IXmlPropertyToken
|
||||
public class StringToken : IXmlPropertyToken, IAttributeToken<string>
|
||||
{
|
||||
public string Token => "string";
|
||||
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 bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
@ -2,12 +2,16 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class UDimToken : IXmlPropertyToken
|
||||
public class UDimToken : IXmlPropertyToken, IAttributeToken<UDim>
|
||||
{
|
||||
public string Token => "UDim";
|
||||
|
||||
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 static UDim ReadUDim(XmlNode token, string prefix = "")
|
||||
{
|
||||
try
|
||||
@ -37,6 +41,23 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
node.AppendChild(offset);
|
||||
}
|
||||
|
||||
public static UDim ReadUDim(Attribute attr)
|
||||
{
|
||||
float scale = attr.ReadFloat();
|
||||
int offset = attr.ReadInt();
|
||||
|
||||
return new UDim(scale, offset);
|
||||
}
|
||||
|
||||
public static void WriteUDim(Attribute attr, UDim value)
|
||||
{
|
||||
float scale = value.Scale;
|
||||
attr.WriteFloat(scale);
|
||||
|
||||
int offset = value.Offset;
|
||||
attr.WriteInt(offset);
|
||||
}
|
||||
|
||||
public bool ReadProperty(Property property, XmlNode token)
|
||||
{
|
||||
UDim result = ReadUDim(token);
|
@ -1,12 +1,26 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class UDim2Token : IXmlPropertyToken
|
||||
public class UDim2Token : IXmlPropertyToken, IAttributeToken<UDim2>
|
||||
{
|
||||
public string Token => "UDim2";
|
||||
public string XmlPropertyToken => "UDim2";
|
||||
public AttributeType AttributeType => AttributeType.UDim2;
|
||||
|
||||
public UDim2 ReadAttribute(Attribute attr)
|
||||
{
|
||||
UDim x = UDimToken.ReadUDim(attr);
|
||||
UDim y = UDimToken.ReadUDim(attr);
|
||||
|
||||
return new UDim2(x, y);
|
||||
}
|
||||
|
||||
public void WriteAttribute(Attribute attr, UDim2 value)
|
||||
{
|
||||
UDimToken.WriteUDim(attr, value.X);
|
||||
UDimToken.WriteUDim(attr, value.Y);
|
||||
}
|
||||
|
||||
public bool ReadProperty(Property property, XmlNode token)
|
||||
{
|
@ -1,12 +1,16 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class Vector2Token : IXmlPropertyToken
|
||||
public class Vector2Token : IXmlPropertyToken, IAttributeToken<Vector2>
|
||||
{
|
||||
public string Token => "Vector2";
|
||||
private static string[] Coords = new string[2] { "X", "Y" };
|
||||
public string XmlPropertyToken => "Vector2";
|
||||
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 static Vector2 ReadVector2(XmlNode token)
|
||||
{
|
||||
@ -14,7 +18,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
string key = Coords[i];
|
||||
string key = XmlCoords[i];
|
||||
|
||||
try
|
||||
{
|
||||
@ -42,6 +46,20 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
node.AppendChild(y);
|
||||
}
|
||||
|
||||
public static Vector2 ReadVector2(Attribute attr)
|
||||
{
|
||||
float x = attr.ReadFloat(),
|
||||
y = attr.ReadFloat();
|
||||
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
public static void WriteVector2(Attribute attr, Vector2 value)
|
||||
{
|
||||
attr.WriteFloat(value.X);
|
||||
attr.WriteFloat(value.Y);
|
||||
}
|
||||
|
||||
public bool ReadProperty(Property property, XmlNode token)
|
||||
{
|
||||
Vector2 result = ReadVector2(token);
|
@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class Vector3Token : IXmlPropertyToken
|
||||
public class Vector3Token : IXmlPropertyToken, IAttributeToken<Vector3>
|
||||
{
|
||||
public string Token => "Vector3";
|
||||
private static string[] Coords = new string[3] { "X", "Y", "Z" };
|
||||
public string XmlPropertyToken => "Vector3";
|
||||
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 static Vector3 ReadVector3(XmlNode token)
|
||||
{
|
||||
@ -15,7 +18,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
string key = Coords[i];
|
||||
string key = XmlCoords[i];
|
||||
|
||||
try
|
||||
{
|
||||
@ -46,6 +49,22 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
node.AppendChild(z);
|
||||
}
|
||||
|
||||
public static Vector3 ReadVector3(Attribute attr)
|
||||
{
|
||||
float x = attr.ReadFloat(),
|
||||
y = attr.ReadFloat(),
|
||||
z = attr.ReadFloat();
|
||||
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public static void WriteVector3(Attribute attr, Vector3 value)
|
||||
{
|
||||
attr.WriteFloat(value.X);
|
||||
attr.WriteFloat(value.Y);
|
||||
attr.WriteFloat(value.Z);
|
||||
}
|
||||
|
||||
public bool ReadProperty(Property property, XmlNode token)
|
||||
{
|
||||
Vector3 result = ReadVector3(token);
|
@ -1,12 +1,12 @@
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
namespace RobloxFiles.Tokens
|
||||
{
|
||||
public class Vector3int16Token : IXmlPropertyToken
|
||||
{
|
||||
public string Token => "Vector3int16";
|
||||
private static string[] Coords = new string[3] { "X", "Y", "Z" };
|
||||
public string XmlPropertyToken => "Vector3int16";
|
||||
private static readonly string[] Coords = new string[3] { "X", "Y", "Z" };
|
||||
|
||||
public bool ReadProperty(Property property, XmlNode token)
|
||||
{
|
@ -2,221 +2,221 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using RobloxFiles.DataTypes;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace RobloxFiles
|
||||
{
|
||||
// This enum defines existing attributes
|
||||
// Commented out values are known types
|
||||
// which are unsupported at this time.
|
||||
|
||||
public enum AttributeType
|
||||
{
|
||||
Null = 1,
|
||||
String,
|
||||
Bool,
|
||||
Int,
|
||||
Float,
|
||||
Double,
|
||||
Array,
|
||||
Dictionary,
|
||||
UDim,
|
||||
UDim2,
|
||||
Ray,
|
||||
Faces,
|
||||
Axes,
|
||||
BrickColor,
|
||||
Color3,
|
||||
Vector2,
|
||||
Vector3,
|
||||
Vector2int16,
|
||||
Vector3int16,
|
||||
CFrame,
|
||||
Enum,
|
||||
// Null = 1,
|
||||
String = 2,
|
||||
Bool = 3,
|
||||
// Int = 4,
|
||||
Float = 5,
|
||||
Double = 6,
|
||||
// Array = 7,
|
||||
// Dictionary = 8,
|
||||
UDim = 9,
|
||||
UDim2 = 10,
|
||||
// Ray = 11,
|
||||
// Faces = 12,
|
||||
// Axes = 13
|
||||
BrickColor = 14,
|
||||
Color3 = 15,
|
||||
Vector2 = 16,
|
||||
Vector3 = 17,
|
||||
// Vector2int16 = 18,
|
||||
// Vector3int16 = 19,
|
||||
// CFrame = 20,
|
||||
// Enum = 21,
|
||||
NumberSequence = 23,
|
||||
NumberSequenceKeypoint,
|
||||
ColorSequence,
|
||||
ColorSequenceKeypoint,
|
||||
NumberRange,
|
||||
Rect,
|
||||
PhysicalProperties,
|
||||
Region3 = 31,
|
||||
Region3int16,
|
||||
// NumberSequenceKeypoint = 24,
|
||||
ColorSequence = 25,
|
||||
// ColorSequenceKeypoint = 26,
|
||||
NumberRange = 27,
|
||||
Rect = 28,
|
||||
// PhysicalProperties = 29
|
||||
// Region3 = 31,
|
||||
// Region3int16 = 32
|
||||
}
|
||||
|
||||
public class Attribute : IDisposable
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<AttributeType, Tokenizer> AttributeSupport;
|
||||
private static readonly IReadOnlyDictionary<Type, AttributeType> SupportedTypes;
|
||||
|
||||
public AttributeType DataType { get; private set; }
|
||||
public object Value { get; private set; }
|
||||
|
||||
private struct Tokenizer
|
||||
{
|
||||
public readonly Type Support;
|
||||
public readonly object Token;
|
||||
|
||||
public readonly MethodInfo Reader;
|
||||
public readonly MethodInfo Writer;
|
||||
|
||||
public Tokenizer(Type tokenType, Type support)
|
||||
{
|
||||
Support = support;
|
||||
Token = Activator.CreateInstance(tokenType);
|
||||
|
||||
Reader = support.GetMethod("ReadAttribute");
|
||||
Writer = support.GetMethod("WriteAttribute");
|
||||
}
|
||||
|
||||
public object ReadAttribute(Attribute attr)
|
||||
{
|
||||
var args = new object[1] { attr };
|
||||
return Reader.Invoke(Token, args);
|
||||
}
|
||||
|
||||
public void WriteAttribute(Attribute attr, object value)
|
||||
{
|
||||
var args = new object[2] { attr, value };
|
||||
Writer.Invoke(Token, args);
|
||||
}
|
||||
}
|
||||
|
||||
static Attribute()
|
||||
{
|
||||
var attributeSupport = new Dictionary<AttributeType, Tokenizer>();
|
||||
var supportedTypes = new Dictionary<Type, AttributeType>();
|
||||
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
var handlerTypes =
|
||||
from type in assembly.GetTypes()
|
||||
let typeInfo = type.GetTypeInfo()
|
||||
let support = typeInfo.GetInterface("IAttributeToken`1")
|
||||
where (support != null)
|
||||
select new Tokenizer(typeInfo, support);
|
||||
|
||||
foreach (var tokenizer in handlerTypes)
|
||||
{
|
||||
var token = tokenizer.Token;
|
||||
var support = tokenizer.Support;
|
||||
|
||||
var genericType = support.GenericTypeArguments.FirstOrDefault();
|
||||
var getAttributeType = support.GetMethod("get_AttributeType");
|
||||
var attributeType = (AttributeType)getAttributeType.Invoke(token, null);
|
||||
|
||||
attributeSupport.Add(attributeType, tokenizer);
|
||||
supportedTypes.Add(genericType, attributeType);
|
||||
}
|
||||
|
||||
AttributeSupport = attributeSupport;
|
||||
SupportedTypes = supportedTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the provided type is supported by attributes.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SupportsType(Type type)
|
||||
{
|
||||
return SupportedTypes.ContainsKey(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the provided type is supported by attributes.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static bool SupportsType<T>()
|
||||
{
|
||||
Type type = typeof(T);
|
||||
return SupportsType(type);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string type = Enum.GetName(typeof(AttributeType), DataType);
|
||||
string value = Value?.ToString() ?? "null";
|
||||
return $"[{type}: {value}]";
|
||||
return $"[{DataType}: {value}]";
|
||||
}
|
||||
|
||||
internal BinaryReader reader;
|
||||
// internal BinaryWriter writer;
|
||||
internal BinaryReader Reader;
|
||||
internal BinaryWriter Writer;
|
||||
|
||||
internal int ReadInt() => reader.ReadInt32();
|
||||
internal byte ReadByte() => reader.ReadByte();
|
||||
internal bool ReadBool() => reader.ReadBoolean();
|
||||
internal short ReadShort() => reader.ReadInt16();
|
||||
internal float ReadFloat() => reader.ReadSingle();
|
||||
internal double ReadDouble() => reader.ReadDouble();
|
||||
internal string ReadString() => reader.ReadString(true);
|
||||
internal int ReadInt() => Reader.ReadInt32();
|
||||
internal byte ReadByte() => Reader.ReadByte();
|
||||
internal bool ReadBool() => Reader.ReadBoolean();
|
||||
internal short ReadShort() => Reader.ReadInt16();
|
||||
internal float ReadFloat() => Reader.ReadSingle();
|
||||
internal double ReadDouble() => Reader.ReadDouble();
|
||||
internal string ReadString() => Reader.ReadString(true);
|
||||
|
||||
internal Attribute[] ReadArray()
|
||||
internal void WriteInt(int value) => Writer.Write(value);
|
||||
internal void WriteBool(bool value) => Writer.Write(value);
|
||||
internal void WriteFloat(float value) => Writer.Write(value);
|
||||
internal void WriteDouble(double value) => Writer.Write(value);
|
||||
|
||||
internal void WriteString(string value)
|
||||
{
|
||||
int count = ReadInt();
|
||||
var result = new Attribute[count];
|
||||
int length = value.Length;
|
||||
Writer.Write(length);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
result[i] = new Attribute(reader);
|
||||
|
||||
return result;
|
||||
byte[] utf8 = Encoding.UTF8.GetBytes(value);
|
||||
Writer.Write(utf8);
|
||||
}
|
||||
|
||||
internal object readEnum()
|
||||
internal void Read()
|
||||
{
|
||||
string name = ReadString();
|
||||
int value = ReadInt();
|
||||
|
||||
try
|
||||
{
|
||||
Type enumType = Type.GetType($"RobloxFiles.Enums.{name}");
|
||||
return Enum.ToObject(enumType, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (RobloxFile.LogErrors)
|
||||
Console.Error.WriteLine($"RobloxFile - Got unknown Enum {name} in Attribute.");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void readData()
|
||||
{
|
||||
if (reader == null)
|
||||
if (Reader == null)
|
||||
return;
|
||||
|
||||
DataType = (AttributeType)reader.ReadByte();
|
||||
var dataType = Reader.ReadByte();
|
||||
DataType = (AttributeType)dataType;
|
||||
|
||||
switch (DataType)
|
||||
{
|
||||
case AttributeType.Null:
|
||||
break;
|
||||
case AttributeType.String:
|
||||
Value = ReadString();
|
||||
break;
|
||||
case AttributeType.Bool:
|
||||
Value = ReadBool();
|
||||
break;
|
||||
case AttributeType.Int:
|
||||
Value = ReadInt();
|
||||
break;
|
||||
case AttributeType.Float:
|
||||
Value = ReadFloat();
|
||||
break;
|
||||
case AttributeType.Double:
|
||||
Value = ReadDouble();
|
||||
break;
|
||||
case AttributeType.Array:
|
||||
Value = ReadArray();
|
||||
break;
|
||||
case AttributeType.Dictionary:
|
||||
Value = new Attributes(reader);
|
||||
break;
|
||||
case AttributeType.UDim:
|
||||
Value = new UDim(this);
|
||||
break;
|
||||
case AttributeType.UDim2:
|
||||
Value = new UDim2(this);
|
||||
break;
|
||||
case AttributeType.Ray:
|
||||
Value = new Ray(this);
|
||||
break;
|
||||
case AttributeType.Faces:
|
||||
Value = (Faces)ReadInt();
|
||||
break;
|
||||
case AttributeType.Axes:
|
||||
Value = (Axes)ReadInt();
|
||||
break;
|
||||
case AttributeType.BrickColor:
|
||||
Value = (BrickColor)ReadInt();
|
||||
break;
|
||||
case AttributeType.Color3:
|
||||
Value = new Color3(this);
|
||||
break;
|
||||
case AttributeType.Vector2:
|
||||
Value = new Vector2(this);
|
||||
break;
|
||||
case AttributeType.Vector3:
|
||||
Value = new Vector3(this);
|
||||
break;
|
||||
case AttributeType.Vector2int16:
|
||||
Value = new Vector2int16(this);
|
||||
break;
|
||||
case AttributeType.Vector3int16:
|
||||
Value = new Vector3int16(this);
|
||||
break;
|
||||
case AttributeType.CFrame:
|
||||
Value = new CFrame(this);
|
||||
break;
|
||||
case AttributeType.Enum:
|
||||
Value = readEnum();
|
||||
break;
|
||||
case AttributeType.NumberSequence:
|
||||
Value = new NumberSequence(this);
|
||||
break;
|
||||
case AttributeType.NumberSequenceKeypoint:
|
||||
Value = new NumberSequenceKeypoint(this);
|
||||
break;
|
||||
case AttributeType.ColorSequence:
|
||||
Value = new ColorSequence(this);
|
||||
break;
|
||||
case AttributeType.ColorSequenceKeypoint:
|
||||
Value = new ColorSequenceKeypoint(this);
|
||||
break;
|
||||
case AttributeType.NumberRange:
|
||||
Value = new NumberRange(this);
|
||||
break;
|
||||
case AttributeType.Rect:
|
||||
Value = new Rect(this);
|
||||
break;
|
||||
case AttributeType.PhysicalProperties:
|
||||
bool custom = ReadBool();
|
||||
var tokenizer = AttributeSupport[DataType];
|
||||
Value = tokenizer.ReadAttribute(this);
|
||||
|
||||
if (custom)
|
||||
Value = new PhysicalProperties(this);
|
||||
|
||||
break;
|
||||
case AttributeType.Region3:
|
||||
Value = new Region3(this);
|
||||
break;
|
||||
case AttributeType.Region3int16:
|
||||
Value = new Region3int16(this);
|
||||
break;
|
||||
default: throw new InvalidDataException($"Cannot handle AttributeType {DataType}!");
|
||||
}
|
||||
|
||||
reader = null;
|
||||
Reader = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
reader.Dispose();
|
||||
Reader?.Dispose();
|
||||
}
|
||||
|
||||
internal void Write(BinaryWriter writer)
|
||||
{
|
||||
var tokenizer = AttributeSupport[DataType];
|
||||
Writer = writer;
|
||||
|
||||
writer.Write((byte)DataType);
|
||||
tokenizer.WriteAttribute(this, Value);
|
||||
|
||||
Writer = null;
|
||||
}
|
||||
|
||||
internal Attribute(BinaryReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
readData();
|
||||
Reader = reader;
|
||||
Read();
|
||||
}
|
||||
|
||||
internal Attribute(MemoryStream stream)
|
||||
{
|
||||
reader = new BinaryReader(stream);
|
||||
readData();
|
||||
Reader = new BinaryReader(stream);
|
||||
Read();
|
||||
}
|
||||
|
||||
internal Attribute(object value)
|
||||
{
|
||||
Type type = value.GetType();
|
||||
|
||||
if (SupportedTypes.TryGetValue(type, out AttributeType dataType))
|
||||
{
|
||||
DataType = dataType;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,15 +248,32 @@ namespace RobloxFiles
|
||||
internal Attributes(MemoryStream stream)
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
Initialize(reader);
|
||||
}
|
||||
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
internal byte[] Serialize()
|
||||
{
|
||||
// TODO
|
||||
return Array.Empty<byte>();
|
||||
if (Count == 0)
|
||||
return Array.Empty<byte>();
|
||||
|
||||
using (var output = new MemoryStream())
|
||||
using (var writer = new BinaryWriter(output))
|
||||
{
|
||||
writer.Write(Count);
|
||||
|
||||
foreach (string key in Keys)
|
||||
{
|
||||
var attribute = this[key];
|
||||
attribute.Writer = writer;
|
||||
|
||||
attribute.WriteString(key);
|
||||
attribute.Write(writer);
|
||||
}
|
||||
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,19 +64,22 @@ namespace RobloxFiles
|
||||
public HashSet<string> Tags { get; } = new HashSet<string>();
|
||||
|
||||
/// <summary>The attributes defined for this Instance.</summary>
|
||||
public Attributes Attributes { get; private set; }
|
||||
private Attributes AttributesImpl;
|
||||
|
||||
/// <summary>The public readonly access point of the attributes on this Instance.</summary>
|
||||
public IReadOnlyDictionary<string, Attribute> Attributes => AttributesImpl;
|
||||
|
||||
/// <summary>The internal serialized data of this Instance's attributes</summary>
|
||||
internal byte[] AttributesSerialize
|
||||
{
|
||||
get
|
||||
{
|
||||
return Attributes?.Serialize() ?? Array.Empty<byte>();
|
||||
return AttributesImpl?.Serialize() ?? Array.Empty<byte>();
|
||||
}
|
||||
set
|
||||
{
|
||||
MemoryStream data = new MemoryStream(value);
|
||||
Attributes = new Attributes(data);
|
||||
var data = new MemoryStream(value);
|
||||
AttributesImpl = new Attributes(data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,6 +125,55 @@ namespace RobloxFiles
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to get the value of an attribute whose type is T.
|
||||
/// Returns false if no attribute was found with that type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected type of the attribute.</typeparam>
|
||||
/// <param name="key">The name of the attribute.</param>
|
||||
/// <param name="value">The out value to set.</param>
|
||||
/// <returns>True if the attribute could be read and the out value was set, false otherwise.</returns>
|
||||
public bool GetAttribute<T>(string key, out T value)
|
||||
{
|
||||
if (AttributesImpl.TryGetValue(key, out Attribute attr))
|
||||
{
|
||||
object result = attr.Value;
|
||||
|
||||
if (result is T)
|
||||
{
|
||||
value = (T)result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to set an attribute to the provided value. The provided key must be no longer than 100 characters.
|
||||
/// Returns false if the key is too long or the provided type is not supported by Roblox.
|
||||
/// If an attribute with the provide key already exists, it will be overwritten.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key">The name of the attribute.</param>
|
||||
/// <param name="value">The value to be assigned to the attribute.</param>
|
||||
/// <returns>True if the attribute was set, false otherwise.</returns>
|
||||
public bool SetAttribute<T>(string key, T value)
|
||||
{
|
||||
if (key.Length > 100)
|
||||
return false;
|
||||
|
||||
if (!Attribute.SupportsType<T>())
|
||||
return false;
|
||||
|
||||
var attr = new Attribute(value);
|
||||
AttributesImpl[key] = attr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Returns true if this Instance is an ancestor to the provided Instance.</summary>
|
||||
/// <param name="descendant">The instance whose descendance will be tested against this Instance.</param>
|
||||
public bool IsAncestorOf(Instance descendant)
|
||||
@ -432,7 +484,7 @@ namespace RobloxFiles
|
||||
ParentLocked = true;
|
||||
|
||||
Tags?.Clear();
|
||||
Attributes?.Clear();
|
||||
AttributesImpl?.Clear();
|
||||
|
||||
while (Children.Any())
|
||||
{
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -120,6 +120,8 @@ namespace RobloxFiles.UnitTest
|
||||
RobloxFile bin = RobloxFile.Open(@"Files\Binary.rbxl");
|
||||
RobloxFile xml = RobloxFile.Open(@"Files\Xml.rbxlx");
|
||||
|
||||
Folder attributes = bin.FindFirstChild<Folder>("Attributes", true);
|
||||
|
||||
Console.WriteLine("Files opened! Pausing execution for debugger analysis...");
|
||||
Debugger.Break();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Xml;
|
||||
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.Tokens;
|
||||
|
||||
namespace RobloxFiles.XmlFormat
|
||||
{
|
@ -7,7 +7,7 @@ using System.Xml;
|
||||
|
||||
using RobloxFiles.DataTypes;
|
||||
using RobloxFiles.Utility;
|
||||
using RobloxFiles.XmlFormat.PropertyTokens;
|
||||
using RobloxFiles.Tokens;
|
||||
|
||||
namespace RobloxFiles.XmlFormat
|
||||
{
|
@ -5,6 +5,8 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
|
||||
using RobloxFiles.Tokens;
|
||||
|
||||
namespace RobloxFiles.XmlFormat
|
||||
{
|
||||
public static class XmlPropertyTokens
|
||||
@ -27,7 +29,7 @@ namespace RobloxFiles.XmlFormat
|
||||
|
||||
foreach (IXmlPropertyToken propToken in propTokens)
|
||||
{
|
||||
var tokens = propToken.Token.Split(';')
|
||||
var tokens = propToken.XmlPropertyToken.Split(';')
|
||||
.Select(token => token.Trim())
|
||||
.ToList();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user