Skip to content

Commit

Permalink
Add and update support for common UE Core data types.
Browse files Browse the repository at this point in the history
  • Loading branch information
EliotVU committed Oct 14, 2022
1 parent f90e83d commit 94e0292
Show file tree
Hide file tree
Showing 24 changed files with 517 additions and 96 deletions.
15 changes: 11 additions & 4 deletions Benchmark/UnrealStreamBenchmark.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
using System.IO;
using UELib;
using UELib.Core.Types;
using BenchmarkDotNet.Attributes;
using UELib.Core;

namespace Eliot.UELib.Benchmark
{
public class UnrealStreamBenchmark
{
private IUnrealStream _Stream;

public UnrealStreamBenchmark()
{
// B, G, R, A;
var structBuffer = new byte[] { 255, 128, 64, 80 };
var baseStream = new MemoryStream(structBuffer);
_Stream = new UnrealTestStream(null, baseStream);
}


[Benchmark]
public void ReadStruct()
{
var stream = _Stream;
stream.Seek(0, SeekOrigin.Begin);
stream.ReadStruct(out UColor color);
}
/// <summary>
/// Verify that ReadAtomicStruct is indeed performing its purpose :)
/// </summary>
Expand All @@ -28,4 +35,4 @@ public void ReadAtomicStruct()
stream.ReadAtomicStruct(out UColor color);
}
}
}
}
1 change: 1 addition & 0 deletions Benchmark/UnrealTestStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class UnrealTestStream : UnrealReader, IUnrealStream
public UnrealWriter UW { get; }

public IBufferDecoder Decoder { get; set; }
public IPackageSerializer Serializer { get; set; }

public void SetBranch(EngineBranch packageEngineBranch)
{
Expand Down
2 changes: 1 addition & 1 deletion Test/UnrealPackageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UELib.Core;

namespace UELib.Test
namespace Eliot.UELib.Test
{
/// <summary>
/// The following tests requires UELib to be built without WinForms dependencies.
Expand Down
24 changes: 14 additions & 10 deletions Test/UnrealStreamTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Reflection;
using System.Text;
using UELib.Core.Types;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UELib;
using UELib.Core;

namespace UELib.Test
namespace Eliot.UELib.Test
{
[TestClass]
public class UnrealStreamTests
Expand Down Expand Up @@ -72,15 +73,18 @@ public void ReadAtomicStruct()
writer.Seek(sizeof(int), SeekOrigin.Begin);

// B, G, R, A;
var structBuffer = new byte[] { 255, 128, 64, 80 };
writer.Write(structBuffer);
var inColor = new UColor(255, 128, 64, 80);
stream.WriteAtomicStruct(ref inColor);
Assert.AreEqual(8, stream.Position);

stream.Seek(sizeof(int), SeekOrigin.Begin);
stream.ReadAtomicStruct<UColor>(out var color);
Assert.AreEqual(255, color.B);
Assert.AreEqual(128, color.G);
Assert.AreEqual(64, color.R);
Assert.AreEqual(80, color.A);
stream.ReadAtomicStruct(out UColor outColor);
Assert.AreEqual(8, stream.Position);

Assert.AreEqual(255, outColor.B);
Assert.AreEqual(128, outColor.G);
Assert.AreEqual(64, outColor.R);
Assert.AreEqual(80, outColor.A);
}
}
}
2 changes: 2 additions & 0 deletions src/Branch/PackageObjectLegacyVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public enum PackageObjectLegacyVersion
/// </summary>
ReturnExpressionAddedToReturnToken = 62,

SphereExtendsPlane = 62,

/// <summary>
/// FIXME: Unknown version.
/// </summary>
Expand Down
1 change: 0 additions & 1 deletion src/Core/Classes/UClassDecompiler.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#if DECOMPILE
using System.Text;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down
56 changes: 38 additions & 18 deletions src/Core/Classes/UDefaultProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.IO;
using System.Linq;
using UELib.Annotations;
using UELib.Core.Types;
using UELib.Types;
using UELib.UnrealScript;

