Skip to content

Commit 8f70379

Browse files
authored
Merge pull request #103 from EDITzDev/huxley
Huxley Support
2 parents 9c59956 + 04d1a73 commit 8f70379

File tree

10 files changed

+395
-121
lines changed

10 files changed

+395
-121
lines changed

src/Branch/PackageObjectLegacyVersion.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,12 @@ public enum PackageObjectLegacyVersion
228228
IsModificationAddedToStructMember = GameFFOW,
229229

230230
[Discardable] GameGOWPC = 490,
231+
[Discardable] GameHuxley = 496,
231232

232233
/// <summary>
233-
/// FIXME: Version, not attested in (GoW v490)
234+
/// FIXME: Version, not attested in (Huxley v496)
234235
/// </summary>
235-
SkipSizeAddedToArrayTokenIntrinsics = GameGOWPC + 1,
236+
SkipSizeAddedToArrayTokenIntrinsics = GameHuxley + 1,
236237

237238
VerticalOffsetAddedToUFont = 506,
238239
CleanupFonts = 511,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using UELib.Decoding;
2+
3+
namespace UELib.Branch.UE3.HUXLEY
4+
{
5+
public class CryptoDecoderHuxley : IBufferDecoder
6+
{
7+
private readonly uint _Key;
8+
9+
public CryptoDecoderHuxley(string name)
10+
{
11+
for (int i = 0; i < name.Length; i++)
12+
{
13+
_Key *= 16;
14+
_Key ^= name[i];
15+
}
16+
}
17+
18+
public CryptoDecoderHuxley(uint key) => _Key = key;
19+
20+
public void PreDecode(IUnrealStream stream)
21+
{
22+
}
23+
24+
public void DecodeBuild(IUnrealStream stream, UnrealPackage.GameBuild build)
25+
{
26+
}
27+
28+
public void DecodeRead(long position, byte[] buffer, int index, int count)
29+
{
30+
for (int i = index; i + 4 <= count; i += 4)
31+
{
32+
for (int j = 0; j < 4; j++)
33+
{
34+
buffer[i + j] = (byte)((_Key >> (j * 8)) ^ buffer[i + j]);
35+
}
36+
37+
for (int j = 0; j < 4; j++)
38+
{
39+
buffer[i + j] = (byte)((count >> (j * 8)) ^ buffer[i + j]);
40+
}
41+
}
42+
}
43+
44+
public unsafe void DecodeByte(long position, byte* b)
45+
{
46+
}
47+
}
48+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
3+
using UELib.Core;
4+
5+
namespace UELib.Branch.UE3.HUXLEY
6+
{
7+
public class EngineBranchHuxley : DefaultEngineBranch
8+
{
9+
[Flags]
10+
public enum PackageFlags : uint
11+
{
12+
UseCrypt = 0x8000000
13+
}
14+
15+
public EngineBranchHuxley(BuildGeneration generation) : base(generation)
16+
{
17+
}
18+
19+
public override void PostDeserializeSummary(UnrealPackage linker, IUnrealStream stream, ref UnrealPackage.PackageFileSummary summary)
20+
{
21+
base.PostDeserializeSummary(linker, stream, ref summary);
22+
23+
if (summary.PackageFlags.HasFlags((uint)PackageFlags.UseCrypt))
24+
{
25+
stream.Decoder = linker.Summary.LicenseeVersion >= 23
26+
? new CryptoDecoderHuxley(linker.PackageName)
27+
: new CryptoDecoderHuxley(linker.Summary.Guid.A);
28+
}
29+
}
30+
}
31+
}

src/Core/Classes/Props/UProperty.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.Contracts;
23
using UELib.Annotations;
34
using UELib.Branch;
45
using UELib.Flags;
@@ -223,6 +224,14 @@ protected override void Deserialize()
223224
RepOffset = _Buffer.ReadUShort();
224225
Record(nameof(RepOffset), RepOffset);
225226
}
227+
#if HUXLEY
228+
if (Package.Build == UnrealPackage.GameBuild.BuildName.Huxley)
229+
{
230+
// A property linked to the "Core.Object.LazyLoadPropertyInfo" struct.
231+
var partLoadInfoProperty = _Buffer.ReadObject();
232+
Record(nameof(partLoadInfoProperty), partLoadInfoProperty);
233+
}
234+
#endif
226235
#if R6
227236
if (Package.Build == UnrealPackage.GameBuild.BuildName.R6Vegas)
228237
{

src/Core/Classes/UObject.cs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,17 +187,42 @@ public void BeginDeserializing()
187187

188188
private void InitBuffer()
189189
{
190-
Package.Stream.Seek(ExportTable.SerialOffset, SeekOrigin.Begin);
190+
InitBuffer(Package.Stream);
191+
}
192+
193+
private void InitBuffer(UPackageStream stream)
194+
{
195+
long objectOffset = ExportTable.SerialOffset;
196+
int objectSize = ExportTable.SerialSize;
191197

192-
//Console.WriteLine( "Init buffer for {0}", (string)this );
193-
var buffer = new byte[ExportTable.SerialSize];
194-
_Buffer = new UObjectRecordStream(Package.Stream, buffer);
198+
byte[] buffer = new byte[objectSize];
199+
int byteCount;
200+
201+
// Make an object stream with a decoder as the base stream.
202+
if (stream.Decoder != null)
203+
{
204+
var decoder = stream.Decoder;
205+
// Read without decoding, because the encryption may be affected by the read count. e.g. "Huxley"
206+
stream.Decoder = null;
207+
// Bypass the terrible and slow endian reverse call
208+
stream.Seek(objectOffset, SeekOrigin.Begin);
209+
byteCount = stream.EndianAgnosticRead(buffer, 0, objectSize);
210+
stream.Decoder = decoder;
211+
212+
var baseStream = new MemoryDecoderStream(stream.Decoder, buffer, objectOffset);
213+
_Buffer = new UObjectRecordStream(stream, baseStream);
214+
}
215+
else
216+
{
217+
// Bypass the terrible and slow endian reverse call
218+
stream.Seek(objectOffset, SeekOrigin.Begin);
219+
byteCount = stream.EndianAgnosticRead(buffer, 0, objectSize);
220+
221+
_Buffer = new UObjectRecordStream(stream, buffer);
222+
}
195223

196-
// Bypass the terrible and slow endian reverse call
197-
int read = Package.Stream.EndianAgnosticRead(buffer, 0, ExportTable.SerialSize);
198-
Contract.Assert(ExportTable.SerialOffset + ExportTable.SerialSize <= Package.Stream.Length,
199-
"Exceeded file's length");
200-
//Debug.Assert(read == ExportTable.SerialSize, $"Incomplete read; expected a total bytes of {ExportTable.SerialSize} but got {read}");
224+
Contract.Assert(byteCount == objectSize,
225+
$"Incomplete read; expected a total bytes of {objectSize} but got {byteCount}");
201226
}
202227

203228
internal void EnsureBuffer()
@@ -216,7 +241,7 @@ internal void MaybeDisposeBuffer()
216241
if (_Buffer == null || (DeserializationState & ObjectState.Deserializing) != 0)
217242
return;
218243

219-
_Buffer.DisposeBuffer();
244+
_Buffer.Dispose();
220245
_Buffer = null;
221246
//Console.WriteLine( "Disposed" );
222247
}

