Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
- Full transfer to native save stream may take a while
  • Loading branch information
not_alphanine committed Nov 20, 2024
1 parent 0d09903 commit 5c4e8a4
Show file tree
Hide file tree
Showing 40 changed files with 399 additions and 526 deletions.
92 changes: 79 additions & 13 deletions src/filesystem/filesystem.cpp → src/filesystem/SaveFS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
#include <RedLib.hpp>

#include <RED4ext/Scripting/Natives/Generated/save/MetadataContainer.hpp>
#include <RED4ext/Scripting/Natives/Generated/game/StatsStateMapStructure.hpp>

#include "filesystem.hpp"
#include "SaveFS.hpp"

#include <context/context.hpp>

#include <Shared/Raw/FileSystem/FileSystem.hpp>
#include <Shared/Raw/Package/ScriptableSystemsPackage.hpp>
#include <Shared/Raw/Save/Save.hpp>
#include <Shared/RTTI/PropertyAccessor.hpp>

using namespace Red;

Expand Down Expand Up @@ -649,7 +652,7 @@ bool ReadSaveFileToBuffer(const Red::CString& aSaveName, std::vector<std::byte>&

stream->ReadWrite(&aBuffer[0], static_cast<std::uint32_t>(fileSize));

constexpr auto c_testSaveStream = false;
constexpr auto c_testSaveStream = true;

if constexpr (c_testSaveStream)
{
Expand All @@ -665,23 +668,86 @@ bool ReadSaveFileToBuffer(const Red::CString& aSaveName, std::vector<std::byte>&
auto loadStream = shared::raw::Save::Stream::LoadStream::Create(saveStream, metadata);
loadStream.Initialize();

shared::raw::Save::NodeAccessor sessionDesc(loadStream, "GameSessionDesc", true, false);
{
shared::raw::Save::NodeAccessor sessionDesc(loadStream, "GameSessionDesc", true, false);

if (sessionDesc.IsGood())
{
shared::raw::Save::NodeAccessor sessionConfig(loadStream, "game::SessionConfig", true, false);

if (sessionConfig.IsGood())
{
PluginContext::Spew("Ebin");

Red::ResourcePath path1{};
Red::ResourcePath path2{};

loadStream->ReadWriteEx(&path1);
loadStream->ReadWriteEx(&path2);

PluginContext::Spew("Path 1: {}", path1.hash);
PluginContext::Spew("Path 2: {}", path2.hash);
}
}
}

if (sessionDesc.IsGood())
{
shared::raw::Save::NodeAccessor sessionConfig(loadStream, "game::SessionConfig", true, false);
shared::raw::Save::NodeAccessor scriptableSystemsContainer(loadStream, "ScriptableSystemsContainer", true,
false);

if (scriptableSystemsContainer.IsGood())
{
auto buffer = loadStream.ReadBuffer();

shared::raw::ScriptablePackage::ScriptablePackageReader reader(buffer);

PackageHeader header{};

// The game does this, don't ask
reader.ReadHeader(header);
reader.ReadHeader(header);

if (sessionConfig.IsGood()) {
PluginContext::Spew("Ebin");
shared::raw::ScriptablePackage::ScriptablePackageExtractor extractor(header);

constexpr auto c_testClassName = "PlayerDevelopmentSystem";
auto ref = MakeScriptedHandle(GetClass<"PlayerDevelopmentSystem">());

std::uint32_t classIndex{};

for (; classIndex < reader.rootChunkTypes.size; classIndex++)
{
if (reader.rootChunkTypes[classIndex] == c_testClassName)
{
break;
}
}

extractor.GetObjectById(ref, classIndex);

auto& data = shared::rtti::GetClassProperty<DynArray<Handle<IScriptable>>, "playerData">(ref);


PluginContext::Spew("{}", header.size);
PluginContext::Spew("PDS data size: {}", data.size);

if (data.size > 0u)
{
PluginContext::Spew("Data class name: {}", data[0]->GetType()->name.ToString());
}
}
}

{
shared::raw::Save::NodeAccessor statsSystem(loadStream, "StatsSystem", true, false);

Red::ResourcePath path1{};
Red::ResourcePath path2{};
if (statsSystem.IsGood())
{
auto stateMap = loadStream.ReadPackage(GetClass<game::StatsStateMapStructure>());

loadStream->ReadWriteEx(&path1);
loadStream->ReadWriteEx(&path2);
// It is what it is, should fix it sometime
auto& ptr = *reinterpret_cast<game::StatsStateMapStructure*>(stateMap.instance);

PluginContext::Spew("Path 1: {}", path1.hash);
PluginContext::Spew("Path 2: {}", path2.hash);
PluginContext::Spew("Keys: {}, values: {}", ptr.keys.size, ptr.values.size);
}
}
}
Expand Down
File renamed without changes.
29 changes: 29 additions & 0 deletions src/parsing/New/Nodes/Inventory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <Shared/Util/NamePoolRegistrar.hpp>

#include "Inventory.hpp"

using namespace parser::node;
using namespace Red;
using namespace shared::raw;
using namespace shared::util;

bool InventoryNode::OnRead(shared::raw::Save::Stream::LoadStream& aStream) noexcept
{
static const auto c_itemDataNodeName = NamePoolRegistrar<"itemData">::Get();

Save::NodeAccessor node(aStream, GetName(), true, false);

if (!aStream.IsGood())
{
return false;
}

return aStream.IsGood();
}

CName InventoryNode::GetName() noexcept
{
return NamePoolRegistrar<"inventory">::Get();
}

RTTI_DEFINE_CLASS(parser::node::InventoryNode, { RTTI_PARENT(parser::node::SaveNodeData); });
70 changes: 70 additions & 0 deletions src/parsing/New/Nodes/Inventory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once
#include <RED4ext/RED4ext.hpp>
#include <RedLib.hpp>

#include <parsing/New/TypeDefinitions/NGPlusSaveNode.hpp>

#include <Shared/Raw/Save/Save.hpp>

namespace parser::node
{
struct ItemLootData
{
Red::TweakDBID m_lootPoolId{};
std::uint32_t unk08{};
float m_requiredLevel{};
};

struct InnerItemDataRepresentation
{
Red::ItemID m_itemID{};
Red::CName m_appearanceName{};
Red::TweakDBID m_attachmentSlotID{};

Red::DynArray<InnerItemDataRepresentation> m_children{};

std::uint32_t unk30{};

ItemLootData m_lootData{};
};

struct UniqueItemDataRepresentation : Red::ISerializable
{
RTTI_IMPL_TYPEINFO(UniqueItemDataRepresentation);
RTTI_IMPL_ALLOCATOR();
};

struct BlueprintStackableItemDataRepresentation : Red::ISerializable
{
RTTI_IMPL_TYPEINFO(BlueprintStackableItemDataRepresentation);
RTTI_IMPL_ALLOCATOR();
};

struct StackedItemDataRepresentation : Red::ISerializable
{
RTTI_IMPL_TYPEINFO(StackedItemDataRepresentation);
RTTI_IMPL_ALLOCATOR();
};

struct ItemRepresentation : Red::ISerializable
{
Red::ItemID m_itemID{};

char m_itemFlags{}; // quest, ETC

RTTI_IMPL_TYPEINFO(ItemRepresentation);
RTTI_IMPL_ALLOCATOR();
};

class InventoryNode : public SaveNodeData
{
private:

public:
bool OnRead(shared::raw::Save::Stream::LoadStream& aStream) noexcept override;
Red::CName GetName() noexcept override;

RTTI_IMPL_TYPEINFO(InventoryNode);
RTTI_IMPL_ALLOCATOR();
};
} // namespace parser::node
61 changes: 51 additions & 10 deletions src/parsing/New/Nodes/ScriptableSystemsContainer.cpp
Original file line number Diff line number Diff line change
@@ -1,33 +1,74 @@
#include <algorithm>

#include <Shared/Util/BufferCreator.hpp>
#include <Shared/Util/NamePoolRegistrar.hpp>

#include "ScriptableSystemsContainer.hpp"

using namespace parser::node;
using namespace Red;
using namespace shared::raw;
using namespace shared::util;

bool parser::node::ScriptableSystemsContainerNode::OnRead(Save::Stream::LoadStream& aStream) noexcept
bool ScriptableSystemsContainerNode::OnRead(Save::Stream::LoadStream& aStream) noexcept
{
Save::NodeAccessor node(aStream, GetName(), true, false);

if (aStream.IsGood())
if (!aStream.IsGood())
{
auto buf = aStream.ReadBuffer();
return false;
}

auto buffer = aStream.ReadBuffer();

m_reader.Init(std::move(buf));
// When you're too lazy to go and make a move ctor xD
// Evil code

m_reader.m_readCruids = true;
std::copy_n(reinterpret_cast<char*>(&buffer), sizeof(RawBuffer), reinterpret_cast<char*>(&m_buffer));
std::fill_n(reinterpret_cast<char*>(&buffer), sizeof(RawBuffer), 0);

m_reader.ReadPackage();
ScriptablePackage::ScriptablePackageReader reader(m_buffer);

return aStream.IsGood();
// Yes, the game does this
reader.ReadHeader(m_packageHeader);
reader.ReadHeader(m_packageHeader);

ScriptablePackage::ScriptablePackageExtractor::InitFromHeader(&m_packageExtractor, m_packageHeader);

for (auto i = 0u; i < reader.rootChunkTypes.size; i++)
{
m_systemIndexMap.insert_or_assign(GetClass(reader.rootChunkTypes[i]), i);
}

return false;
return aStream.IsGood();
}

CName parser::node::ScriptableSystemsContainerNode::GetName() noexcept
CName ScriptableSystemsContainerNode::GetName() noexcept
{
return NamePoolRegistrar<"ScriptableSystemsContainer">::Get();
}
}

Handle<IScriptable>& ScriptableSystemsContainerNode::GetScriptableSystem(CClass* aClass) noexcept
{
static Handle<IScriptable> s_empty;

if (m_handleCache.contains(aClass))
{
return m_handleCache[aClass];
}

if (!m_systemIndexMap.contains(aClass))
{
return s_empty;
}

m_handleCache.insert_or_assign(aClass, MakeScriptedHandle(aClass));

auto index = m_systemIndexMap[aClass];

m_packageExtractor.GetObjectById(m_handleCache[aClass], index);

return m_handleCache[aClass];
}

RTTI_DEFINE_CLASS(parser::node::ScriptableSystemsContainerNode, { RTTI_PARENT(parser::node::SaveNodeData); });
19 changes: 16 additions & 3 deletions src/parsing/New/Nodes/ScriptableSystemsContainer.hpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
#pragma once
#include <RED4ext/RED4ext.hpp>
#include <RedLib.hpp>

#include <parsing/New/Readers/PackageReader.hpp>
#include <parsing/New/TypeDefinitions/NGPlusSaveNode.hpp>

#include <tsl/hopscotch_map.h>

#include <Shared/Raw/Package/ScriptableSystemsPackage.hpp>
#include <Shared/Raw/Save/Save.hpp>

namespace parser::node
{
class ScriptableSystemsContainerNode : public SaveNodeData
{
private:
reader::PackageReader m_reader{};
Red::RawBuffer m_buffer{};
Red::PackageHeader m_packageHeader{};
shared::raw::ScriptablePackage::ScriptablePackageExtractor m_packageExtractor{};

tsl::hopscotch_map<Red::CClass*, std::uint32_t> m_systemIndexMap{};
tsl::hopscotch_map<Red::CClass*, Red::Handle<Red::IScriptable>> m_handleCache{};
public:
bool OnRead(shared::raw::Save::Stream::LoadStream& aStream) noexcept override;
Red::CName GetName() noexcept override;

Red::Handle<Red::IScriptable>& GetScriptableSystem(Red::CClass* aClass) noexcept;

RTTI_IMPL_TYPEINFO(ScriptableSystemsContainerNode);
RTTI_IMPL_ALLOCATOR();
};
}
Loading

0 comments on commit 5c4e8a4

Please sign in to comment.