Expand Down Expand Up @@ -64,6 +63,7 @@ public enum DeserializeFlags : byte
/// Name of the UEnum. If Type equals ByteProperty.
/// </summary>
[PublicAPI] [CanBeNull] public UName EnumName;

[PublicAPI] [CanBeNull] public UName InnerTypeName;

/// <summary>
Expand Down Expand Up @@ -225,7 +225,7 @@ private bool DeserializeTagUE1()
ItemName = _Buffer.ReadNameReference();
Record(nameof(ItemName), ItemName);
break;

case PropertyType.ArrayProperty:
{
#if DNF
Expand Down Expand Up @@ -315,7 +315,8 @@ private bool DeserializeTagByOffset()
Type == PropertyType.StructProperty ||
Type == PropertyType.Vector ||
Type == PropertyType.Rotator ||
(Type == PropertyType.BoolProperty && _Buffer.Package.Build == UnrealPackage.GameBuild.BuildName.Batman4))
(Type == PropertyType.BoolProperty &&
_Buffer.Package.Build == UnrealPackage.GameBuild.BuildName.Batman4))
{
switch (Type)
{
Expand Down Expand Up @@ -392,7 +393,7 @@ private void DeserializeTypeDataUE3()
: _Buffer.ReadInt32() > 0;
Record(nameof(BoolValue), BoolValue);
break;

case PropertyType.ArrayProperty:
#if UE4
// FIXME: UE4 version
Expand Down Expand Up @@ -454,7 +455,7 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ
{
var orgOuter = _Outer;
var propertyValue = string.Empty;

// Deserialize Value
switch (type)
{
Expand Down Expand Up @@ -615,7 +616,7 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ
case PropertyType.Color:
{
_Buffer.ReadAtomicStruct(out UColor color);
propertyValue += PropertyDisplay.FormatLiteral(color);
propertyValue += PropertyDisplay.FormatLiteral(ref color);
break;
}

Expand All @@ -632,11 +633,8 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ

case PropertyType.Vector:
{
string x = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags);
string y = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags);
string z = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags);

propertyValue += $"X={x},Y={y},Z={z}";
_Buffer.ReadAtomicStruct(out UVector vector);
propertyValue += PropertyDisplay.FormatLiteral(ref vector);
break;
}

Expand Down Expand Up @@ -687,16 +685,37 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ
}

case PropertyType.Sphere:
{
if (_Buffer.Version < VAtomicStructs)
{
throw new NotSupportedException("Not atomic");
}

_Buffer.ReadStruct(out USphere sphere);

propertyValue += _Buffer.Version >= 62
? $"W={PropertyDisplay.FormatLiteral(sphere.W)},"
: "" +
$"X={PropertyDisplay.FormatLiteral(sphere.X)}," +
$"Y={PropertyDisplay.FormatLiteral(sphere.Y)}," +
$"Z={PropertyDisplay.FormatLiteral(sphere.Z)}";

break;
}

case PropertyType.Plane:
{
if (_Buffer.Version < VAtomicStructs)
{
throw new NotSupportedException("Not atomic");
}

string w = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags);
string v = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags);
propertyValue += $"W={w},{v}";
_Buffer.ReadAtomicStruct(out UPlane plane);

propertyValue += $"W={PropertyDisplay.FormatLiteral(plane.W)}," +
$"X={PropertyDisplay.FormatLiteral(plane.X)}," +
$"Y={PropertyDisplay.FormatLiteral(plane.Y)}," +
$"Z={PropertyDisplay.FormatLiteral(plane.Z)}";
break;
}

Expand Down Expand Up @@ -754,17 +773,17 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ
propertyValue += $"X={x},Y={y}";
break;
}

