0.604.0.6040508

This commit is contained in:
Max 2023-11-28 21:07:30 -06:00
parent 9f4f3bbf63
commit 4bac4d4f3e
17 changed files with 6548 additions and 5027 deletions

View File

@ -39,7 +39,7 @@ namespace RobloxFiles
public IReadOnlyDictionary<uint, SharedString> SharedStrings => SSTR?.Strings;
public bool HasSignatures => (SIGN != null);
public IReadOnlyList<Signature> Signatures => SIGN?.Signatures;
public IReadOnlyList<RbxSignature> Signatures => SIGN?.Signatures;
public BinaryRobloxFile()
{

View File

@ -74,7 +74,7 @@ namespace RobloxFiles.BinaryFormat.Chunks
var prop = new Property(instance, this);
props[i] = prop;
instance.AddProperty(ref prop);
instance.AddProperty(prop);
}
// Setup some short-hand functions for actions used during the read procedure.
@ -103,7 +103,7 @@ namespace RobloxFiles.BinaryFormat.Chunks
string value = reader.ReadString();
// Leave an access point for the original byte sequence, in case this is a BinaryString.
// This will allow the developer to read the sequence without any mangling from C# strings.
// This will allow the developer to read the sequence without any mangling from UTF-8.
byte[] buffer = reader.GetLastStringBuffer();
props[i].RawBuffer = buffer;
@ -132,6 +132,8 @@ namespace RobloxFiles.BinaryFormat.Chunks
if (memberType == typeof(byte[]))
result = buffer;
else if (memberType == typeof(ProtectedString) && File.HasSignatures)
result = new ProtectedString(buffer); // Very likely compiled.
return result;
}
@ -661,6 +663,12 @@ namespace RobloxFiles.BinaryFormat.Chunks
break;
}
case PropertyType.SecurityCapabilities:
{
var capabilities = reader.ReadInterleaved(instCount, BitConverter.ToUInt64);
readProperties(i => capabilities[i]);
break;
}
default:
{
RobloxFile.LogError($"Unhandled property type: {Type} in {this}!");
@ -1301,6 +1309,20 @@ namespace RobloxFiles.BinaryFormat.Chunks
break;
}
case PropertyType.SecurityCapabilities:
{
// FIXME: Verify this is correct once we know what SecurityCapabilities actually does.
var capabilities = new List<ulong>();
props.ForEach(prop =>
{
var value = prop.CastValue<ulong>();
capabilities.Add(value);
});
writer.WriteInterleaved(capabilities);
break;
}
default:
{
RobloxFile.LogError($"Unhandled property type: {Type} in {this}!");

View File

@ -3,35 +3,37 @@ using System.Text;
namespace RobloxFiles.BinaryFormat.Chunks
{
public struct Signature
public enum RbxSignatureType
{
public int Version;
public long Id;
Ed25519
}
public int Length;
public byte[] Data;
public struct RbxSignature
{
public RbxSignatureType SignatureType;
public long PublicKeyId;
public byte[] Value;
}
public class SIGN : IBinaryFileChunk
{
public Signature[] Signatures;
public RbxSignature[] Signatures;
public void Load(BinaryRobloxFileReader reader)
{
int numSignatures = reader.ReadInt32();
Signatures = new Signature[numSignatures];
Signatures = new RbxSignature[numSignatures];
for (int i = 0; i < numSignatures; i++)
{
var signature = new Signature
var signature = new RbxSignature
{
Version = reader.ReadInt32(),
Id = reader.ReadInt64(),
Length = reader.ReadInt32(),
SignatureType = (RbxSignatureType)reader.ReadInt32(),
PublicKeyId = reader.ReadInt64(),
};
signature.Data = reader.ReadBytes(signature.Length);
var length = reader.ReadInt32();
signature.Value = reader.ReadBytes(length);
Signatures[i] = signature;
}
@ -46,13 +48,12 @@ namespace RobloxFiles.BinaryFormat.Chunks
for (int i = 0; i < Signatures.Length; i++)
{
var signature = Signatures[i];
signature.Length = signature.Data.Length;
writer.Write(signature.Version);
writer.Write(signature.Id);
writer.Write((int)signature.SignatureType);
writer.Write(signature.PublicKeyId);
writer.Write(signature.Length);
writer.Write(signature.Data);
writer.Write(signature.Value.Length);
writer.Write(signature.Value);
}
}
@ -66,17 +67,14 @@ namespace RobloxFiles.BinaryFormat.Chunks
var signature = Signatures[i];
builder.AppendLine($"## Signature {i}");
var version = signature.Version;
builder.AppendLine($"- Version: {version}");
var version = Enum.GetName(typeof(RbxSignatureType), signature.SignatureType);
builder.AppendLine($"- SignatureType: {version}");
var id = signature.Id;
builder.AppendLine($"- Id: {id}");
var publicKeyId = signature.PublicKeyId;
builder.AppendLine($"- PublicKeyId: {publicKeyId}");
var length = signature.Length;
builder.AppendLine($"- Length: {length}");
var data = Convert.ToBase64String(signature.Data);
builder.AppendLine($"- Data: {data}");
var value = Convert.ToBase64String(signature.Value);
builder.AppendLine($"- Value: {value}");
}
}
}

