Skip to content

Commit

Permalink
Merge pull request #119 from psiberx/master
Browse files Browse the repository at this point in the history
Added object package reading
  • Loading branch information
wopss authored May 3, 2024
2 parents e498564 + e7733c4 commit bb2909f
Show file tree
Hide file tree
Showing 15 changed files with 615 additions and 2 deletions.
12 changes: 12 additions & 0 deletions include/RED4ext/Detail/AddressHashes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ constexpr std::uint32_t Memory_PoolStorage_OOM = 0xD54F163A;
constexpr std::uint32_t OpcodeHandlers = 0x39532858;
#pragma endregion

#pragma region ObjectPackageExtractor
constexpr std::uint32_t ObjectPackageExtractor_Initialize = 2318998714;
constexpr std::uint32_t ObjectPackageExtractor_ExtractSync = 2038372664;
constexpr std::uint32_t ObjectPackageExtractor_ExtractAsync = 3819248393;
#pragma endregion

#pragma region ObjectPackageReader
constexpr std::uint32_t ObjectPackageReader_ctor = 3628731410;
constexpr std::uint32_t ObjectPackageReader_OnReadHeader = 1632836642;
constexpr std::uint32_t ObjectPackageReader_ReadHeader = 1285757088;
#pragma endregion

#pragma region ResourceDepot
constexpr std::uint32_t ResourceDepot = 0x659A0FC7;
#pragma endregion
Expand Down
3 changes: 2 additions & 1 deletion include/RED4ext/ISerializable-inl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ RED4EXT_INLINE void RED4ext::ISerializable::sub_20()
{
}

RED4EXT_INLINE void RED4ext::ISerializable::sub_28()
RED4EXT_INLINE void RED4ext::ISerializable::PostLoad(const RED4ext::PostLoadParams& aParams)
{
RED4EXT_UNUSED_PARAMETER(aParams);
}

RED4EXT_INLINE bool RED4ext::ISerializable::sub_30()
Expand Down
9 changes: 8 additions & 1 deletion include/RED4ext/ISerializable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ struct CClass;
struct BaseStream;
struct CString;

struct PostLoadParams
{
bool disablePreInitialization; // 00
uint8_t pad01[0x8 - 0x1]; // 01
};
RED4EXT_ASSERT_SIZE(PostLoadParams, 0x8);

struct ISerializable
{
ISerializable();
Expand All @@ -25,7 +32,7 @@ struct ISerializable
virtual Memory::IAllocator* GetAllocator(); // 10
virtual ~ISerializable() = default; // 18
virtual void sub_20(); // 20
virtual void sub_28(); // 28
virtual void PostLoad(const PostLoadParams& aParams); // 28
virtual bool sub_30(); // 30
virtual void sub_38(); // 38
virtual bool sub_40(BaseStream* aStream); // 40
Expand Down
146 changes: 146 additions & 0 deletions include/RED4ext/Package-inl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#ifdef RED4EXT_STATIC_LIB
#include <RED4ext/Package.hpp>
#endif

#include <RED4ext/Detail/AddressHashes.hpp>
#include <RED4ext/Relocation.hpp>

RED4EXT_INLINE RED4ext::ObjectPackageHeader::ObjectPackageHeader()
: rootIndex(-1)
{
}

RED4EXT_INLINE bool RED4ext::ObjectPackageHeader::IsEmpty() const
{
return cruids.IsEmpty();
}

RED4EXT_INLINE RED4ext::ObjectPackageReader::ObjectPackageReader(void* aBuffer, uint32_t aSize)
{
using func_t = void (*)(ObjectPackageReader*);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageReader_ctor);

func(this);

buffer = aBuffer;
size = aSize;
}

RED4EXT_INLINE RED4ext::ObjectPackageReader::ObjectPackageReader(const DeferredDataBuffer& aBuffer)
{
using func_t = void (*)(ObjectPackageReader*);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageReader_ctor);

func(this);

buffer = aBuffer.raw->data;
size = aBuffer.raw->size;
}

RED4EXT_INLINE RED4ext::ObjectPackageReader::ObjectPackageReader(const DataBuffer& aBuffer)
{
using func_t = void (*)(ObjectPackageReader*);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageReader_ctor);

func(this);

buffer = aBuffer.buffer.data;
size = aBuffer.buffer.size;
}

RED4EXT_INLINE RED4ext::ObjectPackageReader::ObjectPackageReader(const RawBuffer& aBuffer)
{
using func_t = void (*)(ObjectPackageReader*);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageReader_ctor);