src/Core/Tables/UExportTableItem.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,15 @@ public void Deserialize(IUnrealStream stream)
217217
{
218218
stream.Skip(sizeof(int));
219219
}
220+
#endif
221+
#if HUXLEY
222+
if (stream.Package.Build == UnrealPackage.GameBuild.BuildName.Huxley)
223+
{
224+
if (stream.LicenseeVersion >= 22)
225+
{
226+
int SerialSize2 = stream.ReadInt32();
227+
}
228+
}
220229
#endif
221230
if (stream.Version >= (uint)PackageObjectLegacyVersion.AddedComponentMapToExports &&
222231
stream.Version < (uint)PackageObjectLegacyVersion.ComponentMapDeprecated
@@ -286,7 +295,11 @@ public void Deserialize(IUnrealStream stream)
286295
}
287296
#endif
288297
stream.Skip(16); // Package guid
298+
#if HUXLEY
299+
if (stream.Version >= 475)
300+
#else
289301
if (stream.Version > 486) // 475? 486(> Stargate Worlds)
302+
#endif
290303
{
291304
stream.Skip(4); // Package flags
292305
}

src/Core/Tables/UObjectTableItem.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,9 @@ public static string GetReferencePath([CanBeNull] UObjectTableItem item)
104104

105105
public virtual byte[] CopyBuffer()
106106
{
107-
var buff = new byte[Size];
107+
byte[] buff = new byte[Size];
108108
Owner.Stream.Seek(Offset, SeekOrigin.Begin);
109-
Owner.Stream.Read(buff, 0, Size);
110-
if (Owner.Stream.BigEndianCode)
111-
{
112-
Array.Reverse(buff);
113-
}
109+
Owner.Stream.EndianAgnosticRead(buff, 0, Size);
114110

115111
return buff;
116112
}

