Skip to content

Commit

Permalink
Small optimizations and code improvements
Browse files Browse the repository at this point in the history
- Made node decompression a tiny bit faster (sidenote: DynArray is a bit slow, maybe directly poking allocators is better?)
- Some fixes in preparation for a EP1-free version (still unsure about worthwhileness)
- Some improvements to the Prologue start, may feel more immersive
  • Loading branch information
not_alphanine committed May 27, 2024
1 parent c7b2820 commit e6ba1fe
Show file tree
Hide file tree
Showing 31 changed files with 235 additions and 151 deletions.
Binary file modified NewGamePlus.rc
Binary file not shown.
3 changes: 1 addition & 2 deletions SaveDataParser.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>EnableAllWarnings</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);NOMINMAX</PreprocessorDefinitions>
Expand All @@ -165,7 +164,7 @@
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<ExternalWarningLevel>Level2</ExternalWarningLevel>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<CreateHotpatchableImage>true</CreateHotpatchableImage>
<CreateHotpatchableImage>false</CreateHotpatchableImage>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<DisableLanguageExtensions>false</DisableLanguageExtensions>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
Expand Down
2 changes: 1 addition & 1 deletion scripting/NGPlusOnReadyForEquipment.reds
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,6 @@ class PlayerProgressionLoader {
let hideOnItemsAdded: array<wref<Item_Record>>;
asRecipeRecord.HideOnItemsAdded(hideOnItemsAdded);
craftBook.AddRecipe(targetItemId, hideOnItemsAdded, result.Amount());
this.m_ngPlusSystem.Spew(s"PlayerProgressionLoader::LoadPlayerCraftbook, added recipe for \(TDBID.ToStringDEBUG(targetItemId))");
break;
}
}
Expand Down Expand Up @@ -296,6 +295,7 @@ class NewGamePlusProgressionLoader extends ScriptableSystem {
let player = GameInstance.GetPlayerSystem(GetGameInstance()).GetLocalPlayerMainGameObject() as PlayerPuppet;
if !IsDefined(player) {
this.m_questsSystem.SetFactStr("ngplus_apply_progression", 0);
this.m_ngPlusSystem.Error("NewGamePlusProgressionLoader::OnProgressionTransferCalled, player not found");
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ RED4EXT_C_EXPORT void RED4EXT_CALL Query(RED4ext::PluginInfo* aInfo)
{
aInfo->name = L"New Game+";
aInfo->author = L"not_alphanine";
aInfo->version = RED4EXT_SEMVER_EX(0, 9, 8, RED4EXT_V0_SEMVER_PRERELEASE_TYPE_RC, 1); // Set your version here.
aInfo->runtime = RED4EXT_RUNTIME_INDEPENDENT;
aInfo->version = RED4EXT_SEMVER_EX(0, 9, 9, 0, 0); // Set your version here.
aInfo->runtime = RED4EXT_RUNTIME_INDEPENDENT;
aInfo->sdk = RED4EXT_SDK_LATEST;
}

Expand Down
32 changes: 31 additions & 1 deletion src/parsing/cursorDef.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <RED4ext/RED4ext.hpp>
#include <RedLib.hpp>

#include <intrin.h>

struct FileCursor;

template<typename ReadableClass>
Expand Down Expand Up @@ -211,6 +213,19 @@ struct FileCursor {
return ret;
}

std::string ReadLengthPrefixedANSI()
{
auto buffer = readLengthPrefixedString();

auto lengthNeeded = WideCharToMultiByte(CP_UTF8, 0, &buffer[0], buffer.size(), nullptr, 0, nullptr, nullptr);

std::string ret(lengthNeeded, char{});

WideCharToMultiByte(CP_UTF8, 0, &buffer[0], buffer.size(), &ret[0], lengthNeeded, nullptr, nullptr);

return ret;
}

// Theoretically if we don't need a copy we could just do a string_view
// But let's be safe!
std::string readString(size_t length) {
Expand Down Expand Up @@ -330,7 +345,7 @@ struct FileCursor {
}

template<typename T>
inline static FileCursor FromVec(const std::vector<T>& aVec)
inline static FileCursor FromVec(std::vector<T>& aVec)
{
return FileCursor{aVec.data(), aVec.size()};
}
Expand All @@ -339,4 +354,19 @@ struct FileCursor {
{
return baseAddress + offset;
}

void CopyTo(void* aBuffer, std::size_t aSize)
{
memcpy(aBuffer, GetCurrentPtr(), aSize);
offset += aSize;
}

void InsertTo(std::vector<std::byte>& aVec, std::size_t aSize)
{
auto begin = GetCurrentPtr();

aVec.insert(aVec.end(), begin, begin + aSize);

offset += aSize;
}
};
4 changes: 2 additions & 2 deletions src/parsing/definitions/compression/compressionHeader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ namespace compression {
struct CompressionHeader {
std::vector<DataChunkInfo> dataChunkInfo{};

int maxEntries;
int m_totalChunkSize{};
std::size_t maxEntries;
std::size_t m_totalChunkSize{};

static CompressionHeader fromCursor(FileCursor& cursor) {
const auto compressionHeaderBasePosition = cursor.offset;
Expand Down
10 changes: 7 additions & 3 deletions src/parsing/definitions/nodeEntry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace cyberpunk {
struct NodeEntry {
std::wstring name;
std::string name;

int id;
int nextId;
Expand Down Expand Up @@ -36,6 +36,8 @@ namespace cyberpunk {
// EVIL UGLY CODE AHEAD, WILL LIKELY LEAK MEMORY LIKE CRAZY
std::unique_ptr<NodeDataInterface> nodeData;

Red::CName m_hash;

inline void addChild(NodeEntry* child) {
child->isChild = true;
child->parent = this;
Expand All @@ -47,15 +49,17 @@ namespace cyberpunk {
nodeChildren.push_back(child);
}

static NodeEntry fromCursor(FileCursor& fileCursor) {
static NodeEntry FromCursor(FileCursor& fileCursor) {
NodeEntry ret{};

ret.name = fileCursor.readLengthPrefixedString();
ret.name = fileCursor.ReadLengthPrefixedANSI();
ret.nextId = fileCursor.readInt();
ret.childId = fileCursor.readInt();
ret.offset = fileCursor.readInt();
ret.size = fileCursor.readInt();

ret.m_hash = Red::CName{ret.name.c_str()};

return ret;
}

Expand Down
14 changes: 11 additions & 3 deletions src/parsing/definitions/nodeParsers/inventory/inventoryNode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include "../parserHelper.hpp"

// TODO: Optimize this
// Make this use Red structures instead of STL for noexcept stuff?
// Seems to have a bunch of pointless copies - get rid of them later
namespace cyberpunk {
struct ItemInfo {
enum class ItemStructure : std::uint8_t {
Expand Down Expand Up @@ -106,11 +109,12 @@ namespace cyberpunk {
ret.isValid = true;

ret.itemInfo = ItemInfo::fromCursor(cursor);
ret.appearanceName = cursor.readLengthPrefixedString();
ret.appearanceName = cursor.readLengthPrefixedString(); // Fix this to use ANSI later, but we don't use appearance name anyway...
ret.attachmentSlotTdbId = cursor.readTdbId();

const auto count = cursor.readVlqInt32();

// Fix this to use new methods later...
for (auto i = 0; i < count; i++) {
ret.children.push_back(fromCursor(cursor));
}
Expand All @@ -136,6 +140,7 @@ namespace cyberpunk {
AdditionalItemInfo additionalItemInfo;
ItemSlotPart itemSlotPart;

// I hate this
bool hasQuantity() const {
return (static_cast<std::uint8_t>(itemInfo.itemStructure) & static_cast<std::uint8_t>(ItemInfo::ItemStructure::Quantity))
== static_cast<std::uint8_t>(ItemInfo::ItemStructure::Quantity) || itemInfo.itemStructure == ItemInfo::ItemStructure::None && itemInfo.itemId.rngSeed == 2;
Expand All @@ -149,7 +154,7 @@ namespace cyberpunk {

class ItemDataNode : public NodeDataInterface {
public:
static constexpr std::wstring_view nodeName = L"itemData";
static constexpr Red::CName m_nodeName = "itemData";

ItemData itemData;
virtual void ReadData(FileCursor& cursor, NodeEntry& node) {
Expand Down Expand Up @@ -179,7 +184,7 @@ namespace cyberpunk {

class InventoryNode : public NodeDataInterface {
public:
static constexpr std::wstring_view nodeName = L"inventory";
static constexpr Red::CName m_nodeName = "inventory";
std::vector<SubInventory> subInventories;
private:
SubInventory readSubInventory(FileCursor& cursor, NodeEntry& node, int offset) {
Expand All @@ -200,6 +205,7 @@ namespace cyberpunk {
PluginContext::Error("Item info parsing error, itemInfoActual->itemData.itemInfo != nextItemInfo");
}

// Relatively big copy
ret.inventoryItems.push_back(itemInfoActual->itemData);
}

Expand All @@ -211,6 +217,7 @@ namespace cyberpunk {
auto offset = 0;

for (auto i = 0; i < count; i++) {
// Big copy, not a fan, fix later, not sure if it's avoidable...
auto subInventory = readSubInventory(cursor, node, offset);

subInventories.push_back(subInventory);
Expand All @@ -224,6 +231,7 @@ namespace cyberpunk {
return aSubInventory.inventoryId == aInventoryId;
});

// Remove assert later
assert(inventoryIt != subInventories.end());

return *inventoryIt;
Expand Down
13 changes: 7 additions & 6 deletions src/parsing/definitions/nodeParsers/parserHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,21 @@ std::unique_ptr<cyberpunk::NodeDataInterface> PersistencySystemParser(FileCursor
return dataPtr;
}

ParseNodeFn FindParser(std::wstring_view aNodeName) {
if (aNodeName == cyberpunk::InventoryNode::nodeName)
ParseNodeFn FindParser(Red::CName aNodeName)
{
if (aNodeName == cyberpunk::InventoryNode::m_nodeName)
{
return InventoryParser;
}
else if (aNodeName == cyberpunk::ItemDataNode::nodeName)
else if (aNodeName == cyberpunk::ItemDataNode::m_nodeName)
{
return ItemInfoParser;
}
else if (aNodeName == cyberpunk::ScriptableSystemsContainerNode::nodeName)
else if (aNodeName == cyberpunk::ScriptableSystemsContainerNode::m_nodeName)
{
return ScriptableSystemsContainerParser;
}
else if (aNodeName == cyberpunk::PersistencySystemNode::nodeName)
else if (aNodeName == cyberpunk::PersistencySystemNode::m_nodeName)
{
return PersistencySystemParser;
}
Expand All @@ -83,7 +84,7 @@ void cyberpunk::ParseChildren(FileCursor& cursor, std::vector<cyberpunk::NodeEnt
}

void cyberpunk::ParseNode(FileCursor& cursor, cyberpunk::NodeEntry& node) {
const auto parserFn = FindParser(node.name);
const auto parserFn = FindParser(node.m_hash);

cursor.offset = node.offset; // cursor.seekTo(FileCursor::SeekTo::Start, node.offset);
cursor.readInt();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace cyberpunk
struct RedPersistentObject
{
// Every persistent object should be ISerializable, I think?
//... Could we just use a handle instead of rolling our own dtor?
Red::ISerializable* m_ptr;

RedPersistentObject(Red::ScriptInstance aInstance)
Expand Down Expand Up @@ -70,7 +71,7 @@ class PersistencySystemNode : public NodeDataInterface
std::vector<PersistentBuffer> m_redClasses;

public:
static constexpr std::wstring_view nodeName = L"PersistencySystem2";
static constexpr Red::CName m_nodeName = "PersistencySystem2";

virtual void ReadData(FileCursor& aCursor, NodeEntry& node)
{
Expand Down Expand Up @@ -148,18 +149,33 @@ class PersistencySystemNode : public NodeDataInterface
}
}

PersistentBuffer& LookupChunk(std::string_view aChunkName)
// Use std::string_view instead of CName to report missing chunks better
PersistentBuffer* LookupChunk(std::string_view aChunkName) noexcept
{
auto chunkIt = std::find_if(m_redClasses.begin(), m_redClasses.end(),
[aChunkName](const PersistentBuffer& aBuffer)
{ return aBuffer.m_className == aChunkName.data(); });

if (chunkIt == m_redClasses.end())
{
throw std::runtime_error{std::format("Failed to find class {} in PersistencySystem2", aChunkName)};
PluginContext::Error(std::format("Failed to find class {} in PersistencySystem2", aChunkName));
return nullptr;
}

return *chunkIt;
return &*chunkIt;
}

template<typename RedClass>
RedClass* LookupInstanceAs(std::string_view aChunkName)
{
auto chunkPtr = LookupChunk(aChunkName);

if (!chunkPtr)
{
return nullptr;
}

return chunkPtr->m_classInstance.As<RedClass>();
}

bool HasChunk(std::string_view aChunkName) const
Expand Down
Loading

0 comments on commit e6ba1fe

Please sign in to comment.