func(this);

buffer = aBuffer.data;
size = aBuffer.size;
}

RED4EXT_INLINE void RED4ext::ObjectPackageReader::OnReadHeader(uint64_t a1, uint64_t a2)
{
using func_t = void (*)(ObjectPackageReader*, uint64_t, uint64_t);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageReader_OnReadHeader);

func(this, a1, a2);
}

RED4EXT_INLINE void RED4ext::ObjectPackageReader::ReadHeader()
{
using func_t = void (*)(ObjectPackageReader*, ObjectPackageHeader&);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageReader_ReadHeader);

func(this, header);
}

RED4EXT_INLINE void RED4ext::ObjectPackageReader::ReadHeader(RED4ext::ObjectPackageHeader& aOut)
{
using func_t = void (*)(ObjectPackageReader*, ObjectPackageHeader&);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageReader_ReadHeader);

func(this, aOut);
}

RED4EXT_INLINE bool RED4ext::ObjectPackageReader::IsEmpty() const
{
return !buffer;
}

RED4EXT_INLINE RED4ext::ObjectPackageExtractorParams::ObjectPackageExtractorParams(const RED4ext::PackageHeader& aHeader)
: header(aHeader)
, loader(ResourceLoader::Get())
, disablePostLoad(false)
, disableImports(false)
, disablePreInitialization(false)
, unk63(0)
, unk64(0)
, unk78(0)
{
}

RED4EXT_INLINE RED4ext::ObjectPackageExtractorParams::ObjectPackageExtractorParams(const RED4ext::ObjectPackageHeader& aHeader)
: ObjectPackageExtractorParams(aHeader.package)
{
}

RED4EXT_INLINE RED4ext::ObjectPackageExtractor::ObjectPackageExtractor(const RED4ext::ObjectPackageExtractorParams& aParams)
: unk78(0)
, loader(nullptr)
, disablePostLoad(false)
, disableImports(false)
, disablePreInitialization(false)
, unkBB(0)
, unkBC(0)
, unkF0(nullptr)
, unkF8(nullptr)
, unk100(nullptr)
, unk108(nullptr)
, unk110(nullptr)
, unk118(nullptr)
{
using func_t = void (*)(ObjectPackageExtractor*, const ObjectPackageExtractorParams&);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageExtractor_Initialize);

func(this, aParams);
}

RED4EXT_INLINE void RED4ext::ObjectPackageExtractor::ExtractSync()
{
using func_t = void (*)(ObjectPackageExtractor*);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageExtractor_ExtractSync);

func(this);
}

RED4EXT_INLINE RED4ext::JobHandle RED4ext::ObjectPackageExtractor::ExtractAsync()
{
using func_t = void (*)(ObjectPackageExtractor*, JobHandle&);
static UniversalRelocFunc<func_t> func(Detail::AddressHashes::ObjectPackageExtractor_ExtractAsync);

JobHandle job;
func(this, job);

return job;
}
154 changes: 154 additions & 0 deletions include/RED4ext/Package.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#pragma once

#include <cstdint>

#include <RED4ext/Common.hpp>
#include <RED4ext/NativeTypes.hpp>
#include <RED4ext/Range.hpp>
#include <RED4ext/ResourceLoader.hpp>