src/Eliot.UELib.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<DefineConstants>DECOMPILE;BINARYMETADATA;UE1;UE2;UE3;UE4;VENGEANCE;SWAT4;UNREAL2;INFINITYBLADE;BORDERLANDS2;GOW2;APB;SPECIALFORCE2;XIII;SINGULARITY;THIEF_DS;DEUSEX_IW;BORDERLANDS;MIRRORSEDGE;BIOSHOCK;HAWKEN;UT;DISHONORED;REMEMBERME;ALPHAPROTOCOL;VANGUARD;TERA;MKKE;TRANSFORMERS;XCOM2;DD2;DCUO;AA2;SPELLBORN;BATMAN;MOH;ROCKETLEAGUE;DNF;LSGAME;UNDYING;HP;DEVASTATION;BATTLEBORN;SPLINTERCELLX;AHIT;GIGANTIC;ENDWAR;SG1;MASS_EFFECT;MOV;MIDWAY;SHADOWSTRIKE;R6</DefineConstants>
3+
<DefineConstants>DECOMPILE;BINARYMETADATA;UE1;UE2;UE3;UE4;VENGEANCE;SWAT4;UNREAL2;INFINITYBLADE;BORDERLANDS2;GOW2;APB;SPECIALFORCE2;XIII;SINGULARITY;THIEF_DS;DEUSEX_IW;BORDERLANDS;MIRRORSEDGE;BIOSHOCK;HAWKEN;UT;DISHONORED;REMEMBERME;ALPHAPROTOCOL;VANGUARD;TERA;MKKE;TRANSFORMERS;XCOM2;DD2;DCUO;AA2;SPELLBORN;BATMAN;MOH;ROCKETLEAGUE;DNF;LSGAME;UNDYING;HP;DEVASTATION;BATTLEBORN;SPLINTERCELLX;AHIT;GIGANTIC;ENDWAR;SG1;MASS_EFFECT;MOV;MIDWAY;SHADOWSTRIKE;R6;HUXLEY</DefineConstants>
44
<TargetFrameworks>net48;netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
55
<LangVersion>12.0</LangVersion>
66
<OutputType>Library</OutputType>

src/UnrealPackage.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using UELib.Branch.UE3.APB;
1515
using UELib.Branch.UE3.DD2;
1616
using UELib.Branch.UE3.GIGANTIC;
17+
using UELib.Branch.UE3.HUXLEY;
1718
using UELib.Branch.UE3.MOH;
1819
using UELib.Branch.UE3.R6;
1920
using UELib.Branch.UE3.RSS;
@@ -456,6 +457,15 @@ public enum BuildName
456457
/// </summary>
457458
[Build(490, 9)] GoW1,
458459

460+
/// <summary>
461+
/// Huxley
462+
///
463+
/// 496/023
464+
/// </summary>
465+
[Build(496, 23)]
466+
[BuildEngineBranch(typeof(EngineBranchHuxley))]
467+
Huxley,
468+
459469
[Build(511, 039, BuildGeneration.HMS)] // The Bourne Conspiracy
460470
[Build(511, 145, BuildGeneration.HMS)] // Transformers: War for Cybertron (PC version)
461471
[Build(511, 144, BuildGeneration.HMS)]
@@ -1247,6 +1257,21 @@ public void Deserialize(IUnrealStream stream)
12471257

12481258
stream.Skip(4);
12491259
}
1260+
#endif
1261+
#if HUXLEY
1262+
if (stream.Package.Build == GameBuild.BuildName.Huxley)
1263+
{
1264+
if (LicenseeVersion >= 8)
1265+
{
1266+
int huxleySignature = stream.ReadInt32();
1267+
Contract.Assert(huxleySignature != 0xFEFEFEFE, "[HUXLEY] Invalid Signature!");
1268+
}
1269+
1270+
if (LicenseeVersion >= 17)
1271+
{
1272+
int unk = stream.ReadInt32();
1273+
}
1274+
}
12501275
#endif
12511276
if (stream.Version >= VHeaderSize)
12521277
{
@@ -2560,10 +2585,9 @@ public bool ContainsEditorData()
25602585

25612586
public byte[] CopyBuffer()
25622587
{
2563-
var buff = new byte[HeaderSize];
2588+
byte[] buff = new byte[Summary.HeaderSize];
25642589
Stream.Seek(0, SeekOrigin.Begin);
2565-
Stream.Read(buff, 0, HeaderSize);
2566-
if (Stream.BigEndianCode) Array.Reverse(buff);
2590+
Stream.EndianAgnosticRead(buff, 0, Summary.HeaderSize);
25672591

25682592
return buff;
25692593
}

0 commit comments

Comments
 (0)