Initial commit.

There's a lot of code at play here, so I haven't tested it yet.
A good chunk of the components are available though.
This commit is contained in:
CloneTrooper1019 2019-01-25 18:39:37 -06:00
parent b4825c146f
commit 9cfd5b2211
40 changed files with 5128 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
bin/*
obj/*
packages/*
.vs/*
*.suo
*.ide

124
BinaryFormat/BinaryFile.cs Normal file
View File

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using Roblox.BinaryFormat.Chunks;
namespace Roblox.BinaryFormat
{
public class RobloxBinaryFile : RobloxFile
{
public const string FileSignature = "<roblox!\x89\xff\x0d\x0a\x1a\x0a";
public readonly List<RobloxBinaryChunk> BinaryChunks = new List<RobloxBinaryChunk>();
public readonly PRNT ParentIds;
public readonly META Metadata;
public readonly Dictionary<int, INST> INSTs = new Dictionary<int, INST>();
public readonly List<PROP> PROPs = new List<PROP>();
public readonly RobloxInstance[] Instances;
public readonly ushort Version;
public readonly uint NumTypes;
public readonly uint NumInstances;
public readonly long Reserved;
public RobloxBinaryFile(byte[] contents)
{
using (MemoryStream file = new MemoryStream(contents))
using (RobloxBinaryReader reader = new RobloxBinaryReader(file))
{
byte[] binSignature = reader.ReadBytes(14);
string signature = Encoding.UTF7.GetString(binSignature);
if (signature != FileSignature)
throw new InvalidDataException("Signature does not match RobloxBinaryFile.FileSignature!");
Version = reader.ReadUInt16();
NumTypes = reader.ReadUInt32();
NumInstances = reader.ReadUInt32();
Reserved = reader.ReadInt64();
// Begin reading the file chunks.
bool reading = true;
Instances = new RobloxInstance[NumInstances];
BinaryChunks = new List<RobloxBinaryChunk>();
while (reading)
{
try
{
RobloxBinaryChunk chunk = new RobloxBinaryChunk(reader);
BinaryChunks.Add(chunk);
switch (chunk.ChunkType)
{
case "INST":
INST inst = new INST(chunk);
INSTs.Add(inst.TypeIndex, inst);
break;
case "PROP":
PROP prop = new PROP(chunk);
PROPs.Add(prop);
break;
case "PRNT":
PRNT prnt = new PRNT(chunk);
ParentIds = prnt;
break;
case "META":
META meta = new META(chunk);
Metadata = meta;
break;
case "END\0":
reading = false;
break;
default:
BinaryChunks.Remove(chunk);
break;
}
}
catch (EndOfStreamException)
{
throw new Exception("Unexpected end of file!");
}
}
foreach (INST chunk in INSTs.Values)
{
foreach (int id in chunk.InstanceIds)
{
RobloxInstance inst = new RobloxInstance();
inst.ClassName = chunk.TypeName;
Instances[id] = inst;
}
}
foreach (PROP prop in PROPs)
{
INST chunk = INSTs[prop.Index];
prop.ReadPropertyValues(chunk, Instances);
}
for (int i = 0; i < ParentIds.NumRelations; i++)
{
int childId = ParentIds.ChildrenIds[i];
int parentId = ParentIds.ParentIds[i];
RobloxInstance child = Instances[childId];
if (parentId >= 0)
{
var parent = Instances[parentId];
child.Parent = parent;
}
else
{
Trunk.Add(child);
}
}
}
}
}
}

57
BinaryFormat/Chunk.cs Normal file
View File

@ -0,0 +1,57 @@
using System;
using System.IO;
using System.Text;
using LZ4;
namespace Roblox.BinaryFormat
{
public class RobloxBinaryChunk
{
public readonly string ChunkType;
public readonly int CompressedSize;
public readonly byte[] CompressedData;
public readonly int Size;
public readonly int Reserved;
public readonly byte[] Data;
public bool HasCompressedData => (CompressedSize > 0);
public override string ToString()
{
return ChunkType + " Chunk [" + Size + ']';
}
public RobloxBinaryReader GetReader(string chunkType)
{
if (ChunkType == chunkType)
{
MemoryStream buffer = new MemoryStream(Data);
return new RobloxBinaryReader(buffer);
}
throw new Exception("Expected " + chunkType + " ChunkType from the input RobloxBinaryChunk");
}
public RobloxBinaryChunk(RobloxBinaryReader reader)
{
byte[] bChunkType = reader.ReadBytes(4);
ChunkType = Encoding.ASCII.GetString(bChunkType);
CompressedSize = reader.ReadInt32();
Size = reader.ReadInt32();
Reserved = reader.ReadInt32();
if (HasCompressedData)
{
CompressedData = reader.ReadBytes(CompressedSize);
Data = LZ4Codec.Decode(CompressedData, 0, CompressedSize, Size);
}
else
{
Data = reader.ReadBytes(Size);
}
}
}
}

View File

@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.IO;
namespace Roblox.BinaryFormat.Chunks
{
public class INST
{
public readonly int TypeIndex;
public readonly string TypeName;
public readonly bool IsService;
public readonly int NumInstances;
public readonly int[] InstanceIds;
public Dictionary<string, PROP> Properties;
public override string ToString()
{
return TypeName;
}
public INST(RobloxBinaryChunk chunk)
{
using (RobloxBinaryReader reader = chunk.GetReader("INST"))
{
TypeIndex = reader.ReadInt32();
TypeName = reader.ReadString();
IsService = reader.ReadBoolean();
NumInstances = reader.ReadInt32();
InstanceIds = reader.ReadInstanceIds(NumInstances);
}
Properties = new Dictionary<string, PROP>();
}
}
}

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.IO;
namespace Roblox.BinaryFormat.Chunks
{
public class META
{
public int NumEntries;
public Dictionary<string, string> Entries;
public META(RobloxBinaryChunk chunk)
{
using (RobloxBinaryReader reader = chunk.GetReader("META"))
{
NumEntries = reader.ReadInt32();
Entries = new Dictionary<string, string>(NumEntries);
for (int i = 0; i < NumEntries; i++)
{
string key = reader.ReadString();
string value = reader.ReadString();
Entries.Add(key, value);
}
}
}
}
}

View File

@ -0,0 +1,23 @@
namespace Roblox.BinaryFormat.Chunks
{
public class PRNT
{
public readonly byte Format;
public readonly int NumRelations;
public readonly int[] ChildrenIds;
public readonly int[] ParentIds;
public PRNT(RobloxBinaryChunk chunk)
{
using (RobloxBinaryReader reader = chunk.GetReader("PRNT"))
{
Format = reader.ReadByte();
NumRelations = reader.ReadInt32();
ChildrenIds = reader.ReadInstanceIds(NumRelations);
ParentIds = reader.ReadInstanceIds(NumRelations);
}
}
}
}

View File

@ -0,0 +1,422 @@
using System;
using System.IO;
using System.Linq;
using Roblox.Enums;
using Roblox.DataTypes;
using Roblox.DataTypes.Utility;
namespace Roblox.BinaryFormat.Chunks
{
public class PROP
{
public int Index { get; private set; }
public string Name { get; private set; }
public readonly PropertyType Type;
public RobloxProperty[] Properties => props;
private RobloxBinaryReader reader;
private RobloxProperty[] props;
public override string ToString()
{
Type PropertyType = typeof(PropertyType);
return '[' + Enum.GetName(PropertyType, Type) + "] " + Name;
}
public PROP(RobloxBinaryChunk chunk)
{
reader = chunk.GetReader("PROP");
Index = reader.ReadInt32();
Name = reader.ReadString();
try
{
byte propType = reader.ReadByte();
Type = (PropertyType)propType;
}
catch
{
Type = PropertyType.Unknown;
}
}
public void ReadPropertyValues(INST instChunk, RobloxInstance[] instMap)
{
int[] ids = instChunk.InstanceIds;
int instCount = ids.Length;
props = new RobloxProperty[instCount];
for (int i = 0; i < instCount; i++)
{
RobloxProperty prop = new RobloxProperty();
prop.Name = Name;
prop.Type = Type;
Properties[i] = prop;
instMap[ids[i]].Properties.Add(prop);
}
// Setup some short-hand functions for frequently used actions.
var readInstanceInts = new Func<int[]>(() => reader.ReadInts(instCount));
var readInstanceFloats = new Func<float[]>(() => reader.ReadFloats(instCount));
var loadProperties = new Action<Func<int, object>>(read =>
{
for (int i = 0; i < instCount; i++)
{
object result = read(i);
props[i].Value = result;
}
});
// Process the property data based on the property type.
switch (Type)
{
case PropertyType.String:
loadProperties(i => reader.ReadString());
break;
case PropertyType.Bool:
loadProperties(i => reader.ReadBoolean());
break;
case PropertyType.Int:
int[] ints = readInstanceInts();
loadProperties(i => ints[i]);
break;
case PropertyType.Float:
float[] floats = readInstanceFloats();
loadProperties(i => floats[i]);
break;
case PropertyType.Double:
loadProperties(i => reader.ReadDouble());
break;
case PropertyType.UDim:
float[] scales = readInstanceFloats();
int[] offsets = readInstanceInts();
loadProperties(i =>
{
float scale = scales[i];
int offset = offsets[i];
return new UDim(scale, offset);
});
break;
case PropertyType.UDim2:
float[] scalesX = readInstanceFloats(), scalesY = readInstanceFloats();
int[] offsetsX = readInstanceInts(), offsetsY = readInstanceInts();
loadProperties(i =>
{
float scaleX = scalesX[i], scaleY = scalesY[i];
int offsetX = offsetsX[i], offsetY = offsetsY[i];
return new UDim2(scaleX, offsetX, scaleY, offsetY);
});
break;
case PropertyType.Ray:
loadProperties(i =>
{
float[] rawOrigin = reader.ReadFloats(3);
Vector3 origin = new Vector3(rawOrigin);
float[] rawDirection = reader.ReadFloats(3);
Vector3 direction = new Vector3(rawDirection);
return new Ray(origin, direction);
});
break;
case PropertyType.Faces:
loadProperties(i =>
{
byte faces = reader.ReadByte();
return (Faces)faces;
});
break;
case PropertyType.Axes:
loadProperties(i =>
{
byte axes = reader.ReadByte();
return (Axes)axes;
});
break;
case PropertyType.BrickColor:
int[] brickColors = readInstanceInts();
loadProperties(i =>
{
int number = brickColors[i];
return BrickColor.New(number);
});
break;
case PropertyType.Color3:
float[] color3_R = readInstanceFloats(),
color3_G = readInstanceFloats(),
color3_B = readInstanceFloats();
loadProperties(i =>
{
float r = color3_R[i],
g = color3_G[i],
b = color3_B[i];
return new Color3(r, g, b);
});
break;
case PropertyType.Vector2:
float[] vector2_X = readInstanceFloats(),
vector2_Y = readInstanceFloats();
loadProperties(i =>
{
float x = vector2_X[i],
y = vector2_Y[i];
return new Vector2(x, y);
});
break;
case PropertyType.Vector3:
float[] vector3_X = readInstanceFloats(),
vector3_Y = readInstanceFloats(),
vector3_Z = readInstanceFloats();
loadProperties(i =>
{
float x = vector3_X[i],
y = vector3_Y[i],
z = vector3_Z[i];
return new Vector3(x, y, z);
});
break;
case PropertyType.CFrame:
case PropertyType.Quaternion:
// Temporarily load the rotation matrices into their properties.
// We'll update them to CFrames once we iterate over the position data.
loadProperties(i =>
{
byte orientId = reader.ReadByte();
if (orientId > 0)
{
NormalId normX = (NormalId)((orientId - 1) / 6);
Vector3 R0 = Vector3.FromNormalId(normX);
NormalId normY = (NormalId)((orientId - 1) % 6);
Vector3 R1 = Vector3.FromNormalId(normY);
// Compute R2 using the cross product of R0 and R1.
Vector3 R2 = R0.Cross(R1);
// Generate the rotation matrix and return it.
return new float[9]
{
R0.X, R0.Y, R0.Z,
R1.X, R1.Y, R1.Z,
R2.X, R2.Y, R2.Z,
};
}
else if (Type == PropertyType.Quaternion)
{
float qx = reader.ReadSingle(),
qy = reader.ReadSingle(),
qz = reader.ReadSingle(),
qw = reader.ReadSingle();
Quaternion quat = new Quaternion(qx, qy, qz, qw);
var rotation = quat.ToCFrame();
return rotation.GetComponents();
}
else
{
float[] matrix = new float[9];
for (int m = 0; m < 9; m++)
{
float value = reader.ReadSingle();
matrix[m] = value;
}
return matrix;
}
});
float[] cframe_X = readInstanceFloats(),
cframe_Y = readInstanceFloats(),
cframe_Z = readInstanceFloats();
loadProperties(i =>
{
float[] matrix = props[i].Value as float[];
float x = cframe_X[i],
y = cframe_Y[i],
z = cframe_Z[i];
float[] position = new float[3] { x, y, z };
float[] components = position.Concat(matrix).ToArray();
return new CFrame(components);
});
break;
case PropertyType.Enum:
uint[] enums = reader.ReadInterwovenValues(instCount, BitConverter.ToUInt32);
loadProperties(i => enums[i]);
break;
case PropertyType.Ref:
int[] instIds = reader.ReadInstanceIds(instCount);
loadProperties(i =>
{
int instId = instIds[i];
return instId >= 0 ? instMap[instId] : null;
});
break;
case PropertyType.Vector3int16:
loadProperties(i =>
{
short x = reader.ReadInt16(),
y = reader.ReadInt16(),
z = reader.ReadInt16();
return new Vector3int16(x, y, z);
});
break;
case PropertyType.NumberSequence:
loadProperties(i =>
{
int keys = reader.ReadInt32();
var keypoints = new NumberSequenceKeypoint[keys];
for (int key = 0; key < keys; key++)
{
float time = reader.ReadSingle(),
value = reader.ReadSingle(),
envelope = reader.ReadSingle();
keypoints[key] = new NumberSequenceKeypoint(time, value, envelope);
}
return new NumberSequence(keypoints);
});
break;
case PropertyType.ColorSequence:
loadProperties(i =>
{
int keys = reader.ReadInt32();
var keypoints = new ColorSequenceKeypoint[keys];
for (int key = 0; key < keys; key++)
{
float time = reader.ReadSingle(),
R = reader.ReadSingle(),
G = reader.ReadSingle(),
B = reader.ReadSingle(),
envelope = reader.ReadSingle(); // unused, but still written
keypoints[key] = new ColorSequenceKeypoint(time, new Color3(R, G, B));
}
return new ColorSequence(keypoints);
});
break;
case PropertyType.NumberRange:
loadProperties(i =>
{
float min = reader.ReadSingle();
float max = reader.ReadSingle();
return new NumberRange(min, max);
});
break;
case PropertyType.Rect:
float[] Rect_X0 = readInstanceFloats(),
Rect_Y0 = readInstanceFloats(),
Rect_X1 = readInstanceFloats(),
Rect_Y1 = readInstanceFloats();
loadProperties(i =>
{
float x0 = Rect_X0[i],
y0 = Rect_Y0[i],
x1 = Rect_X1[i],
y1 = Rect_Y1[i];
return new Rect(x0, y0, x1, y1);
});
break;
case PropertyType.PhysicalProperties:
loadProperties(i =>
{
bool custom = reader.ReadBoolean();
if (custom)
{
float density = reader.ReadSingle(),
friction = reader.ReadSingle(),
elasticity = reader.ReadSingle(),
frictionWeight = reader.ReadSingle(),
elasticityWeight = reader.ReadSingle();
return new PhysicalProperties
(
density,
friction,
elasticity,
frictionWeight,
elasticityWeight
);
}
return null;
});
break;
case PropertyType.Color3uint8:
byte[] color3uint8_R = reader.ReadBytes(instCount),
color3uint8_G = reader.ReadBytes(instCount),
color3uint8_B = reader.ReadBytes(instCount);
loadProperties(i =>
{
byte r = color3uint8_R[i],
g = color3uint8_G[i],
b = color3uint8_B[i];
return Color3.fromRGB(r, g, b);
});
break;
case PropertyType.Int64:
long[] int64s = reader.ReadInterwovenValues(instCount, (buffer, start) =>
{
long result = BitConverter.ToInt64(buffer, start);
return (long)((ulong)result >> 1) ^ (-(result & 1));
});
loadProperties(i => int64s[i]);
break;
}
}
}
}

77
BinaryFormat/Reader.cs Normal file
View File

@ -0,0 +1,77 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Roblox.DataTypes;
namespace Roblox.BinaryFormat
{
public class RobloxBinaryReader : BinaryReader
{
public RobloxBinaryReader(Stream stream) : base(stream) { }
public T[] ReadInterwovenValues<T>(int count, Func<byte[], int, T> decode) where T : struct
{
int bufferSize = Marshal.SizeOf<T>();
byte[] interwoven = ReadBytes(count * bufferSize);
T[] values = new T[count];
for (int i = 0; i < count; i++)
{
long unwind = 0;
for (int weave = 0; weave < bufferSize; weave++)
{
long splice = interwoven[(weave * count) + i];
int strand = (bufferSize - weave - 1) * 8;
unwind |= (splice << strand);
}
byte[] buffer = BitConverter.GetBytes(unwind);
values[i] = decode(buffer, 0);
}
return values;
}
public int[] ReadInts(int count)
{
return ReadInterwovenValues(count, (buffer, start) =>
{
int value = BitConverter.ToInt32(buffer, start);
return (value >> 1) ^ (-(value & 1));
});
}
public float[] ReadFloats(int count)
{
return ReadInterwovenValues(count, (buffer, start) =>
{
uint u = BitConverter.ToUInt32(buffer, start);
uint i = (u >> 1) | (u << 31);
byte[] b = BitConverter.GetBytes(i);
return BitConverter.ToSingle(b, 0);
});
}
public int[] ReadInstanceIds(int count)
{
int[] values = ReadInts(count);
for (int i = 1; i < count; ++i)
values[i] += values[i - 1];
return values;
}
public override string ReadString()
{
int length = ReadInt32();
byte[] buffer = ReadBytes(length);
return Encoding.UTF8.GetString(buffer);
}
}
}

2116
Core/Enums.cs Normal file

File diff suppressed because it is too large Load Diff

91
Core/Instance.cs Normal file
View File

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace Roblox
{
public class RobloxInstance
{
private List<RobloxInstance> _children = new List<RobloxInstance>();
private RobloxInstance _parent;
public string ClassName;
public List<RobloxProperty> Properties = new List<RobloxProperty>();
public bool IsAncestorOf(RobloxInstance other)
{
while (other != null)
{
if (other == this)
return true;
other = other.Parent;
}
return false;
}
public bool IsDescendantOf(RobloxInstance other)
{
return other.IsAncestorOf(this);
}
public RobloxInstance Parent
{
get { return _parent; }
set
{
if (IsAncestorOf(value))
throw new Exception("Parent would result in circular reference.");
if (Parent == this)
throw new Exception("Attempt to set parent to self");
if (_parent != null)
_parent._children.Remove(this);
value._children.Add(this);
_parent = value;
}
}
public ReadOnlyCollection<RobloxInstance> Children
{
get { return _children.AsReadOnly(); }
}
public object ReadProperty(string propertyName)
{
RobloxProperty property = Properties
.Where((prop) => prop.Name == propertyName)
.First();
return property.Value;
}
public bool TryReadProperty<T>(string propertyName, out T value)
{
try
{
object result = ReadProperty(propertyName);
value = (T)result;
return true;
}
catch
{
value = default(T);
return false;
}
}
public override string ToString()
{
var name = "";
TryReadProperty("Name", out name);
return '[' + ClassName + ']' + name;
}
}
}

62
Core/Property.cs Normal file
View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roblox
{
public enum PropertyType
{
Unknown,
String,
Bool,
Int,
Float,
Double,
UDim,
UDim2,
Ray,
Faces,
Axes,
BrickColor,
Color3,
Vector2,
Vector3,
Vector2int16,
CFrame,
Quaternion,
Enum,
Ref,
Vector3int16,
NumberSequence,
ColorSequence,
NumberRange,
Rect,
PhysicalProperties,
Color3uint8,
Int64
}
public class RobloxProperty
{
public string Name;
public PropertyType Type;
public object Value;
public override string ToString()
{
Type PropertyType = typeof(PropertyType);
string typeName = Enum.GetName(PropertyType, Type);
string valueLabel;
if (Value != null)
valueLabel = Value.ToString();
else
valueLabel = "?";
return string.Join(" ", typeName, Name, '=', valueLabel);
}
}
}

13
Core/RobloxFile.cs Normal file
View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roblox
{
public class RobloxFile
{
public List<RobloxInstance> Trunk { get; private set; }
}
}

13
DataTypes/Axes.cs Normal file
View File

@ -0,0 +1,13 @@
using System;
using Roblox.Enums;
namespace Roblox.DataTypes
{
[Flags]
public enum Axes
{
X = 0 << Axis.X,
Y = 0 << Axis.Y,
Z = 0 << Axis.Z,
}
}

118
DataTypes/BrickColor.cs Normal file
View File

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Roblox.DataTypes.Utility;
namespace Roblox.DataTypes
{
public class BrickColor
{
public readonly int Number;
public readonly string Name;
public readonly Color3 Color;
public float R => Color.R;
public float G => Color.G;
public float B => Color.B;
public override string ToString() => Name;
private static List<BrickColor> ByPalette;
private static Dictionary<int, BrickColor> ByNumber;
private static Dictionary<string, BrickColor> ByName;
private static Random RNG = new Random();
private const string DefaultName = "Medium stone grey";
private const int DefaultNumber = 194;
internal BrickColor(int number, int rgb, string name)
{
int r = (rgb / 65536) % 256;
int g = (rgb / 256) % 256;
int b = rgb % 256;
Name = name;
Number = number;
Color = Color3.fromRGB(r, g, b);
}
static BrickColor()
{
ByName = BrickColors.ColorMap.ToDictionary(brickColor => brickColor.Name);
ByNumber = BrickColors.ColorMap.ToDictionary(brickColor => brickColor.Number);
ByPalette = BrickColors.PaletteMap.Select(number => ByNumber[number]).ToList();
}
public static BrickColor New(string name)
{
if (!ByName.ContainsKey(name))
name = DefaultName;
return ByName[name];
}
public static BrickColor New(int number)
{
if (!ByNumber.ContainsKey(number))
number = DefaultNumber;
return ByNumber[number];
}
public static BrickColor New(Color3 color)
{
return New(color.R, color.G, color.B);
}
public static BrickColor New(float r = 0, float g = 0, float b = 0)
{
BrickColor bestMatch = New(-1);
float closest = float.MaxValue;
foreach (BrickColor brickColor in BrickColors.ColorMap)
{
float dist = Math.Abs(brickColor.R - r)
+ Math.Abs(brickColor.G - g)
+ Math.Abs(brickColor.B - b);
if (dist < closest)
{
// Return this BrickColor if its an exact match.
if (dist == 0.0f)
return brickColor;
bestMatch = brickColor;
closest = dist;
}
}
return bestMatch;
}
public static BrickColor Random()
{
int index = RNG.Next(ByPalette.Count);
return ByPalette[index];
}
public static BrickColor Palette(int index)
{
if (index < 0 || index >= ByPalette.Count)
throw new Exception("Palette index was out of range.");
return ByPalette[index];
}
public static BrickColor White() => New("White");
public static BrickColor Gray() => New("Medium stone grey");
public static BrickColor DarkGray() => New("Dark stone grey");
public static BrickColor Black() => New("Black");
public static BrickColor Red() => New("Bright red");
public static BrickColor Yellow() => New("Bright yellow");
public static BrickColor Green() => New("Dark green");
public static BrickColor Blue() => New("Bright blue");
}
}

331
DataTypes/CFrame.cs Normal file
View File

@ -0,0 +1,331 @@
using System;
using Roblox.DataTypes.Utility;
namespace Roblox.DataTypes
{
public class CFrame
{
private float m11 = 1, m12 = 0, m13 = 0, m14 = 0;
private float m21 = 0, m22 = 1, m23 = 0, m24 = 0;
private float m31 = 0, m32 = 0, m33 = 1, m34 = 0;
private const float m41 = 0, m42 = 0, m43 = 0, m44 = 1;
public float X => m14;
public float Y => m24;
public float Z => m34;
public Vector3 Position => new Vector3(X, Y, Z);
public Vector3 LookVector => new Vector3(-m13, -m23, -m33);
public Vector3 RightVector => new Vector3( m11, m21, m31);
public Vector3 UpVector => new Vector3( m12, m22, m32);
public CFrame(Vector3 pos)
{
m14 = pos.X;
m24 = pos.Y;
m34 = pos.Z;
}
public CFrame(Vector3 eye, Vector3 look)
{
Vector3 zAxis = (eye - look).Unit;
Vector3 xAxis = Vector3.Up.Cross(zAxis);
Vector3 yAxis = zAxis.Cross(xAxis);
if (xAxis.Magnitude == 0)
{
if (zAxis.Y < 0)
{
xAxis = new Vector3(0, 0, -1);
yAxis = new Vector3(1, 0, 0);
zAxis = new Vector3(0, -1, 0);
}
else
{
xAxis = new Vector3(0, 0, 1);
yAxis = new Vector3(1, 0, 0);
zAxis = new Vector3(0, 1, 0);
}
}
m11 = xAxis.X; m12 = yAxis.X; m13 = zAxis.X; m14 = eye.X;
m21 = xAxis.Y; m22 = yAxis.Y; m23 = zAxis.Y; m24 = eye.Y;
m31 = xAxis.Z; m32 = yAxis.Z; m33 = zAxis.Z; m34 = eye.Z;
}
public CFrame(float nx = 0, float ny = 0, float nz = 0)
{
m14 = nx;
m24 = ny;
m34 = nz;
}
public CFrame(float nx, float ny, float nz, float i, float j, float k, float w)
{
float ii = i * i;
float jj = j * j;
float kk = k * k;
m14 = nx;
m24 = ny;
m34 = nz;
m11 = 1 - 2 * jj - 2 * kk;
m12 = 2 * (i * j - k * w);
m13 = 2 * (i * k + j * w);
m21 = 2 * (i * j + k * w);
m22 = 1 - 2 * ii - 2 * kk;
m23 = 2 * (j * k - i * w);
m31 = 2 * (i * k - j * w);
m32 = 2 * (j * k + i * w);
m33 = 1 - 2 * ii - 2 * jj;
}
public CFrame(float n14, float n24, float n34, float n11, float n12, float n13, float n21, float n22, float n23, float n31, float n32, float n33)
{
m14 = n14; m24 = n24; m34 = n34;
m11 = n11; m12 = n12; m13 = n13;
m21 = n21; m22 = n22; m23 = n23;
m31 = n31; m32 = n32; m33 = n33;
}
public CFrame(params float[] comp)
{
if (comp.Length < 12)
throw new Exception("There should be 12 floats provided to construct CFrame with an array of floats");
m14 = comp[0]; m24 = comp[1]; m34 = comp[2];
m11 = comp[3]; m12 = comp[4]; m13 = comp[5];
m21 = comp[6]; m22 = comp[7]; m23 = comp[8];
m31 = comp[9]; m32 = comp[10]; m33 = comp[11];
}
public static CFrame operator +(CFrame a, Vector3 b)
{
float[] ac = a.GetComponents();
float x = ac[0], y = ac[1], z = ac[2],
m11 = ac[3], m12 = ac[4], m13 = ac[5],
m21 = ac[6], m22 = ac[7], m23 = ac[8],
m31 = ac[9], m32 = ac[10], m33 = ac[11];
return new CFrame(x + b.X, y + b.Y, z + b.Z, m11, m12, m13, m21, m22, m23, m31, m32, m33);
}
public static CFrame operator -(CFrame a, Vector3 b)
{
float[] ac = a.GetComponents();
float x = ac[0], y = ac[1], z = ac[2],
m11 = ac[3], m12 = ac[4], m13 = ac[5],
m21 = ac[6], m22 = ac[7], m23 = ac[8],
m31 = ac[9], m32 = ac[10], m33 = ac[11];
return new CFrame(x - b.X, y - b.Y, z - b.Z, m11, m12, m13, m21, m22, m23, m31, m32, m33);
}
public static Vector3 operator *(CFrame a, Vector3 b)
{
float[] ac = a.GetComponents();
float x = ac[0], y = ac[1], z = ac[2],
m11 = ac[3], m12 = ac[4], m13 = ac[5],
m21 = ac[6], m22 = ac[7], m23 = ac[8],
m31 = ac[9], m32 = ac[10], m33 = ac[11];
Vector3 right = new Vector3(m11, m21, m31);
Vector3 up = new Vector3(m12, m22, m32);
Vector3 back = new Vector3(m13, m23, m33);
return a.Position + b.X * right + b.Y * up + b.Z * back;
}
public static CFrame operator *(CFrame a, CFrame b)
{
float[] ac = a.GetComponents();
float[] bc = b.GetComponents();
float a14 = ac[0], a24 = ac[1], a34 = ac[2],
a11 = ac[3], a12 = ac[4], a13 = ac[5],
a21 = ac[6], a22 = ac[7], a23 = ac[8],
a31 = ac[9], a32 = ac[10], a33 = ac[11];
float b14 = bc[0], b24 = bc[1], b34 = bc[2],
b11 = bc[3], b12 = bc[4], b13 = bc[5],
b21 = bc[6], b22 = bc[7], b23 = bc[8],
b31 = bc[9], b32 = bc[10], b33 = bc[11];
float n11 = a11 * b11 + a12 * b21 + a13 * b31 + a14 * m41;
float n12 = a11 * b12 + a12 * b22 + a13 * b32 + a14 * m42;
float n13 = a11 * b13 + a12 * b23 + a13 * b33 + a14 * m43;
float n14 = a11 * b14 + a12 * b24 + a13 * b34 + a14 * m44;
float n21 = a21 * b11 + a22 * b21 + a23 * b31 + a24 * m41;
float n22 = a21 * b12 + a22 * b22 + a23 * b32 + a24 * m42;
float n23 = a21 * b13 + a22 * b23 + a23 * b33 + a24 * m43;
float n24 = a21 * b14 + a22 * b24 + a23 * b34 + a24 * m44;
float n31 = a31 * b11 + a32 * b21 + a33 * b31 + a34 * m41;
float n32 = a31 * b12 + a32 * b22 + a33 * b32 + a34 * m42;
float n33 = a31 * b13 + a32 * b23 + a33 * b33 + a34 * m43;
float n34 = a31 * b14 + a32 * b24 + a33 * b34 + a34 * m44;
float n41 = 0 * b11 + m42 * b21 + m43 * b31 + m44 * m41;
float n42 = 0 * b12 + m42 * b22 + m43 * b32 + m44 * m42;
float n43 = 0 * b13 + m42 * b23 + m43 * b33 + m44 * m43;
float n44 = 0 * b14 + m42 * b24 + m43 * b34 + m44 * m44;
return new CFrame(n14, n24, n34, n11, n12, n13, n21, n22, n23, n31, n32, n33);
}
public override string ToString()
{
return string.Join(", ", GetComponents());
}
private static Vector3 VectorAxisAngle(Vector3 vec, Vector3 axis, float theta)
{
Vector3 unit = vec.Unit;
float cosAng = (float)Math.Cos(theta);
float sinAng = (float)Math.Sin(theta);
return axis * cosAng + axis.Dot(unit) * unit *
(1 - cosAng) + unit.Cross(axis) * sinAng;
}
public CFrame Inverse()
{
float[] ac = GetComponents();
float a14 = ac[0], a24 = ac[1], a34 = ac[2],
a11 = ac[3], a12 = ac[4], a13 = ac[5],
a21 = ac[6], a22 = ac[7], a23 = ac[8],
a31 = ac[9], a32 = ac[10], a33 = ac[11];
float det = ( a11 * a22 * a33 * m44 + a11 * a23 * a34 * m42 + a11 * a24 * a32 * m43
+ a12 * a21 * a34 * m43 + a12 * a23 * a31 * m44 + a12 * a24 * a33 * m41
+ a13 * a21 * a32 * m44 + a13 * a22 * a34 * m41 + a13 * a24 * a31 * m42
+ a14 * a21 * a33 * m42 + a14 * a22 * a31 * m43 + a14 * a23 * a32 * m41
- a11 * a22 * a34 * m43 - a11 * a23 * a32 * m44 - a11 * a24 * a33 * m42
- a12 * a21 * a33 * m44 - a12 * a23 * a34 * m41 - a12 * a24 * a31 * m43
- a13 * a21 * a34 * m42 - a13 * a22 * a31 * m44 - a13 * a24 * a32 * m41
- a14 * a21 * a32 * m43 - a14 * a22 * a33 * m41 - a14 * a23 * a31 * m42 );
if (det == 0)
return this;
float b11 = (a22 * a33 * m44 + a23 * a34 * m42 + a24 * a32 * m43 - a22 * a34 * m43 - a23 * a32 * m44 - a24 * a33 * m42) / det;
float b12 = (a12 * a34 * m43 + a13 * a32 * m44 + a14 * a33 * m42 - a12 * a33 * m44 - a13 * a34 * m42 - a14 * a32 * m43) / det;
float b13 = (a12 * a23 * m44 + a13 * a24 * m42 + a14 * a22 * m43 - a12 * a24 * m43 - a13 * a22 * m44 - a14 * a23 * m42) / det;
float b14 = (a12 * a24 * a33 + a13 * a22 * a34 + a14 * a23 * a32 - a12 * a23 * a34 - a13 * a24 * a32 - a14 * a22 * a33) / det;
float b21 = (a21 * a34 * m43 + a23 * a31 * m44 + a24 * a33 * m41 - a21 * a33 * m44 - a23 * a34 * m41 - a24 * a31 * m43) / det;
float b22 = (a11 * a33 * m44 + a13 * a34 * m41 + a14 * a31 * m43 - a11 * a34 * m43 - a13 * a31 * m44 - a14 * a33 * m41) / det;
float b23 = (a11 * a24 * m43 + a13 * a21 * m44 + a14 * a23 * m41 - a11 * a23 * m44 - a13 * a24 * m41 - a14 * a21 * m43) / det;
float b24 = (a11 * a23 * a34 + a13 * a24 * a31 + a14 * a21 * a33 - a11 * a24 * a33 - a13 * a21 * a34 - a14 * a23 * a31) / det;
float b31 = (a21 * a32 * m44 + a22 * a34 * m41 + a24 * a31 * m42 - a21 * a34 * m42 - a22 * a31 * m44 - a24 * a32 * m41) / det;
float b32 = (a11 * a34 * m42 + a12 * a31 * m44 + a14 * a32 * m41 - a11 * a32 * m44 - a12 * a34 * m41 - a14 * a31 * m42) / det;
float b33 = (a11 * a22 * m44 + a12 * a24 * m41 + a14 * a21 * m42 - a11 * a24 * m42 - a12 * a21 * m44 - a14 * a22 * m41) / det;
float b34 = (a11 * a24 * a32 + a12 * a21 * a34 + a14 * a22 * a31 - a11 * a22 * a34 - a12 * a24 * a31 - a14 * a21 * a32) / det;
float b41 = (a21 * a33 * m42 + a22 * a31 * m43 + a23 * a32 * m41 - a21 * a32 * m43 - a22 * a33 * m41 - a23 * a31 * m42) / det;
float b42 = (a11 * a32 * m43 + a12 * a33 * m41 + a13 * a31 * m42 - a11 * a33 * m42 - a12 * a31 * m43 - a13 * a32 * m41) / det;
float b43 = (a11 * a23 * m42 + a12 * a21 * m43 + a13 * a22 * m41 - a11 * a22 * m43 - a12 * a23 * m41 - a13 * a21 * m42) / det;
float b44 = (a11 * a22 * a33 + a12 * a23 * a31 + a13 * a21 * a32 - a11 * a23 * a32 - a12 * a21 * a33 - a13 * a22 * a31) / det;
return new CFrame(b14, b24, b34, b11, b12, b13, b21, b22, b23, b31, b32, b33);
}
public static CFrame FromAxisAngle(Vector3 axis, float theta)
{
Vector3 r = VectorAxisAngle(axis, Vector3.Right, theta);
Vector3 u = VectorAxisAngle(axis, Vector3.Up, theta);
Vector3 b = VectorAxisAngle(axis, Vector3.Back, theta);
return new CFrame(0, 0, 0, r.X, u.X, b.X, r.Y, u.Y, b.Y, r.Z, u.Z, b.Z);
}
public static CFrame Angles(float x, float y, float z)
{
CFrame cfx = FromAxisAngle(Vector3.Right, x);
CFrame cfy = FromAxisAngle(Vector3.Up, y);
CFrame cfz = FromAxisAngle(Vector3.Back, z);
return cfx * cfy * cfz;
}
public static CFrame FromEulerAnglesXYZ(float x, float y, float z)
{
return Angles(x, y, z);
}
public CFrame Lerp(CFrame other, float t)
{
if (t == 0.0f)
{
return this;
}
else if (t == 1.0f)
{
return other;
}
else
{
Quaternion q1 = new Quaternion(this);
Quaternion q2 = new Quaternion(other);
CFrame rot = q1.Slerp(q2, t).ToCFrame();
Vector3 pos = Position.Lerp(other.Position, t);
return new CFrame(pos) * rot;
}
}
public CFrame ToWorldSpace(CFrame cf2)
{
return this * cf2;
}
public CFrame ToObjectSpace(CFrame other)
{
return Inverse() * other;
}
public Vector3 PointToWorldSpace(Vector3 v)
{
return this * v;
}
public Vector3 PointToObjectSpace(Vector3 v)
{
return Inverse() * v;
}
public Vector3 VectorToWorldSpace(Vector3 v)
{
return (this - Position) * v;
}
public Vector3 VectorToObjectSpace(Vector3 v)
{
return (this - Position).Inverse() * v;
}
public float[] GetComponents()
{
return new float[] { m14, m24, m34, m11, m12, m13, m21, m22, m23, m31, m32, m33 };
}
public float[] toEulerAnglesXYZ()
{
float x = (float)Math.Atan2(-m23, m33);
float y = (float)Math.Asin(m13);
float z = (float)Math.Atan2(-m12, m11);
return new float[] { x, y, z };
}
}
}

91
DataTypes/Color3.cs Normal file
View File

@ -0,0 +1,91 @@
using System;
namespace Roblox.DataTypes
{
public struct Color3
{
public readonly float R, G, B;
public Color3(float r = 0, float g = 0, float b = 0)
{
R = r;
G = g;
B = b;
}
public override string ToString()
{
return string.Join(", ", R, G, B);
}
public static Color3 fromRGB(int r = 0, int g = 0, int b = 0)
{
return new Color3(r / 255f, g / 255f, b / 255f);
}
public static Color3 fromHSV(float h = 0, float s = 0, float v = 0)
{
int i = (int)Math.Min(5, Math.Floor(6.0 * h));
float f = 6.0f * h - i;
float m = v * (1.0f - (s));
float n = v * (1.0f - (s * f));
float k = v * (1.0f - (s * (1 - f)));
switch (i)
{
case 0:
return new Color3(v, k, m);
case 1:
return new Color3(n, v, m);
case 2:
return new Color3(m, v, k);
case 3:
return new Color3(m, n, v);
case 4:
return new Color3(k, m, v);
case 5:
return new Color3(v, m, n);
default:
return new Color3();
}
}
public static float[] toHSV(Color3 color)
{
float val = Math.Max(Math.Max(color.R, color.G), color.B);
if (Math.Abs(val) < 0.001f)
return new float[3] { 0, 0, 0 };
float hue = Math.Min(Math.Min(color.R, color.G), color.B);
float sat = (val - hue) / val;
if (Math.Abs(sat) >= 0.001f)
{
Vector3 rgbN = val - new Vector3(color.R, color.G, color.B);
rgbN /= (val - hue);
if (color.R == val)
hue = (color.G == hue) ? 5.0f + rgbN.Z : 1.0f - rgbN.Y;
else if (color.G == val)
hue = (color.B == hue) ? 1.0f + rgbN.X : 3.0f - rgbN.Z;
else
hue = (color.R == hue) ? 3.0f + rgbN.Y : 5.0f - rgbN.Z;
hue /= 6.0f;
}
return new float[3] { hue, sat, val };
}
public Color3 Lerp(Color3 other, float alpha)
{
float r = (R + (other.R - R) * alpha);
float g = (G + (other.G - G) * alpha);
float b = (B + (other.B - B) * alpha);
return new Color3(r, g, b);
}
}
}

View File

@ -0,0 +1,52 @@
using System;
namespace Roblox.DataTypes
{
public struct ColorSequence
{
public readonly ColorSequenceKeypoint[] Keypoints;
public ColorSequence(Color3 c)
{
ColorSequenceKeypoint a = new ColorSequenceKeypoint(0, c);
ColorSequenceKeypoint b = new ColorSequenceKeypoint(1, c);
Keypoints = new ColorSequenceKeypoint[2] { a, b };
}
public ColorSequence(Color3 c0, Color3 c1)
{
ColorSequenceKeypoint a = new ColorSequenceKeypoint(0, c0);
ColorSequenceKeypoint b = new ColorSequenceKeypoint(1, c1);
Keypoints = new ColorSequenceKeypoint[2] { a, b };
}
public ColorSequence(ColorSequenceKeypoint[] keypoints)
{
int len = keypoints.Length;
if (len < 2)
throw new Exception("ColorSequence: requires at least 2 keypoints");
else if (len > 20)
throw new Exception("ColorSequence: table is too long.");
for (int i = 1; i < len; i++)
if (keypoints[i-1].Time > keypoints[i].Time)
throw new Exception("ColorSequence: all keypoints must be ordered by time");
if (keypoints[0].Time < 0)
throw new Exception("ColorSequence must start at time=0.0");
if (keypoints[len-1].Time > 1)
throw new Exception("ColorSequence must end at time=1.0");
Keypoints = keypoints;
}
public override string ToString()
{
return string.Join(" ", Keypoints);
}
}
}

View File

@ -0,0 +1,19 @@
namespace Roblox.DataTypes
{
public struct ColorSequenceKeypoint
{
public readonly float Time;
public readonly Color3 Color;
public ColorSequenceKeypoint(float time, Color3 color)
{
Time = time;
Color = color;
}
public override string ToString()
{
return string.Join(" ", Time, Color.R, Color.G, Color.B, 0);
}
}
}

16
DataTypes/Faces.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
using Roblox.Enums;
namespace Roblox.DataTypes
{
[Flags]
public enum Faces
{
Right = 0 << NormalId.Right,
Top = 0 << NormalId.Top,
Back = 0 << NormalId.Back,
Left = 0 << NormalId.Left,
Bottom = 0 << NormalId.Bottom,
Front = 0 << NormalId.Front,
}
}

24
DataTypes/NumberRange.cs Normal file
View File

@ -0,0 +1,24 @@
using System;
namespace Roblox.DataTypes
{
public struct NumberRange
{
public readonly float Min;
public readonly float Max;
public NumberRange(float min, float max)
{
if (max - min < 0)
throw new Exception("NumberRange: invalid range");
Min = min;
Max = max;
}
public override string ToString()
{
return string.Join(" ", Min, Max);
}
}
}

View File

@ -0,0 +1,52 @@
using System;
namespace Roblox.DataTypes
{
public struct NumberSequence
{
public readonly NumberSequenceKeypoint[] Keypoints;
public NumberSequence(float n)
{
NumberSequenceKeypoint a = new NumberSequenceKeypoint(0, n);
NumberSequenceKeypoint b = new NumberSequenceKeypoint(1, n);
Keypoints = new NumberSequenceKeypoint[2] { a, b };
}
public NumberSequence(float n0, float n1)
{
NumberSequenceKeypoint a = new NumberSequenceKeypoint(0, n0);
NumberSequenceKeypoint b = new NumberSequenceKeypoint(1, n1);
Keypoints = new NumberSequenceKeypoint[2] { a, b };
}
public NumberSequence(NumberSequenceKeypoint[] keypoints)
{
int len = keypoints.Length;
if (len < 2)
throw new Exception("NumberSequence: requires at least 2 keypoints");
else if (len > 20)
throw new Exception("NumberSequence: table is too long.");
for (int i = 1; i < len; i++)
if (keypoints[i - 1].Time > keypoints[i].Time)
throw new Exception("NumberSequence: all keypoints must be ordered by time");
if (keypoints[0].Time < 0)
throw new Exception("NumberSequence must start at time=0.0");
if (keypoints[len - 1].Time > 1)
throw new Exception("NumberSequence must end at time=1.0");
Keypoints = keypoints;
}
public override string ToString()
{
return string.Join(" ", Keypoints);
}
}
}

View File

@ -0,0 +1,21 @@
namespace Roblox.DataTypes
{
public struct NumberSequenceKeypoint
{
public readonly float Time;
public readonly float Value;
public readonly float Envelope;
public NumberSequenceKeypoint(float time, float value, float envelope = 0)
{
Time = time;
Value = value;
Envelope = envelope;
}
public override string ToString()
{
return string.Join(" ", Time, Value, Envelope);
}
}
}

29
DataTypes/PathWaypoint.cs Normal file
View File

@ -0,0 +1,29 @@
using System;
using Roblox.Enums;
namespace Roblox.DataTypes
{
public struct PathWaypoint
{
public readonly Vector3 Position;
public readonly PathWaypointAction Action;
public PathWaypoint(Vector3? position)
{
Position = position ?? Vector3.Zero;
Action = PathWaypointAction.Walk;
}
public PathWaypoint(Vector3 position, PathWaypointAction action = PathWaypointAction.Walk)
{
Position = position;
Action = action;
}
public override string ToString()
{
Type PathWaypointAction = typeof(PathWaypointAction);
return '{' + Position + "} " + Enum.GetName(PathWaypointAction, Action);
}
}
}

View File

@ -0,0 +1,50 @@
using Roblox.Enums;
using Roblox.DataTypes.Utility;
namespace Roblox.DataTypes
{
public struct PhysicalProperties
{
public readonly float Density;
public readonly float Friction;
public readonly float Elasticity;
public float FrictionWeight;
public float ElasticityWeight;
public PhysicalProperties(Material material)
{
Density = MaterialInfo.DensityMap[material];
Friction = MaterialInfo.FrictionMap[material];
Elasticity = MaterialInfo.ElasticityMap[material];
FrictionWeight = 1;
ElasticityWeight = 1;
}
public PhysicalProperties(float density, float friction, float elasticity)
{
Density = density;
Friction = friction;
Elasticity = elasticity;
FrictionWeight = 1;
ElasticityWeight = 1;
}
public PhysicalProperties(float density, float friction, float elasticity, float frictionWeight, float elasticityWeight)
{
Density = density;
Friction = friction;
Elasticity = elasticity;
FrictionWeight = frictionWeight;
ElasticityWeight = elasticityWeight;
}
public override string ToString()
{
return string.Join(", ", Density, Friction, Elasticity, FrictionWeight, ElasticityWeight);
}
}
}

47
DataTypes/Ray.cs Normal file
View File

@ -0,0 +1,47 @@
namespace Roblox.DataTypes
{
public struct Ray
{
public readonly Vector3 Origin;
public readonly Vector3 Direction;
public Ray Unit
{
get
{
Ray unit;
if (Direction.Magnitude == 1.0f)
unit = this;
else
unit = new Ray(Origin, Direction.Unit);
return unit;
}
}
public Ray(Vector3 origin, Vector3 direction)
{
Origin = origin;
Direction = direction;
}
public override string ToString()
{
return '{' + Origin + "}, {" + Direction + '}';
}
public Vector3 ClosestPoint(Vector3 point)
{
Vector3 offset = point - Origin;
float diff = offset.Dot(Direction) / Direction.Dot(Direction);
return Origin + (diff * Direction);
}
public float Distance(Vector3 point)
{
Vector3 projected = ClosestPoint(point);
return (point - projected).Magnitude;
}
}
}

28
DataTypes/Rect.cs Normal file
View File

@ -0,0 +1,28 @@
namespace Roblox.DataTypes
{
public struct Rect
{
public readonly Vector2 Min;
public readonly Vector2 Max;
public float Width => (Max - Min).X;
public float Height => (Max - Min).Y;
public Rect(Vector2? min, Vector2? max)
{
Min = min ?? Vector2.Zero;
Max = max ?? Vector2.Zero;
}
public Rect(float minX, float minY, float maxX, float maxY)
{
Min = new Vector2(minX, minY);
Max = new Vector2(maxX, maxY);
}
public override string ToString()
{
return string.Join(", ", Min, Max);
}
}
}

43
DataTypes/Region3.cs Normal file
View File

@ -0,0 +1,43 @@
using System;
namespace Roblox.DataTypes
{
public struct Region3
{
public readonly CFrame CFrame;
public readonly Vector3 Size;
public Region3(Vector3 a, Vector3 b)
{
CFrame = new CFrame((a + b) / 2);
Size = b - a;
}
public override string ToString()
{
return CFrame + "; " + Size;
}
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
);
Vector3 emax = new Vector3
(
(float)Math.Floor(max.X) * resolution,
(float)Math.Floor(max.Y) * resolution,
(float)Math.Floor(max.Z) * resolution
);
return new Region3(emin, emax);
}
}
}

24
DataTypes/Region3int16.cs Normal file
View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roblox.DataTypes
{
public struct Region3int16
{
public readonly Vector3int16 Min, Max;
public Region3int16(Vector3int16? min, Vector3int16? max)
{
Min = min ?? new Vector3int16();
Max = max ?? new Vector3int16();
}
public override string ToString()
{
return string.Join("; ", Min, Max);
}
}
}

29
DataTypes/UDim.cs Normal file
View File

@ -0,0 +1,29 @@
namespace Roblox.DataTypes
{
public struct UDim
{
public readonly float Scale;
public readonly int Offset;
public UDim(float scale = 0, int offset = 0)
{
Scale = scale;
Offset = offset;
}
public static UDim operator+(UDim a, UDim b)
{
return new UDim(a.Scale + b.Scale, a.Offset + b.Offset);
}
public static UDim operator-(UDim a, UDim b)
{
return new UDim(a.Scale - b.Scale, a.Offset - b.Offset);
}
public override string ToString()
{
return string.Join(", ", Scale, Offset);
}
}
}

38
DataTypes/UDim2.cs Normal file
View File

@ -0,0 +1,38 @@
namespace Roblox.DataTypes
{
public struct UDim2
{
public readonly UDim X, Y;
public UDim Width => X;
public UDim Height => Y;
public UDim2(float scaleX, int offsetX, float scaleY, int offsetY)
{
X = new UDim(scaleX, offsetX);
Y = new UDim(scaleY, offsetY);
}
public UDim2(UDim x, UDim y)
{
X = x;
Y = y;
}
public override string ToString()
{
return '{' + X.ToString() + "},{" + Y.ToString() + '}';
}
public UDim2 Lerp(UDim2 other, float alpha)
{
float scaleX = X.Scale + ((other.X.Scale - X.Scale) * alpha);
int offsetX = X.Offset + (int)((other.X.Offset - X.Offset) * alpha);
float scaleY = Y.Scale + ((other.Y.Scale - Y.Scale) * alpha);
int offsetY = Y.Offset + (int)((other.Y.Offset - Y.Offset) * alpha);
return new UDim2(scaleX, offsetX, scaleY, offsetY);
}
}
}

View File

@ -0,0 +1,251 @@
using System.Collections.Generic;
using Roblox.DataTypes;
namespace Roblox.DataTypes.Utility
{
public static class BrickColors
{
/// <summary>
/// This represents Roblox's static palette of BrickColors.
/// Each int refers to the `Number` identifying a BrickColor.
/// It is used by the BrickColor.palette constructor, which
/// is in turn used by the BrickColor.random constructor.
/// </summary>
public static readonly int[] PaletteMap = new int[128]
{
141, 301, 107, 26, 1012, 303, 1011, 304,
28, 1018, 302, 305, 306, 307, 308, 1021,
309, 310, 1019, 135, 102, 23, 1010, 312,
313, 37, 1022, 1020, 1027, 311, 315, 1023,
1031, 316, 151, 317, 318, 319, 1024, 314,
1013, 1006, 321, 322, 104, 1008, 119, 323,
324, 325, 320, 11, 1026, 1016, 1032, 1015,
327, 1005, 1009, 29, 328, 1028, 208, 45,
329, 330, 331, 1004, 21, 332, 333, 24,
334, 226, 1029, 335, 336, 342, 343, 338,
1007, 339, 133, 106, 340, 341, 1001, 1,
9, 1025, 337, 344, 345, 1014, 105, 346,
347, 348, 349, 1030, 125, 101, 350, 192,
351, 352, 353, 354, 1002, 5, 18, 217,
355, 356, 153, 357, 358, 359, 360, 38,
361, 362, 199, 194, 363, 364, 365, 1003,
};
/// <summary>
/// This contains a list of all available BrickColors on Roblox.
/// </summary>
public static IReadOnlyCollection<BrickColor> ColorMap = new List<BrickColor>()
{
new BrickColor( 1, 0xF2F3F3, "White"),
new BrickColor( 2, 0xA1A5A2, "Grey"),
new BrickColor( 3, 0xF9E999, "Light yellow"),
new BrickColor( 5, 0xD7C59A, "Brick yellow"),
new BrickColor( 6, 0xC2DAB8, "Light green (Mint)"),
new BrickColor( 9, 0xE8BAC8, "Light reddish violet"),
new BrickColor( 11, 0x80BBDB, "Pastel Blue"),
new BrickColor( 12, 0xCB8442, "Light orange brown"),
new BrickColor( 18, 0xCC8E69, "Nougat"),
new BrickColor( 21, 0xC4281C, "Bright red"),
new BrickColor( 22, 0xC470A0, "Med. reddish violet"),
new BrickColor( 23, 0x0D69AC, "Bright blue"),
new BrickColor( 24, 0xF5CD30, "Bright yellow"),
new BrickColor( 25, 0x624732, "Earth orange"),
new BrickColor( 26, 0x1B2A35, "Black"),
new BrickColor( 27, 0x6D6E6C, "Dark grey"),
new BrickColor( 28, 0x287F47, "Dark green"),
new BrickColor( 29, 0xA1C48C, "Medium green"),
new BrickColor( 36, 0xF3CF9B, "Lig. Yellowich orange"),
new BrickColor( 37, 0x4B974B, "Bright green"),
new BrickColor( 38, 0xA05F35, "Dark orange"),
new BrickColor( 39, 0xC1CADE, "Light bluish violet"),
new BrickColor( 40, 0xECECEC, "Transparent"),
new BrickColor( 41, 0xCD544B, "Tr. Red"),
new BrickColor( 42, 0xC1DFF0, "Tr. Lg blue"),
new BrickColor( 43, 0x7BB6E8, "Tr. Blue"),
new BrickColor( 44, 0xF7F18D, "Tr. Yellow"),
new BrickColor( 45, 0xB4D2E4, "Light blue"),
new BrickColor( 47, 0xD9856C, "Tr. Flu. Reddish orange"),
new BrickColor( 48, 0x84B68D, "Tr. Green"),
new BrickColor( 49, 0xF8F184, "Tr. Flu. Green"),
new BrickColor( 50, 0xECE8DE, "Phosph. White"),
new BrickColor( 100, 0xEEC4B6, "Light red"),
new BrickColor( 101, 0xDA867A, "Medium red"),
new BrickColor( 102, 0x6E99CA, "Medium blue"),
new BrickColor( 103, 0xC7C1B7, "Light grey"),
new BrickColor( 104, 0x6B327C, "Bright violet"),
new BrickColor( 105, 0xE29B40, "Br. yellowish orange"),
new BrickColor( 106, 0xDA8541, "Bright orange"),
new BrickColor( 107, 0x008F9C, "Bright bluish green"),
new BrickColor( 108, 0x685C43, "Earth yellow"),
new BrickColor( 110, 0x435493, "Bright bluish violet"),
new BrickColor( 111, 0xBFB7B1, "Tr. Brown"),
new BrickColor( 112, 0x6874AC, "Medium bluish violet"),
new BrickColor( 113, 0xE5ADC8, "Tr. Medi. reddish violet"),
new BrickColor( 115, 0xC7D23C, "Med. yellowish green"),
new BrickColor( 116, 0x55A5AF, "Med. bluish green"),
new BrickColor( 118, 0xB7D7D5, "Light bluish green"),
new BrickColor( 119, 0xA4BD47, "Br. yellowish green"),
new BrickColor( 120, 0xD9E4A7, "Lig. yellowish green"),
new BrickColor( 121, 0xE7AC58, "Med. yellowish orange"),
new BrickColor( 123, 0xD36F4C, "Br. reddish orange"),
new BrickColor( 124, 0x923978, "Bright reddish violet"),
new BrickColor( 125, 0xEAB892, "Light orange"),
new BrickColor( 126, 0xA5A5CB, "Tr. Bright bluish violet"),
new BrickColor( 127, 0xDCBC81, "Gold"),
new BrickColor( 128, 0xAE7A59, "Dark nougat"),
new BrickColor( 131, 0x9CA3A8, "Silver"),
new BrickColor( 133, 0xD5733D, "Neon orange"),
new BrickColor( 134, 0xD8DD56, "Neon green"),
new BrickColor( 135, 0x74869D, "Sand blue"),
new BrickColor( 136, 0x877C90, "Sand violet"),
new BrickColor( 137, 0xE09864, "Medium orange"),
new BrickColor( 138, 0x958A73, "Sand yellow"),
new BrickColor( 140, 0x203A56, "Earth blue"),
new BrickColor( 141, 0x27462D, "Earth green"),
new BrickColor( 143, 0xCFE2F7, "Tr. Flu. Blue"),
new BrickColor( 145, 0x7988A1, "Sand blue metallic"),
new BrickColor( 146, 0x958EA3, "Sand violet metallic"),
new BrickColor( 147, 0x938767, "Sand yellow metallic"),
new BrickColor( 148, 0x575857, "Dark grey metallic"),
new BrickColor( 149, 0x161D32, "Black metallic"),
new BrickColor( 150, 0xABADAC, "Light grey metallic"),
new BrickColor( 151, 0x789082, "Sand green"),
new BrickColor( 153, 0x957977, "Sand red"),
new BrickColor( 154, 0x7B2E2F, "Dark red"),
new BrickColor( 157, 0xFFF67B, "Tr. Flu. Yellow"),
new BrickColor( 158, 0xE1A4C2, "Tr. Flu. Red"),
new BrickColor( 168, 0x756C62, "Gun metallic"),
new BrickColor( 176, 0x97695B, "Red flip/flop"),
new BrickColor( 178, 0xB48455, "Yellow flip/flop"),
new BrickColor( 179, 0x898788, "Silver flip/flop"),
new BrickColor( 180, 0xD7A94B, "Curry"),
new BrickColor( 190, 0xF9D62E, "Fire Yellow"),
new BrickColor( 191, 0xE8AB2D, "Flame yellowish orange"),
new BrickColor( 192, 0x694028, "Reddish brown"),
new BrickColor( 193, 0xCF6024, "Flame reddish orange"),
new BrickColor( 194, 0xA3A2A5, "Medium stone grey"),
new BrickColor( 195, 0x4667A4, "Royal blue"),
new BrickColor( 196, 0x23478B, "Dark Royal blue"),
new BrickColor( 198, 0x8E4285, "Bright reddish lilac"),
new BrickColor( 199, 0x635F62, "Dark stone grey"),
new BrickColor( 200, 0x828A5D, "Lemon metalic"),
new BrickColor( 208, 0xE5E4DF, "Light stone grey"),
new BrickColor( 209, 0xB08E44, "Dark Curry"),
new BrickColor( 210, 0x709578, "Faded green"),
new BrickColor( 211, 0x79B5B5, "Turquoise"),
new BrickColor( 212, 0x9FC3E9, "Light Royal blue"),
new BrickColor( 213, 0x6C81B7, "Medium Royal blue"),
new BrickColor( 216, 0x904C2A, "Rust"),
new BrickColor( 217, 0x7C5C46, "Brown"),
new BrickColor( 218, 0x96709F, "Reddish lilac"),
new BrickColor( 219, 0x6B629B, "Lilac"),
new BrickColor( 220, 0xA7A9CE, "Light lilac"),
new BrickColor( 221, 0xCD6298, "Bright purple"),
new BrickColor( 222, 0xE4ADC8, "Light purple"),
new BrickColor( 223, 0xDC9095, "Light pink"),
new BrickColor( 224, 0xF0D5A0, "Light brick yellow"),
new BrickColor( 225, 0xEBB87F, "Warm yellowish orange"),
new BrickColor( 226, 0xFDEA8D, "Cool yellow"),
new BrickColor( 232, 0x7DBBDD, "Dove blue"),
new BrickColor( 268, 0x342B75, "Medium lilac"),
new BrickColor( 301, 0x506D54, "Slime green"),
new BrickColor( 302, 0x5B5D69, "Smoky grey"),
new BrickColor( 303, 0x0010B0, "Dark blue"),
new BrickColor( 304, 0x2C651D, "Parsley green"),
new BrickColor( 305, 0x527CAE, "Steel blue"),
new BrickColor( 306, 0x335882, "Storm blue"),
new BrickColor( 307, 0x102ADC, "Lapis"),
new BrickColor( 308, 0x3D1585, "Dark indigo"),
new BrickColor( 309, 0x348E40, "Sea green"),
new BrickColor( 310, 0x5B9A4C, "Shamrock"),
new BrickColor( 311, 0x9FA1AC, "Fossil"),
new BrickColor( 312, 0x592259, "Mulberry"),
new BrickColor( 313, 0x1F801D, "Forest green"),
new BrickColor( 314, 0x9FADC0, "Cadet blue"),
new BrickColor( 315, 0x0989CF, "Electric blue"),
new BrickColor( 316, 0x7B007B, "Eggplant"),
new BrickColor( 317, 0x7C9C6B, "Moss"),
new BrickColor( 318, 0x8AAB85, "Artichoke"),
new BrickColor( 319, 0xB9C4B1, "Sage green"),
new BrickColor( 320, 0xCACBD1, "Ghost grey"),
new BrickColor( 321, 0xA75E9B, "Lilac"),
new BrickColor( 322, 0x7B2F7B, "Plum"),
new BrickColor( 323, 0x94BE81, "Olivine"),
new BrickColor( 324, 0xA8BD99, "Laurel green"),
new BrickColor( 325, 0xDFDFDE, "Quill grey"),
new BrickColor( 327, 0x970000, "Crimson"),
new BrickColor( 328, 0xB1E5A6, "Mint"),
new BrickColor( 329, 0x98C2DB, "Baby blue"),
new BrickColor( 330, 0xFF98DC, "Carnation pink"),
new BrickColor( 331, 0xFF5959, "Persimmon"),
new BrickColor( 332, 0x750000, "Maroon"),
new BrickColor( 333, 0xEFB838, "Gold"),
new BrickColor( 334, 0xF8D96D, "Daisy orange"),
new BrickColor( 335, 0xE7E7EC, "Pearl"),
new BrickColor( 336, 0xC7D4E4, "Fog"),
new BrickColor( 337, 0xFF9494, "Salmon"),
new BrickColor( 338, 0xBE6862, "Terra Cotta"),
new BrickColor( 339, 0x562424, "Cocoa"),
new BrickColor( 340, 0xF1E7C7, "Wheat"),
new BrickColor( 341, 0xFEF3BB, "Buttermilk"),
new BrickColor( 342, 0xE0B2D0, "Mauve"),
new BrickColor( 343, 0xD490BD, "Sunrise"),
new BrickColor( 344, 0x965555, "Tawny"),
new BrickColor( 345, 0x8F4C2A, "Rust"),
new BrickColor( 346, 0xD3BE96, "Cashmere"),
new BrickColor( 347, 0xE2DCBC, "Khaki"),
new BrickColor( 348, 0xEDEAEA, "Lily white"),
new BrickColor( 349, 0xE9DADA, "Seashell"),
new BrickColor( 350, 0x883E3E, "Burgundy"),
new BrickColor( 351, 0xBC9B5D, "Cork"),
new BrickColor( 352, 0xC7AC78, "Burlap"),
new BrickColor( 353, 0xCABFA3, "Beige"),
new BrickColor( 354, 0xBBB3B2, "Oyster"),
new BrickColor( 355, 0x6C584B, "Pine Cone"),
new BrickColor( 356, 0xA0844F, "Fawn brown"),
new BrickColor( 357, 0x958988, "Hurricane grey"),
new BrickColor( 358, 0xABA89E, "Cloudy grey"),
new BrickColor( 359, 0xAF9483, "Linen"),
new BrickColor( 360, 0x966766, "Copper"),
new BrickColor( 361, 0x564236, "Dirt brown"),
new BrickColor( 362, 0x7E683F, "Bronze"),
new BrickColor( 363, 0x69665C, "Flint"),
new BrickColor( 364, 0x5A4C42, "Dark taupe"),
new BrickColor( 365, 0x6A3909, "Burnt Sienna"),
new BrickColor(1001, 0xF8F8F8, "Institutional white"),
new BrickColor(1002, 0xCDCDCD, "Mid gray"),
new BrickColor(1003, 0x111111, "Really black"),
new BrickColor(1004, 0xFF0000, "Really red"),
new BrickColor(1005, 0xFFB000, "Deep orange"),
new BrickColor(1006, 0xB480FF, "Alder"),
new BrickColor(1007, 0xA34B4B, "Dusty Rose"),
new BrickColor(1008, 0xC1BE42, "Olive"),
new BrickColor(1009, 0xFFFF00, "New Yeller"),
new BrickColor(1010, 0x0000FF, "Really blue"),
new BrickColor(1011, 0x002060, "Navy blue"),
new BrickColor(1012, 0x2154B9, "Deep blue"),
new BrickColor(1013, 0x04AFEC, "Cyan"),
new BrickColor(1014, 0xAA5500, "CGA brown"),
new BrickColor(1015, 0xAA00AA, "Magenta"),
new BrickColor(1016, 0xFF66CC, "Pink"),
new BrickColor(1017, 0xFFAF00, "Deep orange"),
new BrickColor(1018, 0x12EED4, "Teal"),
new BrickColor(1019, 0x00FFFF, "Toothpaste"),
new BrickColor(1020, 0x00FF00, "Lime green"),
new BrickColor(1021, 0x3A7D15, "Camo"),
new BrickColor(1022, 0x7F8E64, "Grime"),
new BrickColor(1023, 0x8C5B9F, "Lavender"),
new BrickColor(1024, 0xAFDDFF, "Pastel light blue"),
new BrickColor(1025, 0xFFC9C9, "Pastel orange"),
new BrickColor(1026, 0xB1A7FF, "Pastel violet"),
new BrickColor(1027, 0x9FF3E9, "Pastel blue-green"),
new BrickColor(1028, 0xCCFFCC, "Pastel green"),
new BrickColor(1029, 0xFFFFCC, "Pastel yellow"),
new BrickColor(1030, 0xFFCC99, "Pastel brown"),
new BrickColor(1031, 0x6225D1, "Royal purple"),
new BrickColor(1032, 0xFF00BF, "Hot pink"),
};
}
}

View File

@ -0,0 +1,128 @@
using System.Collections.Generic;
using Roblox.Enums;
namespace Roblox.DataTypes.Utility
{
public static class MaterialInfo
{
public static IReadOnlyDictionary<Material, float> DensityMap = new Dictionary<Material, float>()
{
{Material.Air, 0.01f},
{Material.Asphalt, 2.36f},
{Material.Basalt, 2.69f},
{Material.Brick, 1.92f},
{Material.Cobblestone, 2.69f},
{Material.Concrete, 2.40f},
{Material.CorrodedMetal, 7.85f},
{Material.CrackedLava, 2.69f},
{Material.DiamondPlate, 7.85f},
{Material.Fabric, 0.70f},
{Material.Foil, 2.70f},
{Material.Glacier, 0.92f},
{Material.Glass, 2.40f},
{Material.Granite, 2.69f},
{Material.Grass, 0.90f},
{Material.Ground, 0.90f},
{Material.Ice, 0.92f},
{Material.LeafyGrass, 0.90f},
{Material.Limestone, 2.69f},
{Material.Marble, 2.56f},
{Material.Metal, 7.85f},
{Material.Mud, 0.90f},
{Material.Neon, 0.70f},
{Material.Pavement, 2.69f},
{Material.Pebble, 2.40f},
{Material.Plastic, 0.70f},
{Material.Rock, 2.69f},
{Material.Salt, 2.16f},
{Material.Sand, 1.60f},
{Material.Sandstone, 2.69f},
{Material.Slate, 2.69f},
{Material.SmoothPlastic, 0.70f},
{Material.Snow, 0.90f},
{Material.Water, 1.00f},
{Material.Wood, 0.35f},
{Material.WoodPlanks, 0.35f},
};
public static IReadOnlyDictionary<Material, float> ElasticityMap = new Dictionary<Material, float>()
{
{Material.Air, 0.01f},
{Material.Asphalt, 0.20f},
{Material.Basalt, 0.15f},
{Material.Brick, 0.15f},
{Material.Cobblestone, 0.17f},
{Material.Concrete, 0.20f},
{Material.CorrodedMetal, 0.20f},
{Material.CrackedLava, 0.15f},
{Material.DiamondPlate, 0.25f},
{Material.Fabric, 0.05f},
{Material.Foil, 0.25f},
{Material.Glacier, 0.15f},
{Material.Glass, 0.20f},
{Material.Granite, 0.20f},
{Material.Grass, 0.10f},
{Material.Ground, 0.10f},
{Material.Ice, 0.15f},
{Material.LeafyGrass, 0.10f},
{Material.Limestone, 0.15f},
{Material.Marble, 0.17f},
{Material.Metal, 0.25f},
{Material.Mud, 0.07f},
{Material.Neon, 0.20f},
{Material.Pavement, 0.17f},
{Material.Pebble, 0.17f},
{Material.Plastic, 0.50f},
{Material.Rock, 0.17f},
{Material.Salt, 0.05f},
{Material.Sand, 0.05f},
{Material.Sandstone, 0.15f},
{Material.Slate, 0.20f},
{Material.SmoothPlastic, 0.50f},
{Material.Snow, 0.03f},
{Material.Water, 0.01f},
{Material.Wood, 0.20f},
{Material.WoodPlanks, 0.20f},
};
public static IReadOnlyDictionary<Material, float> FrictionMap = new Dictionary<Material, float>()
{
{Material.Air, 0.01f},
{Material.Asphalt, 0.80f},
{Material.Basalt, 0.70f},
{Material.Brick, 0.80f},
{Material.Cobblestone, 0.50f},
{Material.Concrete, 0.70f},
{Material.CorrodedMetal, 0.70f},
{Material.CrackedLava, 0.65f},
{Material.DiamondPlate, 0.35f},
{Material.Fabric, 0.35f},
{Material.Foil, 0.40f},
{Material.Glacier, 0.05f},
{Material.Glass, 0.25f},
{Material.Granite, 0.40f},
{Material.Grass, 0.40f},
{Material.Ground, 0.45f},
{Material.Ice, 0.02f},
{Material.LeafyGrass, 0.40f},
{Material.Limestone, 0.50f},
{Material.Marble, 0.20f},
{Material.Metal, 0.40f},
{Material.Mud, 0.30f},
{Material.Neon, 0.30f},
{Material.Pavement, 0.50f},
{Material.Pebble, 0.40f},
{Material.Plastic, 0.30f},
{Material.Rock, 0.50f},
{Material.Salt, 0.50f},
{Material.Sand, 0.50f},
{Material.Sandstone, 0.50f},
{Material.Slate, 0.40f},
{Material.SmoothPlastic, 0.20f},
{Material.Snow, 0.30f},
{Material.Water, 0.00f},
{Material.Wood, 0.48f},
{Material.WoodPlanks, 0.48f},
};
}
}

View File

@ -0,0 +1,207 @@
using System;
namespace Roblox.DataTypes.Utility
{
public class Quaternion
{
public readonly float X;
public readonly float Y;
public readonly float Z;
public readonly float W;
public float Magnitude
{
get
{
float squared = Dot(this);
double magnitude = Math.Sqrt(squared);
return (float)magnitude;
}
}
public Quaternion(float x, float y, float z, float w)
{
X = x;
Y = y;
Z = z;
W = w;
}
public Quaternion(Vector3 qv, float qw)
{
X = qv.X;
Y = qv.Y;
Z = qv.Z;
W = qw;
}
public Quaternion(CFrame cf)
{
CFrame matrix = (cf - cf.Position);
float[] ac = cf.GetComponents();
float m41 = ac[0], m42 = ac[1], m43 = ac[2],
m11 = ac[3], m12 = ac[4], m13 = ac[5],
m21 = ac[6], m22 = ac[7], m23 = ac[8],
m31 = ac[9], m32 = ac[10], m33 = ac[11];
float trace = m11 + m22 + m33;
if (trace > 0)
{
float s = (float)Math.Sqrt(1 + trace);
float r = 0.5f / s;
W = s * 0.5f;
X = (m32 - m23) * r;
Y = (m13 - m31) * r;
Z = (m21 - m12) * r;
}
else
{
float big = Math.Max(Math.Max(m11, m22), m33);
if (big == m11)
{
float s = (float)Math.Sqrt(1 + m11 - m22 - m33);
float r = 0.5f / s;
W = (m32 - m23) * r;
X = 0.5f * s;
Y = (m21 + m12) * r;
Z = (m13 + m31) * r;
}
else if (big == m22)
{
float s = (float)Math.Sqrt(1 - m11 + m22 - m33);
float r = 0.5f / s;
W = (m13 - m31) * r;
X = (m21 + m12) * r;
Y = 0.5f * s;
Z = (m32 + m23) * r;
}
else if (big == m33)
{
float s = (float)Math.Sqrt(1 - m11 - m22 + m33);
float r = 0.5f / s;
W = (m21 - m12) * r;
X = (m13 + m31) * r;
Y = (m32 + m23) * r;
Z = 0.5f * s;
}
}
}
public float Dot(Quaternion other)
{
return (X * other.X) + (Y * other.Y) + (Z * other.Z) + (W * other.W);
}
public Quaternion Lerp(Quaternion other, float alpha)
{
Quaternion result = this * (1.0f - alpha) + other * alpha;
return result / result.Magnitude;
}
public Quaternion Slerp(Quaternion other, float alpha)
{
float cosAng = Dot(other);
if (cosAng < 0)
{
other = -other;
cosAng = -cosAng;
}
double ang = Math.Acos(cosAng);
if (ang >= 0.05f)
{
float scale0 = (float)Math.Sin((1.0f - alpha) * ang);
float scale1 = (float)Math.Sin(alpha * ang);
float denom = (float)Math.Sin(ang);
return ((this * scale0) + (other * scale1)) / denom;
}
else
{
return Lerp(other, alpha);
}
}
public CFrame ToCFrame()
{
float xc = X * 2f;
float yc = Y * 2f;
float zc = Z * 2f;
float xx = X * xc;
float xy = X * yc;
float xz = X * zc;
float wx = W * xc;
float wy = W * yc;
float wz = W * zc;
float yy = Y * yc;
float yz = Y * zc;
float zz = Z * zc;
return new CFrame
(
0, 0, 0,
1f - (yy + zz),
xy - wz,
xz + wy,
xy + wz,
1f - (xx + zz),
yz - wx,
xz - wy,
yz + wx,
1f - (xx + yy)
);
}
public static Quaternion operator +(Quaternion a, Quaternion b)
{
return new Quaternion(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W);
}
public static Quaternion operator -(Quaternion a, Quaternion b)
{
return new Quaternion(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W);
}
public static Quaternion operator *(Quaternion a, float f)
{
return new Quaternion(a.X * f, a.Y * f, a.Z * f, a.W * f);
}
public static Quaternion operator /(Quaternion a, float f)
{
return new Quaternion(a.X / f, a.Y / f, a.Z / f, a.W / f);
}
public static Quaternion operator -(Quaternion a)
{
return new Quaternion(-a.X, -a.Y, -a.Z, -a.W);
}
public static Quaternion operator *(Quaternion a, Quaternion b)
{
Vector3 v1 = new Vector3(a.X, a.Y, a.Z);
float s1 = a.W;
Vector3 v2 = new Vector3(b.X, b.Y, b.Z);
float s2 = b.W;
return new Quaternion(s1 * v2 + s2 * v1 + v1.Cross(v2), s1 * s2 - v1.Dot(v2));
}
}
}

100
DataTypes/Vector2.cs Normal file
View File

@ -0,0 +1,100 @@
using System;
namespace Roblox.DataTypes
{
public struct Vector2
{
public readonly float X, Y;
public float Magnitude
{
get
{
float product = Dot(this);
double magnitude = Math.Sqrt(product);
return (float)magnitude;
}
}
public Vector2 Unit
{
get { return this / Magnitude; }
}
public Vector2(float x = 0, float y = 0)
{
X = x;
Y = y;
}
public Vector2(float[] coords)
{
X = coords.Length > 0 ? coords[0] : 0;
Y = coords.Length > 1 ? coords[1] : 0;
}
private delegate Vector2 Operator(Vector2 a, Vector2 b);
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)
{
Vector2 numVec = new Vector2(num, num);
return upcast(numVec, vec);
}
private static Operator add = new Operator((a, b) => new Vector2(a.X + b.X, a.Y + b.Y));
private static Operator sub = new Operator((a, b) => new Vector2(a.X - b.X, a.Y - b.Y));
private static Operator mul = new Operator((a, b) => new Vector2(a.X * b.X, a.Y * b.Y));
private static 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 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 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 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 Zero => new Vector2(0, 0);
public override string ToString()
{
return string.Join(", ", X, Y);
}
public float Dot(Vector2 other)
{
float dotX = X * other.X;
float dotY = Y * other.Y;
return dotX + dotY;
}
public Vector2 Cross(Vector2 other)
{
float crossX = X * other.Y;
float crossY = Y * other.X;
return new Vector2(crossX, crossY);
}
public Vector2 Lerp(Vector2 other, float t)
{
return this + (other - this) * t;
}
}
}

133
DataTypes/Vector3.cs Normal file
View File

@ -0,0 +1,133 @@
using System;
using Roblox.Enums;
namespace Roblox.DataTypes
{
public struct Vector3
{
public readonly float X, Y, Z;
public float Magnitude
{
get
{
float product = Dot(this);
double magnitude = Math.Sqrt(product);
return (float)magnitude;
}
}
public Vector3 Unit
{
get { return this / Magnitude; }
}
public Vector3(float x = 0, float y = 0, float z = 0)
{
X = x;
Y = y;
Z = z;
}
public Vector3(float[] coords)
{
X = coords.Length > 0 ? coords[0] : 0;
Y = coords.Length > 1 ? coords[1] : 0;
Z = coords.Length > 2 ? coords[2] : 0;
}
public static Vector3 FromAxis(Axis axis)
{
float[] coords = new float[3] { 0f, 0f, 0f };
int index = (int)axis;
coords[index] = 1f;
return new Vector3(coords);
}
public static Vector3 FromNormalId(NormalId normalId)
{
float[] coords = new float[3] { 0f, 0f, 0f };
int index = (int)normalId;
coords[index % 3] = (index > 2 ? -1f : 1f);
return new Vector3(coords);
}
private delegate Vector3 Operator(Vector3 a, Vector3 b);
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)
{
Vector3 numVec = new Vector3(num, num, num);
return upcast(numVec, vec);
}
private static Operator add = new Operator((a, b) => new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z));
private static Operator sub = new Operator((a, b) => new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z));
private static Operator mul = new Operator((a, b) => new Vector3(a.X * b.X, a.Y * b.Y, a.Z * b.Z));
private static 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 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 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 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 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 override string ToString()
{
return string.Join(", ", X, Y, Z);
}
public float Dot(Vector3 other)
{
float dotX = X * other.X;
float dotY = Y * other.Y;
float dotZ = Z * other.Z;
return dotX + dotY + dotZ;
}
public Vector3 Cross(Vector3 other)
{
float crossX = Y * other.Z - other.Y * Z;
float crossY = Z * other.X - other.Z * X;
float crossZ = X * other.Y - other.X * Y;
return new Vector3(crossX, crossY, crossZ);
}
public Vector3 Lerp(Vector3 other, float t)
{
return this + (other - this) * t;
}
public bool isClose(Vector3 other, float epsilon = 0.0f)
{
return (other - this).Magnitude <= Math.Abs(epsilon);
}
}
}

69
DataTypes/Vector3int16.cs Normal file
View File

@ -0,0 +1,69 @@
using System;
namespace Roblox.DataTypes
{
public struct Vector3int16
{
public readonly short X, Y, Z;
public Vector3int16(short x = 0, short y = 0, short z = 0)
{
X = x;
Y = y;
Z = z;
}
public Vector3int16(int x = 0, int y = 0, int z = 0)
{
X = (short)x;
Y = (short)y;
Z = (short)z;
}
public override string ToString()
{
return string.Join(", ", X, Y, Z);
}
private delegate Vector3int16 Operator(Vector3int16 a, Vector3int16 b);
private static Vector3int16 upcastShortOp(Vector3int16 vec, short num, Operator upcast)
{
Vector3int16 numVec = new Vector3int16(num, num, num);
return upcast(vec, numVec);
}
private static Vector3int16 upcastShortOp(short num, Vector3int16 vec, Operator upcast)
{
Vector3int16 numVec = new Vector3int16(num, num, num);
return upcast(numVec, vec);
}
private static Operator add = new Operator((a, b) => new Vector3int16(a.X + b.X, a.Y + b.Y, a.Z + b.Z));
private static Operator sub = new Operator((a, b) => new Vector3int16(a.X - b.X, a.Y - b.Y, a.Z - b.Z));
private static Operator mul = new Operator((a, b) => new Vector3int16(a.X * b.X, a.Y * b.Y, a.Z * b.Z));
private static Operator div = new Operator((a, b) =>
{
if (b.X == 0 || b.Y == 0 || b.Z == 0)
throw new DivideByZeroException();
return new Vector3int16(a.X / b.X, a.Y / b.Y, a.Z / b.Z);
});
public static Vector3int16 operator +(Vector3int16 a, Vector3int16 b) => add(a, b);
public static Vector3int16 operator +(Vector3int16 v, short n) => upcastShortOp(v, n, add);
public static Vector3int16 operator +(short n, Vector3int16 v) => upcastShortOp(n, v, add);
public static Vector3int16 operator -(Vector3int16 a, Vector3int16 b) => sub(a, b);
public static Vector3int16 operator -(Vector3int16 v, short n) => upcastShortOp(v, n, sub);
public static Vector3int16 operator -(short n, Vector3int16 v) => upcastShortOp(n, v, sub);
public static Vector3int16 operator *(Vector3int16 a, Vector3int16 b) => mul(a, b);
public static Vector3int16 operator *(Vector3int16 v, short n) => upcastShortOp(v, n, mul);
public static Vector3int16 operator *(short n, Vector3int16 v) => upcastShortOp(n, v, mul);
public static Vector3int16 operator /(Vector3int16 a, Vector3int16 b) => div(a, b);
public static Vector3int16 operator /(Vector3int16 v, short n) => upcastShortOp(v, n, div);
public static Vector3int16 operator /(short n, Vector3int16 v) => upcastShortOp(n, v, div);
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RobloxFileFormat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RobloxFileFormat")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("cf50c0e2-23a7-4dc1-b4b2-e60cde716253")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

99
RobloxFileFormat.csproj Normal file
View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Roblox</RootNamespace>
<AssemblyName>RobloxFileFormat</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="LZ4, Version=1.0.15.93, Culture=neutral, PublicKeyToken=62e1b5ec1eec9bdd, processorArchitecture=MSIL">
<HintPath>packages\lz4net.1.0.15.93\lib\net4-client\LZ4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BinaryFormat\Chunk.cs" />
<Compile Include="BinaryFormat\BinaryFile.cs" />
<Compile Include="BinaryFormat\ChunkTypes\INST.cs" />
<Compile Include="BinaryFormat\ChunkTypes\META.cs" />
<Compile Include="BinaryFormat\ChunkTypes\PRNT.cs" />
<Compile Include="BinaryFormat\ChunkTypes\PROP.cs" />
<Compile Include="BinaryFormat\Reader.cs" />
<Compile Include="Core\Property.cs" />
<Compile Include="DataTypes\Axes.cs" />
<Compile Include="DataTypes\BrickColor.cs" />
<Compile Include="DataTypes\CFrame.cs" />
<Compile Include="DataTypes\Color3.cs" />
<Compile Include="DataTypes\ColorSequence.cs" />
<Compile Include="DataTypes\ColorSequenceKeypoint.cs" />
<Compile Include="DataTypes\Faces.cs" />
<Compile Include="DataTypes\NumberRange.cs" />
<Compile Include="DataTypes\NumberSequence.cs" />
<Compile Include="DataTypes\NumberSequenceKeypoint.cs" />
<Compile Include="DataTypes\PathWaypoint.cs" />
<Compile Include="DataTypes\PhysicalProperties.cs" />
<Compile Include="DataTypes\Ray.cs" />
<Compile Include="DataTypes\Region3int16.cs" />
<Compile Include="DataTypes\Utility\BrickColors.cs" />
<Compile Include="DataTypes\Vector3int16.cs" />
<Compile Include="Core\Enums.cs" />
<Compile Include="DataTypes\Utility\MaterialInfo.cs" />
<Compile Include="DataTypes\Utility\Quaternion.cs" />
<Compile Include="DataTypes\Rect.cs" />
<Compile Include="DataTypes\Region3.cs" />
<Compile Include="DataTypes\UDim.cs" />
<Compile Include="DataTypes\UDim2.cs" />
<Compile Include="DataTypes\Vector2.cs" />
<Compile Include="DataTypes\Vector3.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Core\RobloxFile.cs" />
<Compile Include="Core\Instance.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

22
RobloxFileFormat.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobloxFileFormat", "RobloxFileFormat.csproj", "{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

4
packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="lz4net" version="1.0.15.93" targetFramework="net452" />
</packages>