Added read support for Instance Attributes.
This isn't 100% finished yet. I intend to add some better API for reading specific attributes, as well as write support (of course!)
This commit is contained in:
parent
fd8598c1b5
commit
e14b092aa7
@ -87,6 +87,9 @@ namespace RobloxFiles.BinaryFormat.Chunks
|
||||
// Check if this is going to be casted as a BinaryString.
|
||||
// BinaryStrings should use a type of byte[] instead.
|
||||
|
||||
if (Name == "AttributesSerialize")
|
||||
return buffer;
|
||||
|
||||
Property prop = props[i];
|
||||
Instance instance = prop.Instance;
|
||||
|
||||
|
@ -26,6 +26,9 @@ namespace RobloxFiles.DataTypes
|
||||
private const string DefaultName = "Medium stone grey";
|
||||
private const int DefaultNumber = 194;
|
||||
|
||||
public static implicit operator int(BrickColor color) => color.Number;
|
||||
public static implicit operator BrickColor(int number) => FromNumber(number);
|
||||
|
||||
internal BrickColor(int number, uint rgb, string name)
|
||||
{
|
||||
uint r = (rgb / 65536) % 256;
|
||||
@ -44,6 +47,7 @@ namespace RobloxFiles.DataTypes
|
||||
ByPalette = BrickColors.PaletteMap.Select(number => ByNumber[number]).ToList();
|
||||
}
|
||||
|
||||
|
||||
public static BrickColor FromName(string name)
|
||||
{
|
||||
BrickColor result = null;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using RobloxFiles.Enums;
|
||||
|
||||
namespace RobloxFiles.DataTypes
|
||||
{
|
||||
@ -121,6 +122,50 @@ namespace RobloxFiles.DataTypes
|
||||
m31 = comp[9]; m32 = comp[10]; m33 = comp[11];
|
||||
}
|
||||
|
||||
private void initFromMatrix(Vector3 pos, Vector3 vX, Vector3 vY, Vector3 vZ = 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static CFrame operator +(CFrame a, Vector3 b)
|
||||
{
|
||||
float[] ac = a.GetComponents();
|
||||
|
@ -5,6 +5,7 @@ namespace RobloxFiles.DataTypes
|
||||
public class Color3
|
||||
{
|
||||
public readonly float R, G, B;
|
||||
public override string ToString() => $"{R}, {G}, {B}";
|
||||
|
||||
public Color3(float r = 0, float g = 0, float b = 0)
|
||||
{
|
||||
@ -13,9 +14,11 @@ namespace RobloxFiles.DataTypes
|
||||
B = b;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal Color3(Attribute attr)
|
||||
{
|
||||
return string.Join(", ", R, G, B);
|
||||
R = attr.readFloat();
|
||||
G = attr.readFloat();
|
||||
B = attr.readFloat();
|
||||
}
|
||||
|
||||
public static Color3 FromRGB(uint r = 0, uint g = 0, uint b = 0)
|
||||
|
@ -7,6 +7,7 @@
|
||||
public class Color3uint8
|
||||
{
|
||||
public readonly byte R, G, B;
|
||||
public override string ToString() => $"{R}, {G}, {B}";
|
||||
|
||||
public Color3uint8(byte r = 0, byte g = 0, byte b = 0)
|
||||
{
|
||||
@ -15,11 +16,6 @@
|
||||
B = b;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(", ", R, G, B);
|
||||
}
|
||||
|
||||
public static implicit operator Color3(Color3uint8 color)
|
||||
{
|
||||
float r = color.R / 255f;
|
||||
|
@ -6,6 +6,11 @@ namespace RobloxFiles.DataTypes
|
||||
{
|
||||
public readonly ColorSequenceKeypoint[] Keypoints;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join<ColorSequenceKeypoint>(" ", Keypoints);
|
||||
}
|
||||
|
||||
public ColorSequence(Color3 c) : this(c, c)
|
||||
{
|
||||
}
|
||||
@ -43,9 +48,15 @@ namespace RobloxFiles.DataTypes
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public ColorSequence(Attribute attr)
|
||||
{
|
||||
return string.Join<ColorSequenceKeypoint>(" ", Keypoints);
|
||||
int numKeys = attr.readInt();
|
||||
var keypoints = new ColorSequenceKeypoint[numKeys];
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
keypoints[i] = new ColorSequenceKeypoint(attr);
|
||||
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,11 @@
|
||||
public readonly Color3 Value;
|
||||
public readonly int Envelope;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Time} {Value.R} {Value.G} {Value.B} {Envelope}";
|
||||
}
|
||||
|
||||
public ColorSequenceKeypoint(float time, Color3 value, int envelope = 0)
|
||||
{
|
||||
Time = time;
|
||||
@ -13,9 +18,11 @@
|
||||
Envelope = envelope;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal ColorSequenceKeypoint(Attribute attr)
|
||||
{
|
||||
return string.Join(" ", Time, Value.R, Value.G, Value.B, Envelope);
|
||||
Envelope = attr.readInt();
|
||||
Time = attr.readFloat();
|
||||
Value = new Color3(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,7 @@
|
||||
public class Content
|
||||
{
|
||||
public readonly string Url;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Url;
|
||||
}
|
||||
public override string ToString() => Url;
|
||||
|
||||
public Content(string url)
|
||||
{
|
||||
|
@ -7,24 +7,39 @@ namespace RobloxFiles.DataTypes
|
||||
public readonly float Min;
|
||||
public readonly float Max;
|
||||
|
||||
public override string ToString() => $"{Min} {Max}";
|
||||
|
||||
public NumberRange(float num)
|
||||
{
|
||||
Min = num;
|
||||
Max = num;
|
||||
}
|
||||
|
||||
private static void checkRange(float min, float max)
|
||||
{
|
||||
if (max - min >= 0)
|
||||
return;
|
||||
|
||||
throw new Exception("NumberRange: invalid range");
|
||||
}
|
||||
|
||||
public NumberRange(float min = 0, float max = 0)
|
||||
{
|
||||
if (max - min < 0)
|
||||
throw new Exception("NumberRange: invalid range");
|
||||
checkRange(min, max);
|
||||
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal NumberRange(Attribute attr)
|
||||
{
|
||||
return string.Join(" ", Min, Max);
|
||||
float min = attr.readFloat();
|
||||
float max = attr.readFloat();
|
||||
|
||||
checkRange(min, max);
|
||||
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,11 @@ namespace RobloxFiles.DataTypes
|
||||
{
|
||||
public readonly NumberSequenceKeypoint[] Keypoints;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join<NumberSequenceKeypoint>(" ", Keypoints);
|
||||
}
|
||||
|
||||
public NumberSequence(float n)
|
||||
{
|
||||
NumberSequenceKeypoint a = new NumberSequenceKeypoint(0, n);
|
||||
@ -47,9 +52,15 @@ namespace RobloxFiles.DataTypes
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public NumberSequence(Attribute attr)
|
||||
{
|
||||
return string.Join<NumberSequenceKeypoint>(" ", Keypoints);
|
||||
int numKeys = attr.readInt();
|
||||
var keypoints = new NumberSequenceKeypoint[numKeys];
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
keypoints[i] = new NumberSequenceKeypoint(attr);
|
||||
|
||||
Keypoints = keypoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,11 @@
|
||||
public readonly float Value;
|
||||
public readonly float Envelope;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Time} {Value} {Envelope}";
|
||||
}
|
||||
|
||||
public NumberSequenceKeypoint(float time, float value, float envelope = 0)
|
||||
{
|
||||
Time = time;
|
||||
@ -13,9 +18,11 @@
|
||||
Envelope = envelope;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal NumberSequenceKeypoint(Attribute attr)
|
||||
{
|
||||
return string.Join(" ", Time, Value, Envelope);
|
||||
Envelope = attr.readFloat();
|
||||
Time = attr.readFloat();
|
||||
Value = attr.readFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,11 @@ namespace RobloxFiles.DataTypes
|
||||
public readonly float FrictionWeight = 1.0f;
|
||||
public readonly float ElasticityWeight = 1.0f;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Density}, {Friction}, {Elasticity}, {FrictionWeight}, {ElasticityWeight}";
|
||||
}
|
||||
|
||||
public PhysicalProperties(Material material)
|
||||
{
|
||||
if (MaterialInfo.FrictionWeightMap.ContainsKey(material))
|
||||
@ -32,9 +37,14 @@ namespace RobloxFiles.DataTypes
|
||||
ElasticityWeight = elasticityWeight;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal PhysicalProperties(Attribute attr)
|
||||
{
|
||||
return string.Join(", ", Density, Friction, Elasticity, FrictionWeight, ElasticityWeight);
|
||||
Density = attr.readFloat();
|
||||
Friction = attr.readFloat();
|
||||
Elasticity = attr.readFloat();
|
||||
|
||||
FrictionWeight = attr.readFloat();
|
||||
ElasticityWeight = attr.readFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,7 @@
|
||||
public class ProtectedString
|
||||
{
|
||||
public readonly string ProtectedValue;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ProtectedValue;
|
||||
}
|
||||
public override string ToString() => ProtectedValue;
|
||||
|
||||
public ProtectedString(string value)
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ namespace RobloxFiles.DataTypes
|
||||
public class Quaternion
|
||||
{
|
||||
public readonly float X, Y, Z, W;
|
||||
public override string ToString() => $"{X}, {Y}, {Z}, {W}";
|
||||
|
||||
public float Magnitude
|
||||
{
|
||||
@ -21,11 +22,6 @@ namespace RobloxFiles.DataTypes
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(", ", X, Y, Z, W);
|
||||
}
|
||||
|
||||
public Quaternion(float x, float y, float z, float w)
|
||||
{
|
||||
X = x;
|
||||
|
@ -5,6 +5,8 @@
|
||||
public readonly Vector3 Origin;
|
||||
public readonly Vector3 Direction;
|
||||
|
||||
public override string ToString() => $"{{{Origin}}}, {{{Direction}}}";
|
||||
|
||||
public Ray Unit
|
||||
{
|
||||
get
|
||||
@ -26,9 +28,10 @@
|
||||
Direction = direction ?? new Vector3();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal Ray(Attribute attr)
|
||||
{
|
||||
return '{' + Origin.ToString() + "}, {" + Direction.ToString() + '}';
|
||||
Origin = new Vector3(attr);
|
||||
Direction = new Vector3(attr);
|
||||
}
|
||||
|
||||
public Vector3 ClosestPoint(Vector3 point)
|
||||
|
@ -8,6 +8,8 @@
|
||||
public float Width => (Max - Min).X;
|
||||
public float Height => (Max - Min).Y;
|
||||
|
||||
public override string ToString() => $"{Min}, {Max}";
|
||||
|
||||
public Rect(Vector2 min = null, Vector2 max = null)
|
||||
{
|
||||
Min = min ?? Vector2.Zero;
|
||||
@ -20,9 +22,10 @@
|
||||
Max = new Vector2(maxX, maxY);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal Rect(Attribute attr)
|
||||
{
|
||||
return string.Join(", ", Min, Max);
|
||||
Min = new Vector2(attr);
|
||||
Max = new Vector2(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,37 +4,39 @@ namespace RobloxFiles.DataTypes
|
||||
{
|
||||
public class Region3
|
||||
{
|
||||
public readonly CFrame CFrame;
|
||||
public readonly Vector3 Size;
|
||||
public readonly Vector3 Min, Max;
|
||||
|
||||
public Region3(Vector3 a, Vector3 b)
|
||||
public Vector3 Size => (Max - Min);
|
||||
public CFrame CFrame => new CFrame((Min + Max) / 2);
|
||||
|
||||
public override string ToString() => $"{CFrame}; {Size}";
|
||||
|
||||
public Region3(Vector3 min, Vector3 max)
|
||||
{
|
||||
CFrame = new CFrame((a + b) / 2);
|
||||
Size = b - a;
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal Region3(Attribute attr)
|
||||
{
|
||||
return CFrame + "; " + Size;
|
||||
Min = new Vector3(attr);
|
||||
Max = new Vector3(attr);
|
||||
}
|
||||
|
||||
public Region3 ExpandToGrid(float resolution)
|
||||
{
|
||||
Vector3 min = (CFrame - (Size / 2)).Position / resolution;
|
||||
Vector3 max = (CFrame + (Size / 2)).Position / resolution;
|
||||
|
||||
Vector3 emin = new Vector3
|
||||
(
|
||||
(float)Math.Floor(min.X) * resolution,
|
||||
(float)Math.Floor(min.Y) * resolution,
|
||||
(float)Math.Floor(min.Z) * resolution
|
||||
(float)Math.Floor(Min.X) * resolution,
|
||||
(float)Math.Floor(Min.Y) * resolution,
|
||||
(float)Math.Floor(Min.Z) * resolution
|
||||
);
|
||||
|
||||
Vector3 emax = new Vector3
|
||||
(
|
||||
(float)Math.Floor(max.X) * resolution,
|
||||
(float)Math.Floor(max.Y) * resolution,
|
||||
(float)Math.Floor(max.Z) * resolution
|
||||
(float)Math.Floor(Max.X) * resolution,
|
||||
(float)Math.Floor(Max.Y) * resolution,
|
||||
(float)Math.Floor(Max.Z) * resolution
|
||||
);
|
||||
|
||||
return new Region3(emin, emax);
|
||||
|
@ -1,14 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RobloxFiles.DataTypes
|
||||
namespace RobloxFiles.DataTypes
|
||||
{
|
||||
public struct Region3int16
|
||||
public class Region3int16
|
||||
{
|
||||
public readonly Vector3int16 Min, Max;
|
||||
public override string ToString() => $"{Min}; {Max}";
|
||||
|
||||
public Region3int16(Vector3int16 min = null, Vector3int16 max = null)
|
||||
{
|
||||
@ -16,9 +11,10 @@ namespace RobloxFiles.DataTypes
|
||||
Max = max ?? new Vector3int16();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal Region3int16(Attribute attr)
|
||||
{
|
||||
return string.Join("; ", Min, Max);
|
||||
Min = new Vector3int16(attr);
|
||||
Max = new Vector3int16(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,20 @@
|
||||
public readonly float Scale;
|
||||
public readonly int Offset;
|
||||
|
||||
public override string ToString() => $"{Scale}, {Offset}";
|
||||
|
||||
public UDim(float scale = 0, int offset = 0)
|
||||
{
|
||||
Scale = scale;
|
||||
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,10 +28,5 @@
|
||||
{
|
||||
return new UDim(a.Scale - b.Scale, a.Offset - b.Offset);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(", ", Scale, Offset);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
public class UDim2
|
||||
{
|
||||
public readonly UDim X, Y;
|
||||
public override string ToString() => $"{{{X}}},{{{Y}}}";
|
||||
|
||||
public UDim Width => X;
|
||||
public UDim Height => Y;
|
||||
@ -19,9 +20,10 @@
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal UDim2(Attribute attr)
|
||||
{
|
||||
return '{' + X.ToString() + "},{" + Y.ToString() + '}';
|
||||
X = new UDim(attr);
|
||||
Y = new UDim(attr);
|
||||
}
|
||||
|
||||
public UDim2 Lerp(UDim2 other, float alpha)
|
||||
|
@ -5,6 +5,7 @@ namespace RobloxFiles.DataTypes
|
||||
public class Vector2
|
||||
{
|
||||
public readonly float X, Y;
|
||||
public override string ToString() => $"{X}, {Y}";
|
||||
|
||||
public float Magnitude
|
||||
{
|
||||
@ -34,6 +35,12 @@ namespace RobloxFiles.DataTypes
|
||||
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)
|
||||
@ -76,11 +83,6 @@ namespace RobloxFiles.DataTypes
|
||||
|
||||
public static Vector2 Zero => new Vector2(0, 0);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(", ", X, Y);
|
||||
}
|
||||
|
||||
public float Dot(Vector2 other)
|
||||
{
|
||||
float dotX = X * other.X;
|
||||
|
69
DataTypes/Vector2int16.cs
Normal file
69
DataTypes/Vector2int16.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using System;
|
||||
|
||||
namespace RobloxFiles.DataTypes
|
||||
{
|
||||
public class Vector2int16
|
||||
{
|
||||
public readonly short X, Y;
|
||||
public override string ToString() => $"{X}, {Y}";
|
||||
|
||||
public Vector2int16(short x = 0, short y = 0)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public Vector2int16(int x = 0, int y = 0)
|
||||
{
|
||||
X = (short)x;
|
||||
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)
|
||||
{
|
||||
Vector2int16 numVec = new Vector2int16(num, num);
|
||||
return upcast(vec, numVec);
|
||||
}
|
||||
|
||||
private static Vector2int16 upcastShortOp(short num, Vector2int16 vec, Operator upcast)
|
||||
{
|
||||
Vector2int16 numVec = new Vector2int16(num, num);
|
||||
return upcast(numVec, vec);
|
||||
}
|
||||
|
||||
private static Operator add = new Operator((a, b) => new Vector2int16(a.X + b.X, a.Y + b.Y));
|
||||
private static Operator sub = new Operator((a, b) => new Vector2int16(a.X - b.X, a.Y - b.Y));
|
||||
private static Operator mul = new Operator((a, b) => new Vector2int16(a.X * b.X, a.Y * b.Y));
|
||||
private static Operator div = new Operator((a, b) =>
|
||||
{
|
||||
if (b.X == 0 || b.Y == 0)
|
||||
throw new DivideByZeroException();
|
||||
|
||||
return new Vector2int16(a.X / b.X, a.Y / b.Y);
|
||||
});
|
||||
|
||||
public static Vector2int16 operator +(Vector2int16 a, Vector2int16 b) => add(a, b);
|
||||
public static Vector2int16 operator +(Vector2int16 v, short n) => upcastShortOp(v, n, add);
|
||||
public static Vector2int16 operator +(short n, Vector2int16 v) => upcastShortOp(n, v, add);
|
||||
|
||||
public static Vector2int16 operator -(Vector2int16 a, Vector2int16 b) => sub(a, b);
|
||||
public static Vector2int16 operator -(Vector2int16 v, short n) => upcastShortOp(v, n, sub);
|
||||
public static Vector2int16 operator -(short n, Vector2int16 v) => upcastShortOp(n, v, sub);
|
||||
|
||||
public static Vector2int16 operator *(Vector2int16 a, Vector2int16 b) => mul(a, b);
|
||||
public static Vector2int16 operator *(Vector2int16 v, short n) => upcastShortOp(v, n, mul);
|
||||
public static Vector2int16 operator *(short n, Vector2int16 v) => upcastShortOp(n, v, mul);
|
||||
|
||||
public static Vector2int16 operator /(Vector2int16 a, Vector2int16 b) => div(a, b);
|
||||
public static Vector2int16 operator /(Vector2int16 v, short n) => upcastShortOp(v, n, div);
|
||||
public static Vector2int16 operator /(short n, Vector2int16 v) => upcastShortOp(n, v, div);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ namespace RobloxFiles.DataTypes
|
||||
public class Vector3
|
||||
{
|
||||
public readonly float X, Y, Z;
|
||||
public override string ToString() => $"{X}, {Y}, {Z}";
|
||||
|
||||
public float Magnitude
|
||||
{
|
||||
@ -37,6 +38,13 @@ namespace RobloxFiles.DataTypes
|
||||
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 };
|
||||
@ -102,10 +110,7 @@ namespace RobloxFiles.DataTypes
|
||||
public static Vector3 Up => new Vector3(0, 1, 0);
|
||||
public static Vector3 Back => new Vector3(0, 0, 1);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(", ", X, Y, Z);
|
||||
}
|
||||
|
||||
|
||||
public float Dot(Vector3 other)
|
||||
{
|
||||
|
@ -5,12 +5,10 @@ namespace RobloxFiles.DataTypes
|
||||
public class Vector3int16
|
||||
{
|
||||
public readonly short X, Y, Z;
|
||||
public override string ToString() => $"{X}, {Y}, {Z}";
|
||||
|
||||
public Vector3int16()
|
||||
public Vector3int16() : this(0, 0, 0)
|
||||
{
|
||||
X = 0;
|
||||
Y = 0;
|
||||
Z = 0;
|
||||
}
|
||||
|
||||
public Vector3int16(short x = 0, short y = 0, short z = 0)
|
||||
@ -27,9 +25,11 @@ namespace RobloxFiles.DataTypes
|
||||
Z = (short)z;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
internal Vector3int16(Attribute attr)
|
||||
{
|
||||
return string.Join(", ", X, Y, Z);
|
||||
X = attr.readShort();
|
||||
Y = attr.readShort();
|
||||
Z = attr.readShort();
|
||||
}
|
||||
|
||||
private delegate Vector3int16 Operator(Vector3int16 a, Vector3int16 b);
|
||||
|
@ -81,10 +81,13 @@
|
||||
<Compile Include="DataTypes\Color3uint8.cs" />
|
||||
<Compile Include="DataTypes\ProtectedString.cs" />
|
||||
<Compile Include="DataTypes\Content.cs" />
|
||||
<Compile Include="DataTypes\Region3int16.cs" />
|
||||
<Compile Include="DataTypes\SharedString.cs" />
|
||||
<Compile Include="DataTypes\Vector2int16.cs" />
|
||||
<Compile Include="Interfaces\IBinaryFileChunk.cs" />
|
||||
<Compile Include="Generated\Classes.cs" />
|
||||
<Compile Include="Generated\Enums.cs" />
|
||||
<Compile Include="Tree\Attributes.cs" />
|
||||
<Compile Include="Tree\Property.cs" />
|
||||
<Compile Include="Tree\Instance.cs" />
|
||||
<Compile Include="RobloxFile.cs" />
|
||||
|
Binary file not shown.
252
Tree/Attributes.cs
Normal file
252
Tree/Attributes.cs
Normal file
@ -0,0 +1,252 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles
|
||||
{
|
||||
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,
|
||||
NumberSequence = 23,
|
||||
NumberSequenceKeypoint,
|
||||
ColorSequence,
|
||||
ColorSequenceKeypoint,
|
||||
NumberRange,
|
||||
Rect,
|
||||
PhysicalProperties,
|
||||
Region3 = 31,
|
||||
Region3int16,
|
||||
}
|
||||
|
||||
public class Attribute
|
||||
{
|
||||
public AttributeType DataType { get; private set; }
|
||||
public object Value { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string type = Enum.GetName(typeof(AttributeType), DataType);
|
||||
string value = Value?.ToString() ?? "null";
|
||||
return $"[{type}: {value}]";
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
private Attribute[] readArray()
|
||||
{
|
||||
int count = readInt();
|
||||
var result = new Attribute[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
result[i] = new Attribute(reader);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private object readEnum()
|
||||
{
|
||||
string name = readString();
|
||||
int value = readInt();
|
||||
|
||||
try
|
||||
{
|
||||
Type enumType = Type.GetType($"RobloxFiles.Enums.{name}");
|
||||
return Enum.ToObject(enumType, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine($"RobloxFile - Got unknown Enum {name} in Attribute.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void readData()
|
||||
{
|
||||
if (reader == null)
|
||||
return;
|
||||
|
||||
DataType = (AttributeType)reader.ReadByte();
|
||||
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
internal Attribute(BinaryReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
readData();
|
||||
}
|
||||
|
||||
internal Attribute(MemoryStream stream)
|
||||
{
|
||||
reader = new BinaryReader(stream);
|
||||
readData();
|
||||
}
|
||||
}
|
||||
|
||||
public class Attributes : Dictionary<string, Attribute>
|
||||
{
|
||||
private void initialize(BinaryReader reader)
|
||||
{
|
||||
int numEntries = reader.ReadInt32();
|
||||
|
||||
for (int i = 0; i < numEntries; i++)
|
||||
{
|
||||
string key = reader.ReadString(true);
|
||||
var attribute = new Attribute(reader);
|
||||
Add(key, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
internal Attributes(BinaryReader reader)
|
||||
{
|
||||
initialize(reader);
|
||||
}
|
||||
|
||||
internal Attributes(MemoryStream stream)
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
initialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] Serialize()
|
||||
{
|
||||
// TODO
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
@ -57,8 +58,22 @@ namespace RobloxFiles
|
||||
/// <summary>A list of CollectionService tags assigned to this Instance.</summary>
|
||||
public List<string> Tags => RawTags;
|
||||
|
||||
/// <summary>The attributes defined for this Instance.</summary>
|
||||
public Attributes Attributes { get; private set; }
|
||||
|
||||
/// <summary>The internal serialized data of this Instance's attributes</summary>
|
||||
internal byte[] AttributesSerialize;
|
||||
internal byte[] AttributesSerialize
|
||||
{
|
||||
get
|
||||
{
|
||||
return Attributes?.Serialize() ?? new byte[0];
|
||||
}
|
||||
set
|
||||
{
|
||||
MemoryStream data = new MemoryStream(value);
|
||||
Attributes = new Attributes(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal format of the Instance's CollectionService tags.
|
||||
@ -538,6 +553,7 @@ namespace RobloxFiles
|
||||
}
|
||||
|
||||
Property tags = GetProperty("Tags");
|
||||
Property attributes = GetProperty("AttributesSerialize");
|
||||
|
||||
if (tags == null)
|
||||
{
|
||||
@ -545,6 +561,12 @@ namespace RobloxFiles
|
||||
AddProperty(ref tags);
|
||||
}
|
||||
|
||||
if (attributes == null)
|
||||
{
|
||||
attributes = new Property("AttributesSerialize", PropertyType.String);
|
||||
AddProperty(ref attributes);
|
||||
}
|
||||
|
||||
return Properties;
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +166,11 @@ namespace RobloxFiles
|
||||
byte[] data = Instance.SerializedTags;
|
||||
RawValue = data;
|
||||
}
|
||||
else if (Name == "AttributesSerialize")
|
||||
{
|
||||
byte[] data = Instance.AttributesSerialize;
|
||||
RawValue = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
FieldInfo field = Instance.GetType()
|
||||
@ -194,6 +199,11 @@ namespace RobloxFiles
|
||||
byte[] data = value as byte[];
|
||||
Instance.SerializedTags = data;
|
||||
}
|
||||
else if (Name == "AttributesSerialize" && value is byte[])
|
||||
{
|
||||
byte[] data = value as byte[];
|
||||
Instance.AttributesSerialize = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
FieldInfo field = Instance.GetType()
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
internal static class Formatting
|
||||
{
|
||||
@ -112,4 +114,15 @@ internal static class Formatting
|
||||
{
|
||||
return Math.Abs(a - b) < epsilon;
|
||||
}
|
||||
|
||||
public static string ReadString(this BinaryReader reader, bool useIntLength)
|
||||
{
|
||||
if (!useIntLength)
|
||||
return reader.ReadString();
|
||||
|
||||
int len = reader.ReadInt32();
|
||||
byte[] buffer = reader.ReadBytes(len);
|
||||
|
||||
return Encoding.UTF8.GetString(buffer);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user