case PropertyType.PointRegion:
{

string zone = DeserializeDefaultPropertyValue(PropertyType.ObjectProperty, ref deserializeFlags);
string iLeaf = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags);
string zoneNumber = DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags);
string zoneNumber =
DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags);
propertyValue += $"Zone={zone},iLeaf={iLeaf},ZoneNumber={zoneNumber}";
break;
}

#endregion

case PropertyType.PointerProperty:
Expand Down Expand Up @@ -910,6 +929,7 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ
default:
throw new Exception($"Unsupported property tag type {Type}");
}

_Outer = orgOuter;
return propertyValue;
}
Expand Down
4 changes: 4 additions & 0 deletions src/Core/Tables/UImportTableItem.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using UELib.Core;

namespace UELib
{
/// <summary>
Expand All @@ -9,13 +11,15 @@ public sealed class UImportTableItem : UObjectTableItem, IUnrealSerializableClas
#region Serialized Members

private UName _PackageName;

public UName PackageName
{
get => _PackageName;
set => _PackageName = value;
}

private UName _ClassName;

public UName ClassName
{
get => _ClassName;
Expand Down
54 changes: 40 additions & 14 deletions src/Core/Types/UColor.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
using System.Drawing;
using System.Runtime.InteropServices;
using UELib.Annotations;
using System.Runtime.InteropServices;

namespace UELib.Core.Types
namespace UELib.Core
{
/// <summary>
/// Implements FColor/UObject.Color
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct UColor : IUnrealAtomicStruct
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct UColor : IUnrealSerializableClass, IUnrealAtomicStruct
{
// The order may change based on compile-time constants.
// Intel Win32 x86
public byte B, G, R, A;
// Non-intel
//public byte A, R, G, B;

// <Intel-byte-order Win32 x86>
public byte B, G, R, A; // UE2, UE3
//public byte R, G, B, A; // UE1

[PublicAPI]
public Color ToColor()
// <Intel-byte-order Linux x86>
//public byte B, G, R, A; // UE3

// <Non-intel-byte-order>
//public byte A, R, G, B; // UE2, UE3
//public byte A, B, G, R; // UE1

public UColor(byte b, byte g, byte r, byte a)
{
B = b;
G = g;
R = r;
A = a;
}

// FIXME: RGBA UE1, UE2, UE3..
// Always packed as one Int32 (order BGRA for Intel-byte-order) if serialized in bulk, and non bulk for later UE3 builds.
// Packed as RGBA for UE1 unless not build intel-byte-order.
public void Deserialize(IUnrealStream stream)
{
stream.Read(out R);
stream.Read(out G);
stream.Read(out B);
stream.Read(out A);
}

public void Serialize(IUnrealStream stream)
{
return Color.FromArgb(A, R, G, B);
stream.Write(R);
stream.Write(G);
stream.Write(B);
stream.Write(A);
}
}
}
}
40 changes: 40 additions & 0 deletions src/Core/Types/UCoords.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Runtime.InteropServices;

namespace UELib.Core
{
/// <summary>
/// Implements FCoords/UObject.Coords
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct UCoords : IUnrealSerializableClass, IUnrealAtomicStruct
{
public UVector Origin;
public UVector XAxis;
public UVector YAxis;
public UVector ZAxis;

public UCoords(ref UVector origin, ref UVector xAxis, ref UVector yAxis, ref UVector zAxis)
{
Origin = origin;
XAxis = xAxis;
YAxis = yAxis;
ZAxis = zAxis;
}

public void Deserialize(IUnrealStream stream)
{
stream.ReadStruct(out Origin);
stream.ReadStruct(out XAxis);
stream.ReadStruct(out YAxis);
stream.ReadStruct(out ZAxis);
}

public void Serialize(IUnrealStream stream)
{
stream.WriteStruct(ref Origin);
stream.WriteStruct(ref XAxis);
stream.WriteStruct(ref YAxis);
stream.WriteStruct(ref ZAxis);
}
}
}
Loading

0 comments on commit 94e0292

Please sign in to comment.