namespace RED4ext
{
struct PackageHeader
{
struct Chunk
{
uint32_t typeID;
uint32_t offset;
};
RED4EXT_ASSERT_SIZE(Chunk, 0x8);

struct Name
{
uint32_t offset : 24;
uint32_t size : 8;
};
RED4EXT_ASSERT_SIZE(Name, 0x4);

struct Import
{
uint32_t offset : 23;
uint32_t size : 8;
uint32_t sync : 1;
};
RED4EXT_ASSERT_SIZE(Import, 0x4);

uint8_t version; // 00
uint8_t unk01; // 01
uint16_t unk02; // 02
Range<Chunk> root; // 08
Range<Chunk> chunks; // 18
Range<Name> names; // 28
Range<Import> imports; // 38
void* buffer; // 48
uint32_t size; // 50
};
RED4EXT_ASSERT_SIZE(PackageHeader, 0x58);
RED4EXT_ASSERT_OFFSET(PackageHeader, unk02, 0x02);
RED4EXT_ASSERT_OFFSET(PackageHeader, root, 0x08);
RED4EXT_ASSERT_OFFSET(PackageHeader, buffer, 0x48);

struct ObjectPackageHeader
{
ObjectPackageHeader();

[[nodiscard]] bool IsEmpty() const;

int16_t rootIndex; // 00 - Set to 0 if package contains root Entity, otherwise -1
Range<CRUID> cruids; // 08
PackageHeader package; // 18
};
RED4EXT_ASSERT_SIZE(ObjectPackageHeader, 0x70);
RED4EXT_ASSERT_OFFSET(ObjectPackageHeader, rootIndex, 0x0);
RED4EXT_ASSERT_OFFSET(ObjectPackageHeader, cruids, 0x08);
RED4EXT_ASSERT_OFFSET(ObjectPackageHeader, package, 0x18);

struct ObjectPackageReader
{
ObjectPackageReader(void* aBuffer, uint32_t aSize);
ObjectPackageReader(const DeferredDataBuffer& aBuffer);
ObjectPackageReader(const DataBuffer& aBuffer);
ObjectPackageReader(const RawBuffer& aBuffer);

virtual ~ObjectPackageReader() = default; // 00
virtual void OnReadHeader(uint64_t a1, uint64_t a2); // 08

void ReadHeader();
void ReadHeader(ObjectPackageHeader& aOut);

[[nodiscard]] bool IsEmpty() const;

void* buffer; // 08
uint32_t size; // 10
ObjectPackageHeader header; // 18
};
RED4EXT_ASSERT_SIZE(ObjectPackageReader, 0x88);
RED4EXT_ASSERT_OFFSET(ObjectPackageReader, buffer, 0x08);
RED4EXT_ASSERT_OFFSET(ObjectPackageReader, size, 0x10);
RED4EXT_ASSERT_OFFSET(ObjectPackageReader, header, 0x18);

struct ObjectPackageExtractorParams
{
ObjectPackageExtractorParams(const ObjectPackageHeader& aHeader);
ObjectPackageExtractorParams(const PackageHeader& aHeader);

PackageHeader header; // 00
ResourceLoader* loader; // 58
bool disablePostLoad; // 60 - See ObjectPackageExtractor
bool disableImports; // 61 - See ObjectPackageExtractor
bool disablePreInitialization; // 62 - See ObjectPackageExtractor
uint8_t unk63; // 63
uint8_t unk64; // 64
DynArray<uint32_t> unk68; // 68
uint32_t unk78; // 78
RawBuffer unk80; // 80 - Moved to ObjectPackageExtractor in ctor
};
RED4EXT_ASSERT_SIZE(ObjectPackageExtractorParams, 0xA0);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractorParams, loader, 0x58);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractorParams, disablePostLoad, 0x60);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractorParams, disableImports, 0x61);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractorParams, disablePreInitialization, 0x62);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractorParams, unk80, 0x80);

struct ObjectPackageExtractor
{
ObjectPackageExtractor(const ObjectPackageExtractorParams& aParams);

void ExtractSync();
JobHandle ExtractAsync();

WeakPtr<ObjectPackageExtractor> self; // 00
PackageHeader header; // 10
DynArray<uint32_t> unk68; // 68
uint32_t unk78; // 78
RawBuffer unk80; // 80
ResourceLoader* loader; // A0
DynArray<Handle<ISerializable>> results; // A8
bool disablePostLoad; // B8 - Don't call serializable->PostLoad()
bool disableImports; // B9 - Don't load resource references
bool disablePreInitialization; // BA - Don't call pre-initilization during PostLoad()
uint8_t unkBB; // BB
uint8_t unkBC; // BC
DynArray<Handle<ISerializable>> objects; // C0
DynArray<SharedPtr<ResourceToken<>>> resources; // D0
DynArray<uint32_t> unkE0; // E0
void* unkF0; // F0
void* unkF8; // F8
void* unk100; // 100
void* unk108; // 108
void* unk110; // 110
void* unk118; // 118
};
RED4EXT_ASSERT_SIZE(ObjectPackageExtractor, 0x120);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractor, header, 0x10);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractor, results, 0xA8);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractor, disablePostLoad, 0xB8);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractor, disableImports, 0xB9);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractor, disablePreInitialization, 0xBA);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractor, objects, 0xC0);
RED4EXT_ASSERT_OFFSET(ObjectPackageExtractor, resources, 0xD0);
} // namespace RED4ext

#ifdef RED4EXT_HEADER_ONLY
#include <RED4ext/Package-inl.hpp>
#endif
Loading

0 comments on commit bb2909f

Please sign in to comment.