View File

@ -28,7 +28,15 @@ namespace RobloxFiles.DataTypes
public ProtectedString(byte[] compiled)
{
// This'll break in the future if Luau ever has more than 32 VM versions.
// Feels pretty unlikely this'll happen anytime soon, if ever.
IsCompiled = true;
if (compiled.Length > 0)
if (compiled[0] >= 32)
IsCompiled = false;
RawBuffer = compiled;
}

View File

@ -1,5 +1,5 @@
// Auto-generated list of creatable Roblox classes.
// Updated as of 0.600.1.6000716
// Updated as of 0.604.0.6040508
using System;
@ -22,6 +22,14 @@ namespace RobloxFiles
public float Puffiness = 1;
}
public class AccountService : Instance
{
public AccountService()
{
IsService = true;
}
}
public class Accoutrement : Instance
{
public CFrame AttachmentPoint = CFrame.identity;
@ -406,6 +414,18 @@ namespace RobloxFiles
public VirtualCursorMode VirtualCursorMode = VirtualCursorMode.Default;
}
public abstract class BaseRemoteEvent : Instance
{
}
public class RemoteEvent : BaseRemoteEvent
{
}
public class UnreliableRemoteEvent : BaseRemoteEvent
{
}
public abstract class BaseWrap : Instance
{
public Content CageMeshId = "";
@ -893,7 +913,7 @@ namespace RobloxFiles
public class AlignOrientation : Constraint
{
public AlignType AlignType = AlignType.Parallel;
public AlignType AlignType = AlignType.AllAxes;
public CFrame CFrame = CFrame.identity;
public float MaxAngularVelocity = float.MaxValue;
public float MaxTorque = 10000;
@ -1360,7 +1380,7 @@ namespace RobloxFiles
{
}
public class DynamicMesh : DataModelMesh
public class EditableMesh : DataModelMesh
{
public int MeshVersion = 0;
}
@ -1483,7 +1503,7 @@ namespace RobloxFiles
}
}
public class DynamicImage : Instance
public class EditableImage : Instance
{
public Vector2 Size = new Vector2(512, 512);
}
@ -1917,6 +1937,8 @@ namespace RobloxFiles
}
public float LineHeight = 1;
public string LocalizationMatchIdentifier = "";
public string LocalizationMatchedSourceText = "";
public int MaxVisibleGraphemes = -1;
public bool RichText;
public string Text = "Button";
@ -1999,6 +2021,8 @@ namespace RobloxFiles
}
public float LineHeight = 1;
public string LocalizationMatchIdentifier = "";
public string LocalizationMatchedSourceText = "";
public int MaxVisibleGraphemes = -1;
public bool RichText;
public string Text = "Label";
@ -2083,6 +2107,8 @@ namespace RobloxFiles
}
public float LineHeight = 1;
public string LocalizationMatchIdentifier = "";
public string LocalizationMatchedSourceText = "";
public int MaxVisibleGraphemes = -1;
public bool MultiLine;
public Color3 PlaceholderColor3 = Color3.FromRGB(178, 178, 178);
@ -2614,14 +2640,6 @@ namespace RobloxFiles
public bool AllowInsertFreeModels;
}
public class InternalSyncService : Instance
{
public InternalSyncService()
{
IsService = true;
}
}
public abstract class JointInstance : Instance
{
public CFrame C0 = CFrame.identity;
@ -3084,7 +3102,7 @@ namespace RobloxFiles
}
}
public class OperationTree : Instance
public class OperationGraph : Instance
{
}
@ -3590,6 +3608,7 @@ namespace RobloxFiles
public MeshPartHeadsAndAccessories MeshPartHeadsAndAccessories = MeshPartHeadsAndAccessories.Default;
public ModelStreamingBehavior ModelStreamingBehavior = ModelStreamingBehavior.Default;
public PhysicsSteppingMethod PhysicsSteppingMethod = PhysicsSteppingMethod.Default;
public PlayerCharacterDestroyBehavior PlayerCharacterDestroyBehavior = PlayerCharacterDestroyBehavior.Default;
public PrimalPhysicsSolver PrimalPhysicsSolver = PrimalPhysicsSolver.Default;
public RejectCharacterDeletions RejectCharacterDeletions = RejectCharacterDeletions.Default;
public ReplicateInstanceDestroySetting ReplicateInstanceDestroySetting = ReplicateInstanceDestroySetting.Default;
@ -3611,8 +3630,10 @@ namespace RobloxFiles
public class PackageLink : Instance
{
public bool AutoUpdate;
public string DefaultName = "";
public int ModifiedState = 0;
public Content PackageIdSerialize = "";
public byte[] SerializedDefaultAttributes;
public long VersionIdSerialize = 0;
}
@ -3683,14 +3704,6 @@ namespace RobloxFiles
public float ZOffset = 0;
}
public class PatchBundlerFileWatch : Instance
{
public PatchBundlerFileWatch()
{
IsService = true;
}
}
public class PathfindingLink : Instance
{
public Attachment Attachment0;
@ -4061,10 +4074,6 @@ namespace RobloxFiles
}
}
public class RemoteEvent : Instance
{
}
public class RemoteFunction : Instance
{
}
@ -4399,6 +4408,7 @@ namespace RobloxFiles
public NumberRange LoopRegion = new NumberRange(0, 60000);
public bool Looped;
[Obsolete]
public float MinDistance
{
get => EmitterSize;
@ -4422,8 +4432,11 @@ namespace RobloxFiles
public Content SoundId = "";
public double TimePosition = 0;
public float Volume = 0.5f;
[Obsolete]
public float xmlRead_MaxDistance_3 = 10000;
[Obsolete]
public float xmlRead_MinDistance_3
{
get => EmitterSize;
@ -4607,6 +4620,7 @@ namespace RobloxFiles
public HumanoidStateMachineMode HumanoidStateMachineMode = HumanoidStateMachineMode.Default;
public bool LoadCharacterAppearance = true;
public LoadCharacterLayeredClothing LoadCharacterLayeredClothing = LoadCharacterLayeredClothing.Default;
public CharacterControlMode LuaCharacterController = CharacterControlMode.Default;
public float NameDisplayDistance = 100;
public bool UserEmotesEnabled = true;
}
@ -4667,6 +4681,8 @@ namespace RobloxFiles
{
IsService = true;
}
public bool PublishLocked;
}
public class StudioSdkService : Instance
@ -4800,6 +4816,14 @@ namespace RobloxFiles
public bool CustomizedTeleportUI;
}
public class TemporaryCageMeshProvider : Instance
{
public TemporaryCageMeshProvider()
{
IsService = true;
}
}
public class TemporaryScriptService : Instance
{
public TemporaryScriptService()
@ -4945,6 +4969,14 @@ namespace RobloxFiles
}
}
public class TextureGenerationMeshHandler : Instance
{
public TextureGenerationMeshHandler()
{
IsService = true;
}
}
public class TimerService : Instance
{
public TimerService()
@ -5408,6 +5440,14 @@ namespace RobloxFiles
}
}
public class VoiceChatInternal : Instance
{
public VoiceChatInternal()
{
IsService = true;
}
}
public class VoiceChatService : Instance
{
public VoiceChatService()
@ -5416,6 +5456,7 @@ namespace RobloxFiles
}
public bool EnableDefaultVoice = true;
public AudioApiRollout UseAudioApi = AudioApiRollout.Automatic;
}
public class WeldConstraint : Instance

View File

@ -1,5 +1,5 @@
// Auto-generated list of Roblox enums.
// Updated as of 0.600.1.6000716
// Updated as of 0.604.0.6040508
namespace RobloxFiles.Enums
{
@ -61,7 +61,11 @@ namespace RobloxFiles.Enums
public enum AlignType
{
Parallel,
Perpendicular
Perpendicular,
PrimaryAxisParallel,
PrimaryAxisPerpendicular,
PrimaryAxisLookAt,
AllAxes
}
public enum AlphaMode
@ -107,6 +111,13 @@ namespace RobloxFiles.Enums
ScaleWithParentSize
}
public enum AudioApiRollout
{
Disabled,
Automatic,
Enabled
}
public enum AudioSubType
{
Music = 1,
@ -196,6 +207,14 @@ namespace RobloxFiles.Enums
Orbital
}
public enum CharacterControlMode
{
Default,
Legacy,
NoCharacterController,
LuaCharacterController
}
public enum ChatVersion
{
LegacyChatService,
@ -1070,6 +1089,13 @@ namespace RobloxFiles.Enums
Adaptive
}
public enum PlayerCharacterDestroyBehavior
{
Default,
Disabled,
Enabled
}
public enum PoseEasingDirection
{
In,

View File

@ -24,6 +24,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -32,6 +33,25 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="Costura, Version=4.1.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
@ -147,6 +167,7 @@
<Compile Include="Tokens\Ray.cs" />
<Compile Include="Tokens\Rect.cs" />
<Compile Include="Tokens\Ref.cs" />
<Compile Include="Tokens\SecurityCapabilities.cs" />
<Compile Include="Tokens\SharedString.cs" />
<Compile Include="Tokens\String.cs" />
<Compile Include="Tokens\UDim.cs" />

Binary file not shown.

View File

@ -1,26 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31507.150
# Visual Studio Version 17
VisualStudioVersion = 17.3.32929.385
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobloxFileFormat", "RobloxFileFormat.csproj", "{19400E0B-6CA3-4171-9644-657E9858275C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobloxFileFormat", "RobloxFileFormat.csproj", "{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RobloxFileFormat.UnitTest", "UnitTest\RobloxFileFormat.UnitTest.csproj", "{E9FF1680-6FB9-41CD-9A73-7D072CB91118}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{19400E0B-6CA3-4171-9644-657E9858275C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19400E0B-6CA3-4171-9644-657E9858275C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19400E0B-6CA3-4171-9644-657E9858275C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19400E0B-6CA3-4171-9644-657E9858275C}.Release|Any CPU.Build.0 = Release|Any CPU
{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}.Debug|x64.ActiveCfg = Debug|x64
{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}.Debug|x64.Build.0 = Debug|x64
{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
{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}.Release|x64.ActiveCfg = Release|x64
{CF50C0E2-23A7-4DC1-B4B2-E60CDE716253}.Release|x64.Build.0 = Release|x64
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Debug|x64.ActiveCfg = Debug|x64
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Debug|x64.Build.0 = Debug|x64
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Release|Any CPU.Build.0 = Release|Any CPU
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Release|x64.ActiveCfg = Release|x64
{E9FF1680-6FB9-41CD-9A73-7D072CB91118}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,26 @@
using System.Xml;
namespace RobloxFiles.Tokens
{
public class SecurityCapabilitiesToken : IXmlPropertyToken
{
public string XmlPropertyToken => "SecurityCapabilities";
public bool ReadProperty(Property prop, XmlNode node)
{
if (ulong.TryParse(node.InnerText, out var value))
{
prop.Value = value;
return true;
}
return false;
}
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
{
var value = prop.CastValue<ulong>();
node.InnerText = value.ToString();
}
}
}

View File

@ -45,6 +45,12 @@ namespace RobloxFiles
/// <summary>The source AssetId this instance was created in.</summary>
public long SourceAssetId = -1;
/// <summary>Whether the instance defines security capabilities.</summary>
public bool DefinesCapabilities = false;
/// <summary>The SecurityCapabilities of this instance.</summary>
public ulong Capabilities = 0;
/// <summary>A unique identifier declared for the history of this instance.</summary>
public UniqueId HistoryId = new UniqueId(0, 0, 0);
@ -531,7 +537,7 @@ namespace RobloxFiles
if (newProp.Type == PropertyType.Ref)
refProps.Add(newProp);
newInst.AddProperty(ref newProp);
newInst.AddProperty(newProp);
}
var oldParent = oldInst.Parent;
@ -628,7 +634,7 @@ namespace RobloxFiles
/// Adds a property by reference to this Instance's property list.
/// </summary>
/// <param name="prop">A reference to the property that will be added.</param>
internal void AddProperty(ref Property prop)
internal void AddProperty(Property prop)
{
string name = prop.Name;
RemoveProperty(name);
@ -755,7 +761,7 @@ namespace RobloxFiles
Instance = this
};
AddProperty(ref newProp);
AddProperty(newProp);
}
else
{
@ -784,7 +790,7 @@ namespace RobloxFiles
if (GetProperty(name) == null)
{
var prop = new Property(name, propType);
AddProperty(ref prop);
AddProperty(prop);
}
}

View File

@ -42,7 +42,8 @@ namespace RobloxFiles
ProtectedString,
OptionalCFrame,
UniqueId,
FontFace
FontFace,
SecurityCapabilities,
}
public class Property
@ -58,8 +59,7 @@ namespace RobloxFiles
internal static BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase;
// TODO: Map typeof(ProtectedString) to PropertyType.ProtectedString
// if binary files are ever publicly allowed to read it.
// FIXME: Add a proper type for SecurityCapabilities once it's purpose is better understood.
public static readonly IReadOnlyDictionary<Type, PropertyType> Types = new Dictionary<Type, PropertyType>()
{
@ -95,8 +95,9 @@ namespace RobloxFiles
{ typeof(NumberSequence), PropertyType.NumberSequence },
{ typeof(Optional<CFrame>), PropertyType.OptionalCFrame },
{ typeof(ProtectedString), PropertyType.String },
{ typeof(ProtectedString), PropertyType.ProtectedString },
{ typeof(PhysicalProperties), PropertyType.PhysicalProperties },
{ typeof(ulong), PropertyType.SecurityCapabilities },
};
private void ImproviseRawBuffer()

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>

View File

@ -113,7 +113,7 @@ namespace RobloxFiles.XmlFormat
RobloxFile.LogError(readError.Message);
}
instance.AddProperty(ref prop);
instance.AddProperty(prop);
}
else if (RobloxFile.LogErrors)
{

View File

@ -99,7 +99,7 @@ namespace RobloxFiles
Instance refInst = Instances[refId];
refProp.Value = refInst;
}
else if (refId != "null")
else if (refId != "null" && refId != "Ref")
{
LogError($"XmlRobloxFile: Could not resolve reference for {refProp.GetFullName()}");
refProp.Value = null;