Merge branch 'Laupetin:main' into main

This commit is contained in:
Alex 2024-01-26 12:15:26 -05:00 committed by GitHub
commit 80da882b4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 1838 additions and 359 deletions

View File

@ -3,6 +3,7 @@ include "tools/scripts/including.lua"
include "tools/scripts/linking.lua"
include "tools/scripts/options.lua"
include "tools/scripts/platform.lua"
include "tools/scripts/version.lua"
-- ==================
-- Workspace
@ -64,6 +65,13 @@ workspace "OpenAssetTools"
"_CRT_SECURE_NO_WARNINGS"
}
-- Write the current version to a header
-- This is better than adding it as macro here since changing a global macro would cause a full rebuild
WriteVersionHeader()
includedirs {
GetVersionHeaderFolder()
}
filter "options:debug-structureddatadef"
defines { "STRUCTUREDDATADEF_DEBUG" }
filter {}

View File

@ -616,9 +616,13 @@ public:
bool Start(const int argc, const char** argv) override
{
if (!m_args.ParseArgs(argc, argv))
auto shouldContinue = true;
if (!m_args.ParseArgs(argc, argv, shouldContinue))
return false;
if (!shouldContinue)
return true;
if (!m_search_paths.BuildProjectIndependentSearchPaths())
return false;

View File

@ -1,11 +1,13 @@
#include "LinkerArgs.h"
#include "GitVersion.h"
#include "ObjLoading.h"
#include "ObjWriting.h"
#include "Utils/Arguments/UsageInformation.h"
#include "Utils/FileUtils.h"
#include <filesystem>
#include <iostream>
#include <regex>
#include <type_traits>
@ -19,6 +21,12 @@ const CommandLineOption* const OPTION_HELP =
.WithDescription("Displays usage information.")
.Build();
const CommandLineOption* const OPTION_VERSION =
CommandLineOption::Builder::Create()
.WithLongName("version")
.WithDescription("Prints the application version.")
.Build();
const CommandLineOption* const OPTION_VERBOSE =
CommandLineOption::Builder::Create()
.WithShortName("v")
@ -88,6 +96,7 @@ const CommandLineOption* const OPTION_MENU_NO_OPTIMIZATION =
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
OPTION_HELP,
OPTION_VERSION,
OPTION_VERBOSE,
OPTION_BASE_FOLDER,
OPTION_OUTPUT_FOLDER,
@ -100,7 +109,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
};
LinkerArgs::LinkerArgs()
: m_argument_parser(COMMAND_LINE_OPTIONS, std::extent<decltype(COMMAND_LINE_OPTIONS)>::value),
: m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>),
m_base_pattern(R"(\?base\?)"),
m_game_pattern(R"(\?game\?)"),
m_project_pattern(R"(\?project\?)"),
@ -125,6 +134,11 @@ void LinkerArgs::PrintUsage()
usage.Print();
}
void LinkerArgs::PrintVersion()
{
std::cout << "OpenAssetTools Linker " << std::string(GIT_VERSION) << "\n";
}
void LinkerArgs::SetVerbose(const bool isVerbose)
{
m_verbose = isVerbose;
@ -198,8 +212,9 @@ std::set<std::string> LinkerArgs::GetSearchPathsForProject(const std::set<std::s
return out;
}
bool LinkerArgs::ParseArgs(const int argc, const char** argv)
bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
{
shouldContinue = true;
if (!m_argument_parser.ParseArguments(argc - 1, &argv[1]))
{
PrintUsage();
@ -210,7 +225,16 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv)
if (m_argument_parser.IsOptionSpecified(OPTION_HELP))
{
PrintUsage();
return false;
shouldContinue = false;
return true;
}
// Check if the user wants to see the version
if (m_argument_parser.IsOptionSpecified(OPTION_VERSION))
{
PrintVersion();
shouldContinue = false;
return true;
}
m_project_specifiers_to_build = m_argument_parser.GetArguments();

View File

@ -31,6 +31,7 @@ private:
* \brief Prints a command line usage help text for the Linker tool to stdout.
*/
static void PrintUsage();
static void PrintVersion();
void SetVerbose(bool isVerbose);
@ -56,7 +57,7 @@ public:
bool m_verbose;
LinkerArgs();
bool ParseArgs(int argc, const char** argv);
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
/**
* \brief Converts the output path specified by command line arguments to a path applies for the specified project.

View File

@ -14,6 +14,27 @@ bool CsvInputStream::NextRow(std::vector<std::string>& out) const
if (!out.empty())
out.clear();
return EmitNextRow(
[&out](std::string value)
{
out.emplace_back(std::move(value));
});
}
bool CsvInputStream::NextRow(std::vector<const char*>& out, MemoryManager& memory) const
{
if (!out.empty())
out.clear();
return EmitNextRow(
[&out, &memory](const std::string& value)
{
out.emplace_back(memory.Dup(value.c_str()));
});
}
bool CsvInputStream::EmitNextRow(const std::function<void(std::string)>& cb) const
{
auto c = m_stream.get();
const auto isEof = c == EOF;
std::ostringstream col;
@ -21,7 +42,7 @@ bool CsvInputStream::NextRow(std::vector<std::string>& out) const
{
if (c == CSV_SEPARATOR)
{
out.emplace_back(col.str());
cb(col.str());
col.clear();
col.str(std::string());
}
@ -46,7 +67,7 @@ bool CsvInputStream::NextRow(std::vector<std::string>& out) const
if (!isEof)
{
out.emplace_back(col.str());
cb(col.str());
}
return !isEof;

View File

@ -1,28 +1,36 @@
#pragma once
#include "Utils/MemoryManager.h"
#include <functional>
#include <iostream>
#include <string>
#include <vector>
class CsvInputStream
{
std::istream& m_stream;
public:
explicit CsvInputStream(std::istream& stream);
bool NextRow(std::vector<std::string>& out) const;
bool NextRow(std::vector<const char*>& out, MemoryManager& memory) const;
private:
bool EmitNextRow(const std::function<void(std::string)>& cb) const;
std::istream& m_stream;
};
class CsvOutputStream
{
std::ostream& m_stream;
unsigned m_column_count;
unsigned m_current_column;
bool m_first_row;
public:
explicit CsvOutputStream(std::ostream& stream);
void WriteColumn(const std::string& value);
void NextRow();
private:
std::ostream& m_stream;
unsigned m_column_count;
unsigned m_current_column;
bool m_first_row;
};

View File

@ -0,0 +1,36 @@
#include "AssetLoaderLocalizeEntry.h"
#include "Localize/LocalizeCommonAssetLoader.h"
using namespace IW3;
XAssetInfoGeneric* AssetLoaderLocalizeEntry::LoadFromGlobalAssetPools(const std::string& assetName) const
{
return nullptr;
}
void* AssetLoaderLocalizeEntry::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory)
{
return nullptr;
}
bool AssetLoaderLocalizeEntry::CanLoadFromRaw() const
{
return true;
}
bool AssetLoaderLocalizeEntry::LoadFromRaw(
const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
const LocalizeCommonAssetLoader commonLoader(
[memory, manager](const CommonLocalizeEntry& entry)
{
auto* localizeEntry = memory->Create<LocalizeEntry>();
localizeEntry->name = memory->Dup(entry.m_key.c_str());
localizeEntry->value = memory->Dup(entry.m_value.c_str());
manager->AddAsset(ASSET_TYPE_LOCALIZE_ENTRY, entry.m_key, localizeEntry);
});
return commonLoader.LoadLocalizeAsset(assetName, searchPath, manager, zone);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "AssetLoading/BasicAssetLoader.h"
#include "AssetLoading/IAssetLoadingManager.h"
#include "Game/IW3/IW3.h"
#include "SearchPath/ISearchPath.h"
namespace IW3
{
class AssetLoaderLocalizeEntry final : public BasicAssetLoader<ASSET_TYPE_LOCALIZE_ENTRY, LocalizeEntry>
{
public:
_NODISCARD XAssetInfoGeneric* LoadFromGlobalAssetPools(const std::string& assetName) const override;
_NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override;
_NODISCARD bool CanLoadFromRaw() const override;
bool
LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override;
};
} // namespace IW3

View File

@ -0,0 +1,39 @@
#include "AssetLoaderStringTable.h"
#include "Csv/CsvStream.h"
#include "Game/IW3/CommonIW3.h"
#include "ObjLoading.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"
#include <cstring>
using namespace IW3;
void* AssetLoaderStringTable::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory)
{
auto* stringTable = memory->Create<StringTable>();
memset(stringTable, 0, sizeof(StringTable));
stringTable->name = memory->Dup(assetName.c_str());
return stringTable;
}
bool AssetLoaderStringTable::CanLoadFromRaw() const
{
return true;
}
bool AssetLoaderStringTable::LoadFromRaw(
const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
const auto file = searchPath->Open(assetName);
if (!file.IsOpen())
return false;
string_table::StringTableLoaderV1<StringTable> loader;
auto* stringTable = loader.LoadFromStream(assetName, *memory, *file.m_stream);
manager->AddAsset(ASSET_TYPE_STRINGTABLE, assetName, stringTable);
return true;
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "AssetLoading/BasicAssetLoader.h"
#include "Game/IW3/IW3.h"
#include "SearchPath/ISearchPath.h"
namespace IW3
{
class AssetLoaderStringTable final : public BasicAssetLoader<ASSET_TYPE_STRINGTABLE, StringTable>
{
public:
_NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override;
_NODISCARD bool CanLoadFromRaw() const override;
bool
LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override;
};
} // namespace IW3

View File

@ -1,6 +1,7 @@
#include "ObjLoaderIW3.h"
#include "AssetLoaders/AssetLoaderGfxImage.h"
#include "AssetLoaders/AssetLoaderLocalizeEntry.h"
#include "AssetLoaders/AssetLoaderRawFile.h"
#include "AssetLoading/AssetLoadingManager.h"
#include "Game/IW3/GameAssetPoolIW3.h"
@ -43,7 +44,7 @@ ObjLoader::ObjLoader()
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_FONT, Font_s))
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MENULIST, MenuList))
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MENU, menuDef_t))
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_LOCALIZE_ENTRY, LocalizeEntry))
REGISTER_ASSET_LOADER(AssetLoaderLocalizeEntry)
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_WEAPON, WeaponDef))
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SNDDRIVER_GLOBALS, SndDriverGlobals))
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_FX, FxEffectDef))

View File

@ -22,7 +22,7 @@ bool AssetLoaderLocalizeEntry::CanLoadFromRaw() const
bool AssetLoaderLocalizeEntry::LoadFromRaw(
const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
LocalizeCommonAssetLoader commonLoader(
const LocalizeCommonAssetLoader commonLoader(
[memory, manager](const CommonLocalizeEntry& entry)
{
auto* localizeEntry = memory->Create<LocalizeEntry>();

View File

@ -5,6 +5,7 @@
#include "Game/IW4/IW4.h"
#include "ObjLoading.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"
#include <cstring>
@ -30,49 +31,8 @@ bool AssetLoaderStringTable::LoadFromRaw(
if (!file.IsOpen())
return false;
auto* stringTable = memory->Create<StringTable>();
stringTable->name = memory->Dup(assetName.c_str());
std::vector<std::vector<std::string>> csvLines;
std::vector<std::string> currentLine;
auto maxCols = 0u;
const CsvInputStream csv(*file.m_stream);
while (csv.NextRow(currentLine))
{
if (currentLine.size() > maxCols)
maxCols = currentLine.size();
csvLines.emplace_back(std::move(currentLine));
currentLine = std::vector<std::string>();
}
stringTable->columnCount = static_cast<int>(maxCols);
stringTable->rowCount = static_cast<int>(csvLines.size());
const auto cellCount = static_cast<unsigned>(stringTable->rowCount) * static_cast<unsigned>(stringTable->columnCount);
if (cellCount)
{
stringTable->values = static_cast<StringTableCell*>(memory->Alloc(sizeof(StringTableCell) * cellCount));
for (auto row = 0u; row < csvLines.size(); row++)
{
const auto& rowValues = csvLines[row];
for (auto col = 0u; col < maxCols; col++)
{
auto& cell = stringTable->values[row * maxCols + col];
if (col >= rowValues.size() || rowValues[col].empty())
cell.string = "";
else
cell.string = memory->Dup(rowValues[col].c_str());
cell.hash = Common::StringTable_HashString(cell.string);
}
}
}
else
{
stringTable->values = nullptr;
}
string_table::StringTableLoaderV2<StringTable, Common::StringTable_HashString> loader;
auto* stringTable = loader.LoadFromStream(assetName, *memory, *file.m_stream);
manager->AddAsset(ASSET_TYPE_STRINGTABLE, assetName, stringTable);

View File

@ -22,7 +22,7 @@ bool AssetLoaderLocalizeEntry::CanLoadFromRaw() const
bool AssetLoaderLocalizeEntry::LoadFromRaw(
const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
LocalizeCommonAssetLoader commonLoader(
const LocalizeCommonAssetLoader commonLoader(
[memory, manager](const CommonLocalizeEntry& entry)
{
auto* localizeEntry = memory->Create<LocalizeEntry>();

View File

@ -5,6 +5,7 @@
#include "Game/IW5/IW5.h"
#include "ObjLoading.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"
#include <cstring>
@ -30,49 +31,8 @@ bool AssetLoaderStringTable::LoadFromRaw(
if (!file.IsOpen())
return false;
auto* stringTable = memory->Create<StringTable>();
stringTable->name = memory->Dup(assetName.c_str());
std::vector<std::vector<std::string>> csvLines;
std::vector<std::string> currentLine;
auto maxCols = 0u;
const CsvInputStream csv(*file.m_stream);
while (csv.NextRow(currentLine))
{
if (currentLine.size() > maxCols)
maxCols = currentLine.size();
csvLines.emplace_back(std::move(currentLine));
currentLine = std::vector<std::string>();
}
stringTable->columnCount = static_cast<int>(maxCols);
stringTable->rowCount = static_cast<int>(csvLines.size());
const auto cellCount = static_cast<unsigned>(stringTable->rowCount) * static_cast<unsigned>(stringTable->columnCount);
if (cellCount)
{
stringTable->values = static_cast<StringTableCell*>(memory->Alloc(sizeof(StringTableCell) * cellCount));
for (auto row = 0u; row < csvLines.size(); row++)
{
const auto& rowValues = csvLines[row];
for (auto col = 0u; col < maxCols; col++)
{
auto& cell = stringTable->values[row * maxCols + col];
if (col >= rowValues.size() || rowValues[col].empty())
cell.string = "";
else
cell.string = memory->Dup(rowValues[col].c_str());
cell.hash = Common::StringTable_HashString(cell.string);
}
}
}
else
{
stringTable->values = nullptr;
}
string_table::StringTableLoaderV2<StringTable, Common::StringTable_HashString> loader;
auto* stringTable = loader.LoadFromStream(assetName, *memory, *file.m_stream);
manager->AddAsset(ASSET_TYPE_STRINGTABLE, assetName, stringTable);

View File

@ -22,7 +22,7 @@ bool AssetLoaderLocalizeEntry::CanLoadFromRaw() const
bool AssetLoaderLocalizeEntry::LoadFromRaw(
const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
LocalizeCommonAssetLoader commonLoader(
const LocalizeCommonAssetLoader commonLoader(
[memory, manager](const CommonLocalizeEntry& entry)
{
auto* localizeEntry = memory->Create<LocalizeEntry>();

View File

@ -4,6 +4,7 @@
#include "Game/T5/CommonT5.h"
#include "Game/T5/T5.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"
#include <cstring>
@ -29,65 +30,8 @@ bool AssetLoaderStringTable::LoadFromRaw(
if (!file.IsOpen())
return false;
auto* stringTable = memory->Create<StringTable>();
stringTable->name = memory->Dup(assetName.c_str());
std::vector<std::vector<std::string>> csvLines;
std::vector<std::string> currentLine;
auto maxCols = 0u;
const CsvInputStream csv(*file.m_stream);
while (csv.NextRow(currentLine))
{
if (currentLine.size() > maxCols)
maxCols = currentLine.size();
csvLines.emplace_back(std::move(currentLine));
currentLine = std::vector<std::string>();
}
stringTable->columnCount = static_cast<int>(maxCols);
stringTable->rowCount = static_cast<int>(csvLines.size());
const auto cellCount = static_cast<unsigned>(stringTable->rowCount) * static_cast<unsigned>(stringTable->columnCount);
if (cellCount)
{
stringTable->values = static_cast<StringTableCell*>(memory->Alloc(sizeof(StringTableCell) * cellCount));
stringTable->cellIndex = static_cast<int16_t*>(memory->Alloc(sizeof(int16_t) * cellCount));
for (auto c = 0u; c < cellCount; c++)
stringTable->cellIndex[c] = static_cast<int16_t>(c);
for (auto row = 0u; row < csvLines.size(); row++)
{
const auto& rowValues = csvLines[row];
for (auto col = 0u; col < maxCols; col++)
{
auto& cell = stringTable->values[row * maxCols + col];
if (col >= rowValues.size() || rowValues[col].empty())
cell.string = "";
else
cell.string = memory->Dup(rowValues[col].c_str());
cell.hash = Common::Com_HashString(cell.string);
}
}
std::sort(&stringTable->cellIndex[0],
&stringTable->cellIndex[cellCount - 1],
[stringTable, maxCols](const int16_t a, const int16_t b)
{
auto compareResult = stringTable->values[a].hash - stringTable->values[b].hash;
if (compareResult == 0)
compareResult = a % maxCols - b % maxCols;
return compareResult < 0;
});
}
else
{
stringTable->values = nullptr;
stringTable->cellIndex = nullptr;
}
string_table::StringTableLoaderV3<StringTable, Common::Com_HashString> loader;
auto* stringTable = loader.LoadFromStream(assetName, *memory, *file.m_stream);
manager->AddAsset(ASSET_TYPE_STRINGTABLE, assetName, stringTable);

View File

@ -22,7 +22,7 @@ bool AssetLoaderLocalizeEntry::CanLoadFromRaw() const
bool AssetLoaderLocalizeEntry::LoadFromRaw(
const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
LocalizeCommonAssetLoader commonLoader(
const LocalizeCommonAssetLoader commonLoader(
[memory, manager](const CommonLocalizeEntry& entry)
{
auto* localizeEntry = memory->Create<LocalizeEntry>();

View File

@ -4,6 +4,7 @@
#include "Game/T6/CommonT6.h"
#include "Game/T6/T6.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"
#include <cstring>
@ -29,65 +30,8 @@ bool AssetLoaderStringTable::LoadFromRaw(
if (!file.IsOpen())
return false;
auto* stringTable = memory->Create<StringTable>();
stringTable->name = memory->Dup(assetName.c_str());
std::vector<std::vector<std::string>> csvLines;
std::vector<std::string> currentLine;
auto maxCols = 0u;
const CsvInputStream csv(*file.m_stream);
while (csv.NextRow(currentLine))
{
if (currentLine.size() > maxCols)
maxCols = currentLine.size();
csvLines.emplace_back(std::move(currentLine));
currentLine = std::vector<std::string>();
}
stringTable->columnCount = static_cast<int>(maxCols);
stringTable->rowCount = static_cast<int>(csvLines.size());
const auto cellCount = static_cast<unsigned>(stringTable->rowCount) * static_cast<unsigned>(stringTable->columnCount);
if (cellCount)
{
stringTable->values = static_cast<StringTableCell*>(memory->Alloc(sizeof(StringTableCell) * cellCount));
stringTable->cellIndex = static_cast<int16_t*>(memory->Alloc(sizeof(int16_t) * cellCount));
for (auto c = 0u; c < cellCount; c++)
stringTable->cellIndex[c] = static_cast<int16_t>(c);
for (auto row = 0u; row < csvLines.size(); row++)
{
const auto& rowValues = csvLines[row];
for (auto col = 0u; col < maxCols; col++)
{
auto& cell = stringTable->values[row * maxCols + col];
if (col >= rowValues.size() || rowValues[col].empty())
cell.string = "";
else
cell.string = memory->Dup(rowValues[col].c_str());
cell.hash = Common::Com_HashString(cell.string);
}
}
std::sort(&stringTable->cellIndex[0],
&stringTable->cellIndex[cellCount - 1],
[stringTable, maxCols](const int16_t a, const int16_t b)
{
auto compareResult = stringTable->values[a].hash - stringTable->values[b].hash;
if (compareResult == 0)
compareResult = a % maxCols - b % maxCols;
return compareResult < 0;
});
}
else
{
stringTable->values = nullptr;
stringTable->cellIndex = nullptr;
}
string_table::StringTableLoaderV3<StringTable, Common::Com_HashString> loader;
auto* stringTable = loader.LoadFromStream(assetName, *memory, *file.m_stream);
manager->AddAsset(ASSET_TYPE_STRINGTABLE, assetName, stringTable);

View File

@ -0,0 +1,147 @@
#pragma once
#include "Csv/CsvStream.h"
#include <algorithm>
#include <istream>
#include <type_traits>
#include <vector>
namespace string_table
{
template<typename StringTableType, typename CellType> class AbstractStringTableLoader
{
protected:
AbstractStringTableLoader() = default;
virtual ~AbstractStringTableLoader() = default;
AbstractStringTableLoader(const AbstractStringTableLoader& other) = default;
AbstractStringTableLoader(AbstractStringTableLoader&& other) noexcept = default;
AbstractStringTableLoader& operator=(const AbstractStringTableLoader& other) = default;
AbstractStringTableLoader& operator=(AbstractStringTableLoader&& other) noexcept = default;
virtual void SetCellContent(CellType& cell, const char* content) = 0;
virtual void PostProcessStringTable(StringTableType* stringTable, const unsigned cellCount, MemoryManager& memory) {}
public:
StringTableType* LoadFromStream(const std::string& assetName, MemoryManager& memory, std::istream& stream)
{
auto* stringTable = memory.Create<StringTableType>();
stringTable->name = memory.Dup(assetName.c_str());
std::vector<std::vector<std::string>> csvLines;
std::vector<std::string> currentLine;
auto maxCols = 0u;
const CsvInputStream csv(stream);
while (csv.NextRow(currentLine))
{
if (currentLine.size() > maxCols)
maxCols = currentLine.size();
csvLines.emplace_back(std::move(currentLine));
currentLine = std::vector<std::string>();
}
stringTable->columnCount = static_cast<int>(maxCols);
stringTable->rowCount = static_cast<int>(csvLines.size());
const auto cellCount = static_cast<unsigned>(stringTable->rowCount) * static_cast<unsigned>(stringTable->columnCount);
if (cellCount)
{
stringTable->values = static_cast<CellType*>(memory.Alloc(sizeof(CellType) * cellCount));
for (auto row = 0u; row < csvLines.size(); row++)
{
const auto& rowValues = csvLines[row];
for (auto col = 0u; col < maxCols; col++)
{
auto& cell = stringTable->values[row * maxCols + col];
if (col >= rowValues.size() || rowValues[col].empty())
SetCellContent(cell, "");
else
SetCellContent(cell, memory.Dup(rowValues[col].c_str()));
}
}
}
else
{
stringTable->values = nullptr;
}
PostProcessStringTable(stringTable, cellCount, memory);
return stringTable;
}
};
// =================================
// V1: IW3
// - Cells are const char*
// =================================
template<typename StringTableType> class StringTableLoaderV1 final : public AbstractStringTableLoader<StringTableType, const char*>
{
protected:
void SetCellContent(const char*& cell, const char* content) override
{
cell = content;
}
};
// =================================
// V2: IW4, IW5
// - Cells are a struct and have a hash
// =================================
template<typename StringTableType, int (*HashFunc)(const char*)>
class StringTableLoaderV2 final : public AbstractStringTableLoader<StringTableType, std::remove_pointer_t<decltype(StringTableType::values)>>
{
using CellType_t = decltype(*StringTableType::values);
protected:
void SetCellContent(CellType_t& cell, const char* content) override
{
cell.string = content;
cell.hash = HashFunc(content);
}
};
// =================================
// V3: T5, T6
// - Cells are a struct and have a hash
// - StringTable has an index array for binary search
// =================================
template<typename StringTableType, int (*HashFunc)(const char*)>
class StringTableLoaderV3 final : public AbstractStringTableLoader<StringTableType, std::remove_pointer_t<decltype(StringTableType::values)>>
{
using CellType_t = decltype(*StringTableType::values);
protected:
void SetCellContent(CellType_t& cell, const char* content) override
{
cell.string = content;
cell.hash = HashFunc(content);
}
void PostProcessStringTable(StringTableType* stringTable, const unsigned cellCount, MemoryManager& memory) override
{
if (!cellCount)
{
stringTable->cellIndex = nullptr;
return;
}
stringTable->cellIndex = static_cast<int16_t*>(memory.Alloc(sizeof(int16_t) * cellCount));
for (auto i = 0u; i < cellCount; i++)
stringTable->cellIndex[i] = i;
std::sort(&stringTable->cellIndex[0],
&stringTable->cellIndex[cellCount - 1],
[stringTable](const int16_t a, const int16_t b)
{
auto compareResult = stringTable->values[a].hash - stringTable->values[b].hash;
if (compareResult == 0)
compareResult = (a % stringTable->columnCount) - (b % stringTable->columnCount);
return compareResult < 0;
});
}
};
} // namespace string_table

View File

@ -45,9 +45,13 @@ public:
int Run(const int argc, const char** argv)
{
if (!m_args.Parse(argc, argv))
auto shouldContinue = true;
if (!m_args.ParseArgs(argc, argv, shouldContinue))
return 1;
if (!shouldContinue)
return 0;
if (!m_args.m_build_log_file.empty())
{
fs::path p = fs::path(m_args.m_build_log_file).parent_path();

View File

@ -1,11 +1,18 @@
#include "RawTemplaterArguments.h"
#include "GitVersion.h"
#include "Utils/Arguments/CommandLineOption.h"
#include "Utils/Arguments/UsageInformation.h"
#include <iostream>
#include <type_traits>
const CommandLineOption* const OPTION_HELP =
CommandLineOption::Builder::Create().WithShortName("?").WithLongName("help").WithDescription("Displays usage information.").Build();
const CommandLineOption* const OPTION_VERSION =
CommandLineOption::Builder::Create().WithLongName("version").WithDescription("Prints the application version.").Build();
const CommandLineOption* const OPTION_VERBOSE =
CommandLineOption::Builder::Create().WithShortName("v").WithLongName("verbose").WithDescription("Outputs a lot more and more detailed messages.").Build();
@ -30,7 +37,14 @@ const CommandLineOption* const OPTION_DEFINE = CommandLineOption::Builder::Creat
.Reusable()
.Build();
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{OPTION_HELP, OPTION_VERBOSE, OPTION_OUTPUT_FOLDER, OPTION_BUILD_LOG, OPTION_DEFINE};
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
OPTION_HELP,
OPTION_VERSION,
OPTION_VERBOSE,
OPTION_OUTPUT_FOLDER,
OPTION_BUILD_LOG,
OPTION_DEFINE,
};
RawTemplaterArguments::RawTemplaterArguments()
: m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>),
@ -50,8 +64,14 @@ void RawTemplaterArguments::PrintUsage()
usage.Print();
}
bool RawTemplaterArguments::Parse(const int argc, const char** argv)
void RawTemplaterArguments::PrintVersion()
{
std::cout << "OpenAssetTools RawTemplater " << std::string(GIT_VERSION) << "\n";
}
bool RawTemplaterArguments::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
{
shouldContinue = true;
if (!m_argument_parser.ParseArguments(argc - 1, &argv[1]))
{
PrintUsage();
@ -62,7 +82,16 @@ bool RawTemplaterArguments::Parse(const int argc, const char** argv)
if (m_argument_parser.IsOptionSpecified(OPTION_HELP))
{
PrintUsage();
return false;
shouldContinue = false;
return true;
}
// Check if the user wants to see the version
if (m_argument_parser.IsOptionSpecified(OPTION_VERSION))
{
PrintVersion();
shouldContinue = false;
return true;
}
m_input_files = m_argument_parser.GetArguments();

View File

@ -14,6 +14,7 @@ class RawTemplaterArguments
* \brief Prints a command line usage help text for the RawTemplater tool to stdout.
*/
static void PrintUsage();
static void PrintVersion();
public:
bool m_verbose;
@ -27,5 +28,5 @@ public:
RawTemplaterArguments();
bool Parse(int argc, const char** argv);
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
};

View File

@ -429,9 +429,13 @@ public:
*/
bool Start(const int argc, const char** argv)
{
if (!m_args.ParseArgs(argc, argv))
auto shouldContinue = true;
if (!m_args.ParseArgs(argc, argv, shouldContinue))
return false;
if (!shouldContinue)
return true;
if (!BuildSearchPaths())
return false;

View File

@ -1,10 +1,12 @@
#include "UnlinkerArgs.h"
#include "GitVersion.h"
#include "ObjLoading.h"
#include "ObjWriting.h"
#include "Utils/Arguments/UsageInformation.h"
#include "Utils/FileUtils.h"
#include <iostream>
#include <regex>
#include <type_traits>
@ -16,6 +18,12 @@ const CommandLineOption* const OPTION_HELP =
.WithDescription("Displays usage information.")
.Build();
const CommandLineOption* const OPTION_VERSION =
CommandLineOption::Builder::Create()
.WithLongName("version")
.WithDescription("Prints the application version.")
.Build();
const CommandLineOption* const OPTION_VERBOSE =
CommandLineOption::Builder::Create()
.WithShortName("v")
@ -113,6 +121,7 @@ const CommandLineOption* const OPTION_LEGACY_MENUS =
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
OPTION_HELP,
OPTION_VERSION,
OPTION_VERBOSE,
OPTION_MINIMAL_ZONE_FILE,
OPTION_LOAD,
@ -155,6 +164,11 @@ void UnlinkerArgs::PrintUsage()
usage.Print();
}
void UnlinkerArgs::PrintVersion()
{
std::cout << "OpenAssetTools Unlinker " << std::string(GIT_VERSION) << "\n";
}
void UnlinkerArgs::SetVerbose(const bool isVerbose)
{
m_verbose = isVerbose;
@ -237,8 +251,9 @@ void UnlinkerArgs::ParseCommaSeparatedAssetTypeString(const std::string& input)
AddSpecifiedAssetType(std::string(lowerInput, currentPos, lowerInput.size() - currentPos));
}
bool UnlinkerArgs::ParseArgs(const int argc, const char** argv)
bool UnlinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
{
shouldContinue = true;
if (!m_argument_parser.ParseArguments(argc - 1, &argv[1]))
{
PrintUsage();
@ -249,7 +264,16 @@ bool UnlinkerArgs::ParseArgs(const int argc, const char** argv)
if (m_argument_parser.IsOptionSpecified(OPTION_HELP))
{
PrintUsage();
return false;
shouldContinue = false;
return true;
}
// Check if the user wants to see the version
if (m_argument_parser.IsOptionSpecified(OPTION_VERSION))
{
PrintVersion();
shouldContinue = false;
return true;
}
m_zones_to_unlink = m_argument_parser.GetArguments();

View File

@ -21,6 +21,7 @@ private:
* \brief Prints a command line usage help text for the Unlinker tool to stdout.
*/
static void PrintUsage();
static void PrintVersion();
void SetVerbose(bool isVerbose);
bool SetImageDumpingMode();
@ -60,7 +61,7 @@ public:
bool m_verbose;
UnlinkerArgs();
bool ParseArgs(int argc, const char** argv);
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
/**
* \brief Converts the output path specified by command line arguments to a path applies for the specified zone.

View File

@ -203,6 +203,8 @@ function ZoneCode:outputForAssets(assetList)
buildoutputs {
"%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.cpp",
"%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.h",
"%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.cpp",
"%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.h",
"%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_write_db.cpp",
"%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_write_db.h",
"%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_struct_test.cpp",
@ -231,6 +233,8 @@ function ZoneCode:allLoadFiles()
local assetNameLower = string.lower(assetName)
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.cpp")
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.h")
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.cpp")
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.h")
end
end
@ -302,6 +306,7 @@ function ZoneCode:project()
.. ' -c "' .. path.join(path.getabsolute(ProjectFolder()), 'ZoneCode/Game/%{file.basename}/%{file.basename}_Commands.txt') .. '"'
.. ' -o "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets"'
.. ' -g "*" ZoneLoad'
.. ' -g "*" ZoneMark'
.. ' -g "*" ZoneWrite'
.. ' -g "*" AssetStructTests'
}

View File

@ -4,6 +4,7 @@ StructureInformation::StructureInformation(DefinitionWithMembers* definition)
: m_definition(definition),
m_asset_enum_entry(nullptr),
m_is_leaf(false),
m_requires_marking(false),
m_non_embedded_reference_exists(false),
m_single_pointer_reference_exists(false),
m_array_pointer_reference_exists(false),

View File

@ -19,6 +19,7 @@ public:
std::vector<std::unique_ptr<MemberInformation>> m_ordered_members;
bool m_is_leaf;
bool m_requires_marking;
bool m_non_embedded_reference_exists;
bool m_single_pointer_reference_exists;

View File

@ -3,6 +3,7 @@
#include "Domain/Computations/StructureComputations.h"
#include "Templates/AssetStructTestsTemplate.h"
#include "Templates/ZoneLoadTemplate.h"
#include "Templates/ZoneMarkTemplate.h"
#include "Templates/ZoneWriteTemplate.h"
#include <filesystem>
@ -20,6 +21,7 @@ CodeGenerator::CodeGenerator(const ZoneCodeGeneratorArguments* args)
void CodeGenerator::SetupTemplates()
{
m_template_mapping["zoneload"] = std::make_unique<ZoneLoadTemplate>();
m_template_mapping["zonemark"] = std::make_unique<ZoneMarkTemplate>();
m_template_mapping["zonewrite"] = std::make_unique<ZoneWriteTemplate>();
m_template_mapping["assetstructtests"] = std::make_unique<AssetStructTestsTemplate>();
}

View File

@ -27,6 +27,13 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
return str.str();
}
static std::string MarkerClassName(StructureInformation* asset)
{
std::ostringstream str;
str << "Marker_" << asset->m_definition->m_name;
return str.str();
}
static std::string VariableDecl(const DataDefinition* def)
{
std::ostringstream str;
@ -155,7 +162,7 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
if (info && StructureComputations(info).IsAsset())
{
LINE(LoaderClassName(info) << " loader(m_zone, m_stream);")
LINE("AddDependency(loader.Load(" << MakeTypePtrVarName(def) << "));")
LINE("loader.Load(" << MakeTypePtrVarName(def) << ");")
}
else
{
@ -249,32 +256,6 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
LINE("}")
}
void LoadMember_ScriptString(StructureInformation* info,
MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType) const
{
if (loadType == MemberLoadType::ARRAY_POINTER)
{
LINE("varScriptString = " << MakeMemberAccess(info, member, modifier) << ";")
LINE("LoadScriptStringArray(true, " << MakeEvaluation(modifier.GetArrayPointerCountEvaluation()) << ");")
}
else if (loadType == MemberLoadType::EMBEDDED_ARRAY)
{
LINE("varScriptString = " << MakeMemberAccess(info, member, modifier) << ";")
LINE("LoadScriptStringArray(false, " << MakeArrayCount(dynamic_cast<ArrayDeclarationModifier*>(modifier.GetDeclarationModifier())) << ");")
}
else if (loadType == MemberLoadType::EMBEDDED)
{
LINE(MakeMemberAccess(info, member, modifier) << " = UseScriptString(" << MakeMemberAccess(info, member, modifier) << ");")
}
else
{
assert(false);
LINE("#error unsupported loadType " << static_cast<int>(loadType) << " for scripstring")
}
}
void LoadMember_Asset(StructureInformation* info,
MemberInformation* member,
const DeclarationModifierComputations& modifier,
@ -283,7 +264,7 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
if (loadType == MemberLoadType::SINGLE_POINTER)
{
LINE(LoaderClassName(member->m_type) << " loader(m_zone, m_stream);")
LINE("AddDependency(loader.Load(&" << MakeMemberAccess(info, member, modifier) << "));")
LINE("loader.Load(&" << MakeMemberAccess(info, member, modifier) << ");")
}
else if (loadType == MemberLoadType::POINTER_ARRAY)
{
@ -483,10 +464,6 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
{
LoadMember_String(info, member, modifier, loadType);
}
else if (member->m_is_script_string)
{
LoadMember_ScriptString(info, member, modifier, loadType);
}
else if (member->m_type && StructureComputations(member->m_type).IsAsset())
{
LoadMember_Asset(info, member, modifier, loadType);
@ -671,12 +648,6 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
LINE(MakeMemberAccess(info, member, modifier) << " = m_stream->ConvertOffsetToPointer(" << MakeMemberAccess(info, member, modifier) << ");")
if (member->m_is_script_string && loadType == MemberLoadType::ARRAY_POINTER)
{
LINE("MarkScriptStringArrayAsUsed(" << MakeMemberAccess(info, member, modifier) << ", "
<< MakeEvaluation(modifier.GetArrayPointerCountEvaluation()) << ");")
}
m_intendation--;
LINE("}")
}
@ -894,7 +865,7 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
if (computations.ShouldIgnore())
return;
if (member->m_is_string || member->m_is_script_string || computations.ContainsNonEmbeddedReference() || member->m_type && !member->m_type->m_is_leaf
if (member->m_is_string || computations.ContainsNonEmbeddedReference() || member->m_type && !member->m_type->m_is_leaf
|| computations.IsAfterPartialLoad())
{
if (info->m_definition->GetType() == DataDefinitionType::UNION)
@ -1099,7 +1070,12 @@ class ZoneLoadTemplate::Internal final : BaseTemplate
m_intendation++;
LINE("assert(pAsset != nullptr);")
LINE("m_asset_info = reinterpret_cast<XAssetInfo<" << info->m_definition->GetFullName() << ">*>(LinkAsset(GetAssetName(*pAsset), *pAsset));")
LINE("")
LINE(MarkerClassName(m_env.m_asset) << " marker(m_zone);")
LINE("marker.Mark(*pAsset);")
LINE("")
LINE("m_asset_info = reinterpret_cast<XAssetInfo<"
<< info->m_definition->GetFullName() << ">*>(LinkAsset(GetAssetName(*pAsset), *pAsset, marker.GetUsedScriptStrings(), marker.GetDependencies()));")
LINE("*pAsset = m_asset_info->Asset();")
m_intendation--;
@ -1272,6 +1248,7 @@ public:
LINE("// ====================================================================")
LINE("")
LINE("#include \"" << Lower(m_env.m_asset->m_definition->m_name) << "_load_db.h\"")
LINE("#include \"" << Lower(m_env.m_asset->m_definition->m_name) << "_mark_db.h\"")
LINE("#include <cassert>")
LINE("")

View File

@ -0,0 +1,823 @@
#include "ZoneMarkTemplate.h"
#include "Domain/Computations/MemberComputations.h"
#include "Domain/Computations/StructureComputations.h"
#include "Internal/BaseTemplate.h"
#include "Utils/StringUtils.h"
#include <cassert>
#include <iostream>
#include <sstream>
class ZoneMarkTemplate::Internal final : BaseTemplate
{
enum class MemberLoadType
{
ARRAY_POINTER,
DYNAMIC_ARRAY,
EMBEDDED,
EMBEDDED_ARRAY,
POINTER_ARRAY,
SINGLE_POINTER
};
static std::string MarkerClassName(StructureInformation* asset)
{
std::ostringstream str;
str << "Marker_" << asset->m_definition->m_name;
return str.str();
}
static std::string VariableDecl(const DataDefinition* def)
{
std::ostringstream str;
str << def->GetFullName() << "* var" << MakeSafeTypeName(def) << ";";
return str.str();
}
static std::string PointerVariableDecl(const DataDefinition* def)
{
std::ostringstream str;
str << def->GetFullName() << "** var" << MakeSafeTypeName(def) << "Ptr;";
return str.str();
}
void PrintHeaderPtrArrayMarkMethodDeclaration(const DataDefinition* def) const
{
LINE("void MarkPtrArray_" << MakeSafeTypeName(def) << "(size_t count);")
}
void PrintHeaderArrayMarkMethodDeclaration(const DataDefinition* def) const
{
LINE("void MarkArray_" << MakeSafeTypeName(def) << "(size_t count);")
}
void PrintHeaderMarkMethodDeclaration(const StructureInformation* info) const
{
LINE("void Mark_" << MakeSafeTypeName(info->m_definition) << "();")
}
void PrintHeaderGetAssetInfoMethodDeclaration(const StructureInformation* info) const
{
LINE("XAssetInfo<" << info->m_definition->GetFullName() << ">* GetAssetInfo(" << info->m_definition->GetFullName() << "* pAsset) const;")
}
void PrintHeaderGetNameMethodDeclaration(const StructureInformation* info) const
{
LINE("static std::string GetAssetName(" << info->m_definition->GetFullName() << "* pAsset);")
}
void PrintHeaderConstructor() const
{
LINE(MarkerClassName(m_env.m_asset) << "(Zone* zone);")
}
void PrintHeaderMainMarkMethodDeclaration(const StructureInformation* info) const
{
LINE("void Mark(" << info->m_definition->GetFullName() << "* pAsset);")
}
void PrintVariableInitialization(const DataDefinition* def) const
{
LINE("var" << def->m_name << " = nullptr;")
}
void PrintPointerVariableInitialization(const DataDefinition* def) const
{
LINE("var" << def->m_name << "Ptr = nullptr;")
}
void PrintConstructorMethod()
{
LINE(MarkerClassName(m_env.m_asset) << "::" << MarkerClassName(m_env.m_asset) << "(Zone* zone)")
m_intendation++;
LINE(": AssetMarker(" << m_env.m_asset->m_asset_enum_entry->m_name << ", zone)")
m_intendation--;
LINE("{")
m_intendation++;
PrintVariableInitialization(m_env.m_asset->m_definition);
PrintPointerVariableInitialization(m_env.m_asset->m_definition);
LINE("")
for (const auto* type : m_env.m_used_types)
{
if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset())
{
PrintVariableInitialization(type->m_type);
}
}
for (const auto* type : m_env.m_used_types)
{
if (type->m_info && type->m_pointer_array_reference_exists && !type->m_is_context_asset)
{
PrintPointerVariableInitialization(type->m_type);
}
}
m_intendation--;
LINE("}")
}
void PrintMarkPtrArrayMethod_Loading(const DataDefinition* def, const StructureInformation* info) const
{
if (info && !info->m_is_leaf)
{
LINE(MakeTypeVarName(info->m_definition) << " = *" << MakeTypePtrVarName(def) << ";")
LINE("Mark_" << MakeSafeTypeName(def) << "();")
}
}
void PrintMarkPtrArrayMethod_PointerCheck(const DataDefinition* def, StructureInformation* info, const bool reusable)
{
LINE("if (*" << MakeTypePtrVarName(def) << ")")
LINE("{")
m_intendation++;
if (info && StructureComputations(info).IsAsset())
{
LINE("AddDependency(" << MarkerClassName(info) << "(m_zone).GetAssetInfo(*" << MakeTypePtrVarName(def) << "));")
}
else
{
PrintMarkPtrArrayMethod_Loading(def, info);
}
m_intendation--;
LINE("}")
}
void PrintMarkPtrArrayMethod(const DataDefinition* def, StructureInformation* info, const bool reusable)
{
LINE("void " << MarkerClassName(m_env.m_asset) << "::MarkPtrArray_" << MakeSafeTypeName(def) << "(const size_t count)")
LINE("{")
m_intendation++;
LINE("assert(" << MakeTypePtrVarName(def) << " != nullptr);")
LINE("")
LINE(def->GetFullName() << "** var = " << MakeTypePtrVarName(def) << ";")
LINE("for(size_t index = 0; index < count; index++)")
LINE("{")
m_intendation++;
LINE(MakeTypePtrVarName(def) << " = var;")
PrintMarkPtrArrayMethod_PointerCheck(def, info, reusable);
LINE("")
LINE("var++;")
m_intendation--;
LINE("}")
m_intendation--;
LINE("}")
}
void PrintMarkArrayMethod(const DataDefinition* def, const StructureInformation* info)
{
LINE("void " << MarkerClassName(m_env.m_asset) << "::MarkArray_" << MakeSafeTypeName(def) << "(const size_t count)")
LINE("{")
m_intendation++;
LINE("assert(" << MakeTypeVarName(def) << " != nullptr);")
LINE("")
LINE(def->GetFullName() << "* var = " << MakeTypeVarName(def) << ";")
LINE("for(size_t index = 0; index < count; index++)")
LINE("{")
m_intendation++;
LINE(MakeTypeVarName(info->m_definition) << " = var;")
LINE("Mark_" << info->m_definition->m_name << "();")
LINE("var++;")
m_intendation--;
LINE("}")
m_intendation--;
LINE("}")
}
void MarkMember_ScriptString(StructureInformation* info,
MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType) const
{
if (loadType == MemberLoadType::ARRAY_POINTER)
{
LINE("MarkArray_ScriptString(" << MakeMemberAccess(info, member, modifier) << ", " << MakeEvaluation(modifier.GetArrayPointerCountEvaluation())
<< ");")
}
else if (loadType == MemberLoadType::EMBEDDED_ARRAY)
{
LINE("MarkArray_ScriptString(" << MakeMemberAccess(info, member, modifier) << ", "
<< MakeArrayCount(dynamic_cast<ArrayDeclarationModifier*>(modifier.GetDeclarationModifier())) << ");")
}
else if (loadType == MemberLoadType::EMBEDDED)
{
LINE("Mark_ScriptString(" << MakeMemberAccess(info, member, modifier) << ");")
}
else
{
assert(false);
LINE("#error unsupported loadType " << static_cast<int>(loadType) << " for scriptstring")
}
}
void MarkMember_Asset(StructureInformation* info,
MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType) const
{
if (loadType == MemberLoadType::SINGLE_POINTER)
{
LINE("AddDependency(" << MarkerClassName(member->m_type) << "(m_zone).GetAssetInfo(" << MakeMemberAccess(info, member, modifier) << "));")
}
else if (loadType == MemberLoadType::POINTER_ARRAY)
{
MarkMember_PointerArray(info, member, modifier);
}
else
{
assert(false);
LINE("#error unsupported loadType " << static_cast<int>(loadType) << " for asset")
}
}
void MarkMember_ArrayPointer(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
LINE(MakeTypeVarName(member->m_member->m_type_declaration->m_type) << " = " << MakeMemberAccess(info, member, modifier) << ";")
LINE("MarkArray_" << MakeSafeTypeName(member->m_member->m_type_declaration->m_type) << "(" << MakeEvaluation(modifier.GetArrayPointerCountEvaluation())
<< ");")
}
void MarkMember_PointerArray(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
LINE(MakeTypePtrVarName(member->m_member->m_type_declaration->m_type) << " = " << MakeMemberAccess(info, member, modifier) << ";")
if (modifier.IsArray())
{
LINE("MarkPtrArray_" << MakeSafeTypeName(member->m_member->m_type_declaration->m_type) << "(" << modifier.GetArraySize() << ");")
}
else
{
LINE("MarkPtrArray_" << MakeSafeTypeName(member->m_member->m_type_declaration->m_type) << "("
<< MakeEvaluation(modifier.GetPointerArrayCountEvaluation()) << ");")
}
}
void MarkMember_EmbeddedArray(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
const MemberComputations computations(member);
std::string arraySizeStr;
if (modifier.HasDynamicArrayCount())
arraySizeStr = MakeEvaluation(modifier.GetDynamicArrayCountEvaluation());
else
arraySizeStr = std::to_string(modifier.GetArraySize());
LINE(MakeTypeVarName(member->m_member->m_type_declaration->m_type) << " = " << MakeMemberAccess(info, member, modifier) << ";")
LINE("MarkArray_" << MakeSafeTypeName(member->m_member->m_type_declaration->m_type) << "(" << arraySizeStr << ");")
}
void MarkMember_DynamicArray(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
LINE(MakeTypeVarName(member->m_member->m_type_declaration->m_type) << " = " << MakeMemberAccess(info, member, modifier) << ";")
LINE("MarkArray_" << MakeSafeTypeName(member->m_member->m_type_declaration->m_type) << "(" << MakeEvaluation(modifier.GetDynamicArraySizeEvaluation())
<< ");")
}
void MarkMember_Embedded(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
LINE(MakeTypeVarName(member->m_member->m_type_declaration->m_type) << " = &" << MakeMemberAccess(info, member, modifier) << ";")
LINE("Mark_" << MakeSafeTypeName(member->m_member->m_type_declaration->m_type) << "();")
}
void MarkMember_SinglePointer(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
LINE(MakeTypeVarName(member->m_member->m_type_declaration->m_type) << " = " << MakeMemberAccess(info, member, modifier) << ";")
LINE("Mark_" << MakeSafeTypeName(member->m_type->m_definition) << "();")
}
void MarkMember_TypeCheck(StructureInformation* info,
MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType) const
{
if (member->m_is_script_string)
{
MarkMember_ScriptString(info, member, modifier, loadType);
}
else if (member->m_type && StructureComputations(member->m_type).IsAsset())
{
MarkMember_Asset(info, member, modifier, loadType);
}
else
{
switch (loadType)
{
case MemberLoadType::ARRAY_POINTER:
MarkMember_ArrayPointer(info, member, modifier);
break;
case MemberLoadType::SINGLE_POINTER:
MarkMember_SinglePointer(info, member, modifier);
break;
case MemberLoadType::EMBEDDED:
MarkMember_Embedded(info, member, modifier);
break;
case MemberLoadType::POINTER_ARRAY:
MarkMember_PointerArray(info, member, modifier);
break;
case MemberLoadType::DYNAMIC_ARRAY:
MarkMember_DynamicArray(info, member, modifier);
break;
case MemberLoadType::EMBEDDED_ARRAY:
MarkMember_EmbeddedArray(info, member, modifier);
break;
default:
LINE("// t=" << static_cast<int>(loadType))
break;
}
}
}
static bool MarkMember_ShouldMakePointerCheck(StructureInformation* info,
MemberInformation* member,
const DeclarationModifierComputations& modifier,
MemberLoadType loadType)
{
if (loadType != MemberLoadType::ARRAY_POINTER && loadType != MemberLoadType::POINTER_ARRAY && loadType != MemberLoadType::SINGLE_POINTER)
{
return false;
}
if (loadType == MemberLoadType::POINTER_ARRAY)
{
return !modifier.IsArray();
}
if (member->m_is_string)
{
return false;
}
return true;
}
void MarkMember_PointerCheck(StructureInformation* info,
MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType)
{
if (MarkMember_ShouldMakePointerCheck(info, member, modifier, loadType))
{
LINE("if (" << MakeMemberAccess(info, member, modifier) << ")")
LINE("{")
m_intendation++;
MarkMember_TypeCheck(info, member, modifier, loadType);
m_intendation--;
LINE("}")
}
else
{
MarkMember_TypeCheck(info, member, modifier, loadType);
}
}
void MarkMember_ReferenceArray(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier)
{
auto first = true;
for (const auto& entry : modifier.GetArrayEntries())
{
if (first)
{
first = false;
}
else
{
LINE("")
}
MarkMember_Reference(info, member, entry);
}
}
void MarkMember_Reference(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier)
{
if (modifier.IsDynamicArray())
{
MarkMember_PointerCheck(info, member, modifier, MemberLoadType::DYNAMIC_ARRAY);
}
else if (modifier.IsSinglePointer())
{
MarkMember_PointerCheck(info, member, modifier, MemberLoadType::SINGLE_POINTER);
}
else if (modifier.IsArrayPointer())
{
MarkMember_PointerCheck(info, member, modifier, MemberLoadType::ARRAY_POINTER);
}
else if (modifier.IsPointerArray())
{
MarkMember_PointerCheck(info, member, modifier, MemberLoadType::POINTER_ARRAY);
}
else if (modifier.IsArray() && modifier.GetNextDeclarationModifier() == nullptr)
{
MarkMember_PointerCheck(info, member, modifier, MemberLoadType::EMBEDDED_ARRAY);
}
else if (modifier.GetDeclarationModifier() == nullptr)
{
MarkMember_PointerCheck(info, member, modifier, MemberLoadType::EMBEDDED);
}
else if (modifier.IsArray())
{
MarkMember_ReferenceArray(info, member, modifier);
}
else
{
assert(false);
LINE("#error MarkMemberReference failed @ " << member->m_member->m_name)
}
}
void MarkMember_Condition_Struct(StructureInformation* info, MemberInformation* member)
{
LINE("")
if (member->m_condition)
{
LINE("if (" << MakeEvaluation(member->m_condition.get()) << ")")
LINE("{")
m_intendation++;
MarkMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
MarkMember_Reference(info, member, DeclarationModifierComputations(member));
}
}
void MarkMember_Condition_Union(StructureInformation* info, MemberInformation* member)
{
const MemberComputations computations(member);
if (computations.IsFirstMember())
{
LINE("")
if (member->m_condition)
{
LINE("if (" << MakeEvaluation(member->m_condition.get()) << ")")
LINE("{")
m_intendation++;
MarkMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
MarkMember_Reference(info, member, DeclarationModifierComputations(member));
}
}
else if (computations.IsLastMember())
{
if (member->m_condition)
{
LINE("else if (" << MakeEvaluation(member->m_condition.get()) << ")")
LINE("{")
m_intendation++;
MarkMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
LINE("else")
LINE("{")
m_intendation++;
MarkMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
}
else
{
if (member->m_condition)
{
LINE("else if (" << MakeEvaluation(member->m_condition.get()) << ")")
LINE("{")
m_intendation++;
MarkMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
LINE("#error Middle member of union must have condition (" << member->m_member->m_name << ")")
}
}
}
void PrintMarkMemberIfNeedsTreatment(StructureInformation* info, MemberInformation* member)
{
const MemberComputations computations(member);
if (computations.ShouldIgnore() || computations.IsInRuntimeBlock())
return;
if (member->m_is_script_string || member->m_type && (member->m_type->m_requires_marking || StructureComputations(member->m_type).IsAsset()))
{
if (info->m_definition->GetType() == DataDefinitionType::UNION)
MarkMember_Condition_Union(info, member);
else
MarkMember_Condition_Struct(info, member);
}
}
void PrintMarkMethod(StructureInformation* info)
{
const StructureComputations computations(info);
LINE("void " << MarkerClassName(m_env.m_asset) << "::Mark_" << info->m_definition->m_name << "()")
LINE("{")
m_intendation++;
LINE("assert(" << MakeTypeVarName(info->m_definition) << " != nullptr);")
for (const auto& member : info->m_ordered_members)
{
PrintMarkMemberIfNeedsTreatment(info, member.get());
}
m_intendation--;
LINE("}")
}
void PrintGetNameMethod()
{
LINE("std::string " << MarkerClassName(m_env.m_asset) << "::GetAssetName(" << m_env.m_asset->m_definition->GetFullName() << "* pAsset)")
LINE("{")
m_intendation++;
if (!m_env.m_asset->m_name_chain.empty())
{
LINE_START("return pAsset")
auto first = true;
for (auto* member : m_env.m_asset->m_name_chain)
{
if (first)
{
first = false;
LINE_MIDDLE("->" << member->m_member->m_name)
}
else
{
LINE_MIDDLE("." << member->m_member->m_name)
}
}
LINE_END(";")
}
else
{
LINE("return \"" << m_env.m_asset->m_definition->m_name << "\";")
}
m_intendation--;
LINE("}")
}
void PrintGetAssetInfoMethod()
{
LINE("XAssetInfo<" << m_env.m_asset->m_definition->GetFullName() << ">* " << MarkerClassName(m_env.m_asset) << "::GetAssetInfo("
<< m_env.m_asset->m_definition->GetFullName() << "* pAsset) const")
LINE("{")
m_intendation++;
LINE("return reinterpret_cast<XAssetInfo<" << m_env.m_asset->m_definition->GetFullName() << ">*>(GetAssetInfoByName(GetAssetName(pAsset)));")
m_intendation--;
LINE("}")
}
void PrintMainMarkMethod()
{
LINE("void " << MarkerClassName(m_env.m_asset) << "::Mark(" << m_env.m_asset->m_definition->GetFullName() << "* pAsset)")
LINE("{")
m_intendation++;
LINE("assert(pAsset != nullptr);")
LINE("")
LINE(MakeTypeVarName(m_env.m_asset->m_definition) << " = pAsset;")
LINE("Mark_" << MakeSafeTypeName(m_env.m_asset->m_definition) << "();")
m_intendation--;
LINE("}")
}
public:
Internal(std::ostream& stream, RenderingContext* context)
: BaseTemplate(stream, context)
{
}
void Header()
{
LINE("// ====================================================================")
LINE("// This file has been generated by ZoneCodeGenerator.")
LINE("// Do not modify. ")
LINE("// Any changes will be discarded when regenerating.")
LINE("// ====================================================================")
LINE("")
LINE("#pragma once")
LINE("")
LINE("#include \"Loading/AssetMarker.h\"")
LINE("#include \"Game/" << m_env.m_game << "/" << m_env.m_game << ".h\"")
LINE("#include <string>")
LINE("")
LINE("namespace " << m_env.m_game)
LINE("{")
m_intendation++;
LINE("class " << MarkerClassName(m_env.m_asset) << " final : public AssetMarker")
LINE("{")
m_intendation++;
LINE(VariableDecl(m_env.m_asset->m_definition))
LINE(PointerVariableDecl(m_env.m_asset->m_definition))
LINE("")
m_intendation--;
LINE("public:")
m_intendation++;
// Variable Declarations: type varType;
for (auto* type : m_env.m_used_types)
{
if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset())
{
LINE(VariableDecl(type->m_type))
}
}
for (auto* type : m_env.m_used_types)
{
if (type->m_pointer_array_reference_exists && !type->m_is_context_asset)
{
LINE(PointerVariableDecl(type->m_type))
}
}
LINE("")
// Method Declarations
for (auto* type : m_env.m_used_types)
{
if (type->m_pointer_array_reference_exists && type->m_info->m_requires_marking)
{
PrintHeaderPtrArrayMarkMethodDeclaration(type->m_type);
}
}
for (auto* type : m_env.m_used_types)
{
if (type->m_array_reference_exists && type->m_info && !type->m_info->m_is_leaf && type->m_info->m_requires_marking
&& type->m_non_runtime_reference_exists)
{
PrintHeaderArrayMarkMethodDeclaration(type->m_type);
}
}
for (const auto* type : m_env.m_used_structures)
{
if (type->m_non_runtime_reference_exists && !type->m_info->m_is_leaf && type->m_info->m_requires_marking
&& !StructureComputations(type->m_info).IsAsset())
{
PrintHeaderMarkMethodDeclaration(type->m_info);
}
}
PrintHeaderMarkMethodDeclaration(m_env.m_asset);
LINE("")
PrintHeaderGetNameMethodDeclaration(m_env.m_asset);
PrintHeaderGetAssetInfoMethodDeclaration(m_env.m_asset);
LINE("")
PrintHeaderConstructor();
PrintHeaderMainMarkMethodDeclaration(m_env.m_asset);
m_intendation--;
LINE("};")
m_intendation--;
LINE("}")
}
void Source()
{
LINE("// ====================================================================")
LINE("// This file has been generated by ZoneCodeGenerator.")
LINE("// Do not modify. ")
LINE("// Any changes will be discarded when regenerating.")
LINE("// ====================================================================")
LINE("")
LINE("#include \"" << Lower(m_env.m_asset->m_definition->m_name) << "_mark_db.h\"")
LINE("#include <cassert>")
LINE("")
if (!m_env.m_referenced_assets.empty())
{
LINE("// Referenced Assets:")
for (const auto* type : m_env.m_referenced_assets)
{
LINE("#include \"../" << Lower(type->m_type->m_name) << "/" << Lower(type->m_type->m_name) << "_mark_db.h\"")
}
LINE("")
}
LINE("using namespace " << m_env.m_game << ";")
LINE("")
PrintConstructorMethod();
for (const auto* type : m_env.m_used_types)
{
if (type->m_pointer_array_reference_exists && type->m_info->m_requires_marking)
{
LINE("")
PrintMarkPtrArrayMethod(type->m_type, type->m_info, type->m_pointer_array_reference_is_reusable);
}
}
for (const auto* type : m_env.m_used_types)
{
if (type->m_array_reference_exists && type->m_info && !type->m_info->m_is_leaf && type->m_info->m_requires_marking
&& type->m_non_runtime_reference_exists)
{
LINE("")
PrintMarkArrayMethod(type->m_type, type->m_info);
}
}
for (const auto* type : m_env.m_used_structures)
{
if (type->m_non_runtime_reference_exists && !type->m_info->m_is_leaf && type->m_info->m_requires_marking
&& !StructureComputations(type->m_info).IsAsset())
{
LINE("")
PrintMarkMethod(type->m_info);
}
}
LINE("")
PrintMarkMethod(m_env.m_asset);
LINE("")
PrintMainMarkMethod();
LINE("")
PrintGetNameMethod();
PrintGetAssetInfoMethod();
}
};
std::vector<CodeTemplateFile> ZoneMarkTemplate::GetFilesToRender(RenderingContext* context)
{
std::vector<CodeTemplateFile> files;
auto assetName = context->m_asset->m_definition->m_name;
utils::MakeStringLowerCase(assetName);
{
std::ostringstream str;
str << assetName << '/' << assetName << "_mark_db.h";
files.emplace_back(str.str(), TAG_HEADER);
}
{
std::ostringstream str;
str << assetName << '/' << assetName << "_mark_db.cpp";
files.emplace_back(str.str(), TAG_SOURCE);
}
return files;
}
void ZoneMarkTemplate::RenderFile(std::ostream& stream, const int fileTag, RenderingContext* context)
{
Internal internal(stream, context);
if (fileTag == TAG_HEADER)
{
internal.Header();
}
else if (fileTag == TAG_SOURCE)
{
internal.Source();
}
else
{
std::cout << "Unknown tag for ZoneMarkTemplate: " << fileTag << "\n";
}
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Generating/ICodeTemplate.h"
class ZoneMarkTemplate final : public ICodeTemplate
{
static constexpr int TAG_HEADER = 1;
static constexpr int TAG_SOURCE = 2;
class Internal;
public:
std::vector<CodeTemplateFile> GetFilesToRender(RenderingContext* context) override;
void RenderFile(std::ostream& stream, int fileTag, RenderingContext* context) override;
};

View File

@ -8,6 +8,7 @@
#include "Parsing/Impl/ParserFilesystemStream.h"
#include "Parsing/PostProcessing/CalculateSizeAndAlignPostProcessor.h"
#include "Parsing/PostProcessing/LeafsPostProcessor.h"
#include "Parsing/PostProcessing/MarkingRequiredPostProcessor.h"
#include "Parsing/PostProcessing/MemberLeafsPostProcessor.h"
#include "Parsing/PostProcessing/UnionsPostProcessor.h"
#include "Parsing/PostProcessing/UsagesPostProcessor.h"
@ -58,6 +59,7 @@ void CommandsFileReader::SetupPostProcessors()
m_post_processors.emplace_back(std::make_unique<CalculateSizeAndAlignPostProcessor>());
m_post_processors.emplace_back(std::make_unique<UsagesPostProcessor>());
m_post_processors.emplace_back(std::make_unique<LeafsPostProcessor>());
m_post_processors.emplace_back(std::make_unique<MarkingRequiredPostProcessor>());
m_post_processors.emplace_back(std::make_unique<MemberLeafsPostProcessor>());
m_post_processors.emplace_back(std::make_unique<UnionsPostProcessor>());
}

View File

@ -0,0 +1,76 @@
#include "MarkingRequiredPostProcessor.h"
#include "Domain/Computations/MemberComputations.h"
#include "Domain/Computations/StructureComputations.h"
#include "Domain/Definition/PointerDeclarationModifier.h"
#include <unordered_set>
bool MarkingRequiredPostProcessor::CalculateRequiresMarking(std::unordered_set<const void*>& visitedStructures, StructureInformation* info)
{
if (visitedStructures.find(info) != visitedStructures.end())
return info->m_requires_marking;
visitedStructures.emplace(info);
if (info->m_asset_enum_entry)
{
info->m_requires_marking = true;
return true;
}
for (const auto& member : info->m_ordered_members)
{
// If there is a condition to this member, and it always evaluates to false: Skip this member
if (member->m_condition && member->m_condition->IsStatic() && member->m_condition->EvaluateNumeric() == 0)
continue;
// Skip if it has a pointer evaluation that always resolves to 0
auto skip = false;
for (const auto& modifier : member->m_member->m_type_declaration->m_declaration_modifiers)
{
if (modifier->GetType() == DeclarationModifierType::POINTER)
{
const auto* pointer = dynamic_cast<PointerDeclarationModifier*>(modifier.get());
const auto* countEvaluation = pointer->GetCountEvaluation();
if (countEvaluation->IsStatic() && countEvaluation->EvaluateNumeric() == 0)
{
skip = true;
break;
}
}
}
if (skip)
continue;
// Any ScriptStrings or Strings need to be processed.
if (member->m_is_script_string || member->m_type && member->m_type->m_asset_enum_entry)
{
info->m_requires_marking = true;
return true;
}
if (member->m_type != nullptr && member->m_type != info && CalculateRequiresMarking(visitedStructures, member->m_type))
{
info->m_requires_marking = true;
return true;
}
}
info->m_requires_marking = false;
return false;
}
bool MarkingRequiredPostProcessor::PostProcess(IDataRepository* repository)
{
const auto& allInfos = repository->GetAllStructureInformation();
std::unordered_set<const void*> visitedStructures;
for (const auto& info : allInfos)
{
CalculateRequiresMarking(visitedStructures, info);
}
return true;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "IPostProcessor.h"
#include <unordered_set>
class MarkingRequiredPostProcessor final : public IPostProcessor
{
static bool CalculateRequiresMarking(std::unordered_set<const void*>& visitedStructures, StructureInformation* info);
public:
bool PostProcess(IDataRepository* repository) override;
};

View File

@ -64,9 +64,13 @@ public:
int Run(const int argc, const char** argv)
{
if (!m_args.Parse(argc, argv))
auto shouldContinue = true;
if (!m_args.ParseArgs(argc, argv, shouldContinue))
return 1;
if (!shouldContinue)
return 0;
if (!ReadHeaderData() || !ReadCommandsData())
return 1;

View File

@ -1,5 +1,6 @@
#include "ZoneCodeGeneratorArguments.h"
#include "GitVersion.h"
#include "Utils/Arguments/CommandLineOption.h"
#include "Utils/Arguments/UsageInformation.h"
@ -9,6 +10,9 @@
const CommandLineOption* const OPTION_HELP =
CommandLineOption::Builder::Create().WithShortName("?").WithLongName("help").WithDescription("Displays usage information.").Build();
const CommandLineOption* const OPTION_VERSION =
CommandLineOption::Builder::Create().WithLongName("version").WithDescription("Prints the application version.").Build();
const CommandLineOption* const OPTION_VERBOSE =
CommandLineOption::Builder::Create().WithShortName("v").WithLongName("verbose").WithDescription("Outputs a lot more and more detailed messages.").Build();
@ -70,7 +74,15 @@ const CommandLineOption* const OPTION_GENERATE =
.Build();
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
OPTION_HELP, OPTION_VERBOSE, OPTION_HEADER, OPTION_COMMANDS_FILE, OPTION_OUTPUT_FOLDER, OPTION_PRINT, OPTION_GENERATE};
OPTION_HELP,
OPTION_VERSION,
OPTION_VERBOSE,
OPTION_HEADER,
OPTION_COMMANDS_FILE,
OPTION_OUTPUT_FOLDER,
OPTION_PRINT,
OPTION_GENERATE,
};
ZoneCodeGeneratorArguments::GenerationTask::GenerationTask()
: m_all_assets(false)
@ -91,7 +103,7 @@ ZoneCodeGeneratorArguments::GenerationTask::GenerationTask(std::string assetName
}
ZoneCodeGeneratorArguments::ZoneCodeGeneratorArguments()
: m_argument_parser(COMMAND_LINE_OPTIONS, std::extent<decltype(COMMAND_LINE_OPTIONS)>::value),
: m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>),
m_task_flags(0)
{
m_verbose = false;
@ -109,8 +121,14 @@ void ZoneCodeGeneratorArguments::PrintUsage()
usage.Print();
}
bool ZoneCodeGeneratorArguments::Parse(const int argc, const char** argv)
void ZoneCodeGeneratorArguments::PrintVersion()
{
std::cout << "OpenAssetTools ZoneCodeGenerator " << std::string(GIT_VERSION) << "\n";
}
bool ZoneCodeGeneratorArguments::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
{
shouldContinue = true;
if (!m_argument_parser.ParseArguments(argc - 1, &argv[1]))
{
PrintUsage();
@ -121,7 +139,16 @@ bool ZoneCodeGeneratorArguments::Parse(const int argc, const char** argv)
if (m_argument_parser.IsOptionSpecified(OPTION_HELP))
{
PrintUsage();
return false;
shouldContinue = false;
return true;
}
// Check if the user wants to see the version
if (m_argument_parser.IsOptionSpecified(OPTION_VERSION))
{
PrintVersion();
shouldContinue = false;
return true;
}
// -v; --verbose

View File

@ -13,6 +13,7 @@ class ZoneCodeGeneratorArguments
* \brief Prints a command line usage help text for the Unlinker tool to stdout.
*/
static void PrintUsage();
static void PrintVersion();
public:
static constexpr unsigned FLAG_TASK_GENERATE = 1 << 0;
@ -40,8 +41,7 @@ public:
std::vector<GenerationTask> m_generation_tasks;
ZoneCodeGeneratorArguments();
bool Parse(int argc, const char** argv);
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
_NODISCARD bool ShouldGenerate() const;
_NODISCARD bool ShouldPrint() const;

View File

@ -10,73 +10,10 @@ AssetLoader::AssetLoader(const asset_type_t assetType, Zone* zone, IZoneInputStr
{
}
void AssetLoader::AddDependency(XAssetInfoGeneric* assetInfo)
XAssetInfoGeneric*
AssetLoader::LinkAsset(std::string name, void* asset, std::vector<scr_string_t> scriptStrings, std::vector<XAssetInfoGeneric*> dependencies) const
{
if (assetInfo == nullptr)
return;
const auto existingEntry = std::find(m_dependencies.begin(), m_dependencies.end(), assetInfo);
if (existingEntry != m_dependencies.end())
{
return;
}
m_dependencies.push_back(assetInfo);
}
scr_string_t AssetLoader::UseScriptString(const scr_string_t scrString)
{
assert(scrString < m_zone->m_script_strings.Count());
if (scrString >= m_zone->m_script_strings.Count())
return 0u;
m_used_script_strings.emplace(scrString);
return scrString;
}
void AssetLoader::LoadScriptStringArray(const bool atStreamStart, const size_t count)
{
assert(varScriptString != nullptr);
if (atStreamStart)
m_stream->Load<scr_string_t>(varScriptString, count);
auto* ptr = varScriptString;
for (size_t index = 0; index < count; index++)
{
*ptr = UseScriptString(*ptr);
ptr++;
}
}
void AssetLoader::MarkScriptStringArrayAsUsed(const scr_string_t* scrStringArray, const size_t count)
{
for (size_t index = 0; index < count; index++)
{
const auto scrString = scrStringArray[index];
if (scrString >= m_zone->m_script_strings.Count())
continue;
m_used_script_strings.emplace(scrString);
}
}
XAssetInfoGeneric* AssetLoader::LinkAsset(std::string name, void* asset)
{
std::vector<scr_string_t> usedScriptStrings;
if (!m_used_script_strings.empty())
{
for (auto scrString : m_used_script_strings)
{
usedScriptStrings.push_back(scrString);
}
std::sort(usedScriptStrings.begin(), usedScriptStrings.end());
m_used_script_strings.clear();
}
return m_zone->m_pools->AddAsset(m_asset_type, std::move(name), asset, std::move(m_dependencies), std::move(usedScriptStrings));
return m_zone->m_pools->AddAsset(m_asset_type, std::move(name), asset, std::move(dependencies), std::move(scriptStrings));
}
XAssetInfoGeneric* AssetLoader::GetAssetInfo(std::string name) const

View File

@ -11,21 +11,12 @@ class AssetLoader : public ContentLoaderBase
{
asset_type_t m_asset_type;
std::vector<XAssetInfoGeneric*> m_dependencies;
std::unordered_set<scr_string_t> m_used_script_strings;
protected:
scr_string_t* varScriptString;
AssetLoader(asset_type_t assetType, Zone* zone, IZoneInputStream* stream);
void AddDependency(XAssetInfoGeneric* assetInfo);
XAssetInfoGeneric* LinkAsset(std::string name, void* asset, std::vector<scr_string_t> scriptStrings, std::vector<XAssetInfoGeneric*> dependencies) const;
scr_string_t UseScriptString(scr_string_t scrString);
void LoadScriptStringArray(bool atStreamStart, size_t count);
void MarkScriptStringArrayAsUsed(const scr_string_t* scrStringArray, size_t count);
XAssetInfoGeneric* LinkAsset(std::string name, void* asset);
XAssetInfoGeneric* GetAssetInfo(std::string name) const;
_NODISCARD XAssetInfoGeneric* GetAssetInfo(std::string name) const;
};

View File

@ -0,0 +1,73 @@
#include "AssetMarker.h"
#include <algorithm>
#include <cassert>
AssetMarker::AssetMarker(const asset_type_t assetType, Zone* zone)
: m_asset_type(assetType),
m_zone(zone)
{
}
void AssetMarker::AddDependency(XAssetInfoGeneric* assetInfo)
{
if (assetInfo == nullptr)
return;
const auto existingEntry = m_dependencies.find(assetInfo);
if (existingEntry != m_dependencies.end())
return;
m_dependencies.emplace(assetInfo);
}
void AssetMarker::Mark_ScriptString(const scr_string_t scrString)
{
assert(scrString < m_zone->m_script_strings.Count());
if (scrString >= m_zone->m_script_strings.Count())
return;
m_used_script_strings.emplace(scrString);
}
void AssetMarker::MarkArray_ScriptString(const scr_string_t* scrStringArray, const size_t count)
{
assert(scrStringArray != nullptr);
for (size_t index = 0; index < count; index++)
Mark_ScriptString(scrStringArray[index]);
}
XAssetInfoGeneric* AssetMarker::GetAssetInfoByName(std::string name) const
{
return m_zone->m_pools->GetAsset(m_asset_type, std::move(name));
}
std::vector<XAssetInfoGeneric*> AssetMarker::GetDependencies() const
{
std::vector<XAssetInfoGeneric*> dependencies;
if (!m_dependencies.empty())
{
dependencies.reserve(m_dependencies.size());
for (auto dependency : m_dependencies)
dependencies.push_back(dependency);
}
return dependencies;
}
std::vector<scr_string_t> AssetMarker::GetUsedScriptStrings() const
{
std::vector<scr_string_t> usedScriptStrings;
if (!m_used_script_strings.empty())
{
usedScriptStrings.reserve(m_used_script_strings.size());
for (auto scrString : m_used_script_strings)
usedScriptStrings.push_back(scrString);
std::sort(usedScriptStrings.begin(), usedScriptStrings.end());
}
return usedScriptStrings;
}

View File

@ -0,0 +1,32 @@
#pragma once
#include "ContentLoaderBase.h"
#include "Pool/XAssetInfo.h"
#include "Utils/ClassUtils.h"
#include "Zone/ZoneTypes.h"
#include <unordered_set>
class AssetMarker
{
asset_type_t m_asset_type;
std::unordered_set<XAssetInfoGeneric*> m_dependencies;
std::unordered_set<scr_string_t> m_used_script_strings;
protected:
AssetMarker(asset_type_t assetType, Zone* zone);
void AddDependency(XAssetInfoGeneric* assetInfo);
void Mark_ScriptString(scr_string_t scrString);
void MarkArray_ScriptString(const scr_string_t* scrStringArray, size_t count);
_NODISCARD XAssetInfoGeneric* GetAssetInfoByName(std::string name) const;
Zone* m_zone;
public:
_NODISCARD std::vector<XAssetInfoGeneric*> GetDependencies() const;
_NODISCARD std::vector<scr_string_t> GetUsedScriptStrings() const;
};

View File

@ -0,0 +1,46 @@
#include "Game/IW3/AssetLoaders/AssetLoaderStringTable.h"
#include "Game/IW3/GameIW3.h"
#include "Mock/MockAssetLoadingManager.h"
#include "Mock/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <string>
using namespace IW3;
using namespace std::literals;
namespace
{
TEST_CASE("AssetLoaderStringTable(IW3): Can parse string table", "[iw3][stringtable][assetloader]")
{
MockSearchPath searchPath;
searchPath.AddFileData("mp/cooltable.csv",
"test,data,lol\n"
"lorem,ipsum");
Zone zone("MockZone", 0, &g_GameIW3);
MockAssetLoadingManager assetLoadingManager(&zone, &searchPath);
AssetLoaderStringTable assetLoader;
MemoryManager memory;
assetLoader.LoadFromRaw("mp/cooltable.csv", &searchPath, &memory, &assetLoadingManager, &zone);
auto* assetInfo = reinterpret_cast<XAssetInfo<StringTable>*>(assetLoadingManager.MockGetAddedAsset("mp/cooltable.csv"));
REQUIRE(assetInfo != nullptr);
const auto* stringTable = assetInfo->Asset();
REQUIRE(stringTable->name == "mp/cooltable.csv"s);
REQUIRE(stringTable->columnCount == 3);
REQUIRE(stringTable->rowCount == 2);
REQUIRE(stringTable->values[0] == "test"s);
REQUIRE(stringTable->values[1] == "data"s);
REQUIRE(stringTable->values[2] == "lol"s);
REQUIRE(stringTable->values[3] == "lorem"s);
REQUIRE(stringTable->values[4] == "ipsum"s);
REQUIRE(stringTable->values[5] == ""s);
}
} // namespace

View File

@ -0,0 +1,53 @@
#include "Game/IW4/AssetLoaders/AssetLoaderStringTable.h"
#include "Game/IW4/CommonIW4.h"
#include "Game/IW4/GameIW4.h"
#include "Mock/MockAssetLoadingManager.h"
#include "Mock/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <string>
using namespace IW4;
using namespace std::literals;
namespace
{
TEST_CASE("AssetLoaderStringTable(IW4): Can parse string table", "[iw4][stringtable][assetloader]")
{
MockSearchPath searchPath;
searchPath.AddFileData("mp/cooltable.csv",
"test,data,lol\n"
"lorem,ipsum");
Zone zone("MockZone", 0, &g_GameIW4);
MockAssetLoadingManager assetLoadingManager(&zone, &searchPath);
AssetLoaderStringTable assetLoader;
MemoryManager memory;
assetLoader.LoadFromRaw("mp/cooltable.csv", &searchPath, &memory, &assetLoadingManager, &zone);
auto* assetInfo = reinterpret_cast<XAssetInfo<StringTable>*>(assetLoadingManager.MockGetAddedAsset("mp/cooltable.csv"));
REQUIRE(assetInfo != nullptr);
const auto* stringTable = assetInfo->Asset();
REQUIRE(stringTable->name == "mp/cooltable.csv"s);
REQUIRE(stringTable->columnCount == 3);
REQUIRE(stringTable->rowCount == 2);
CHECK(stringTable->values[0].string == "test"s);
CHECK(stringTable->values[0].hash == 0x364492);
CHECK(stringTable->values[1].string == "data"s);
CHECK(stringTable->values[1].hash == 0x2eefaa);
CHECK(stringTable->values[2].string == "lol"s);
CHECK(stringTable->values[2].hash == 0x1a349);
CHECK(stringTable->values[3].string == "lorem"s);
CHECK(stringTable->values[3].hash == 0x6261837);
CHECK(stringTable->values[4].string == "ipsum"s);
CHECK(stringTable->values[4].hash == 0x5fc4bc4);
CHECK(stringTable->values[5].string == ""s);
CHECK(stringTable->values[5].hash == 0x0);
}
} // namespace

View File

@ -0,0 +1,52 @@
#include "Game/IW5/AssetLoaders/AssetLoaderStringTable.h"
#include "Game/IW5/GameIW5.h"
#include "Mock/MockAssetLoadingManager.h"
#include "Mock/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <string>
using namespace IW5;
using namespace std::literals;
namespace
{
TEST_CASE("AssetLoaderStringTable(IW5): Can parse string table", "[iw5][stringtable][assetloader]")
{
MockSearchPath searchPath;
searchPath.AddFileData("mp/cooltable.csv",
"test,data,lol\n"
"lorem,ipsum");
Zone zone("MockZone", 0, &g_GameIW5);
MockAssetLoadingManager assetLoadingManager(&zone, &searchPath);
AssetLoaderStringTable assetLoader;
MemoryManager memory;
assetLoader.LoadFromRaw("mp/cooltable.csv", &searchPath, &memory, &assetLoadingManager, &zone);
auto* assetInfo = reinterpret_cast<XAssetInfo<StringTable>*>(assetLoadingManager.MockGetAddedAsset("mp/cooltable.csv"));
REQUIRE(assetInfo != nullptr);
const auto* stringTable = assetInfo->Asset();
REQUIRE(stringTable->name == "mp/cooltable.csv"s);
REQUIRE(stringTable->columnCount == 3);
REQUIRE(stringTable->rowCount == 2);
CHECK(stringTable->values[0].string == "test"s);
CHECK(stringTable->values[0].hash == 0x364492);
CHECK(stringTable->values[1].string == "data"s);
CHECK(stringTable->values[1].hash == 0x2eefaa);
CHECK(stringTable->values[2].string == "lol"s);
CHECK(stringTable->values[2].hash == 0x1a349);
CHECK(stringTable->values[3].string == "lorem"s);
CHECK(stringTable->values[3].hash == 0x6261837);
CHECK(stringTable->values[4].string == "ipsum"s);
CHECK(stringTable->values[4].hash == 0x5fc4bc4);
CHECK(stringTable->values[5].string == ""s);
CHECK(stringTable->values[5].hash == 0x0);
}
} // namespace

View File

@ -0,0 +1,59 @@
#include "Game/T5/AssetLoaders/AssetLoaderStringTable.h"
#include "Game/T5/GameT5.h"
#include "Mock/MockAssetLoadingManager.h"
#include "Mock/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <string>
using namespace T5;
using namespace std::literals;
namespace
{
TEST_CASE("AssetLoaderStringTable(T5): Can parse string table", "[t5][stringtable][assetloader]")
{
MockSearchPath searchPath;
searchPath.AddFileData("mp/cooltable.csv",
"test,data,lol\n"
"lorem,ipsum");
Zone zone("MockZone", 0, &g_GameT5);
MockAssetLoadingManager assetLoadingManager(&zone, &searchPath);
AssetLoaderStringTable assetLoader;
MemoryManager memory;
assetLoader.LoadFromRaw("mp/cooltable.csv", &searchPath, &memory, &assetLoadingManager, &zone);
auto* assetInfo = reinterpret_cast<XAssetInfo<StringTable>*>(assetLoadingManager.MockGetAddedAsset("mp/cooltable.csv"));
REQUIRE(assetInfo != nullptr);
const auto* stringTable = assetInfo->Asset();
REQUIRE(stringTable->name == "mp/cooltable.csv"s);
REQUIRE(stringTable->columnCount == 3);
REQUIRE(stringTable->rowCount == 2);
CHECK(stringTable->values[0].string == "test"s);
CHECK(stringTable->values[0].hash == 0x7c9e6865);
CHECK(stringTable->values[1].string == "data"s);
CHECK(stringTable->values[1].hash == 0x7c95915f);
CHECK(stringTable->values[2].string == "lol"s);
CHECK(stringTable->values[2].hash == 0xb888d0c);
CHECK(stringTable->values[3].string == "lorem"s);
CHECK(stringTable->values[3].hash == 0xfe02704);
CHECK(stringTable->values[4].string == "ipsum"s);
CHECK(stringTable->values[4].hash == 0xfaa7033);
CHECK(stringTable->values[5].string == ""s);
CHECK(stringTable->values[5].hash == 0x1505);
REQUIRE(stringTable->cellIndex != nullptr);
CHECK(stringTable->cellIndex[0] == 2);
CHECK(stringTable->cellIndex[1] == 4);
CHECK(stringTable->cellIndex[2] == 3);
CHECK(stringTable->cellIndex[3] == 1);
CHECK(stringTable->cellIndex[4] == 0);
}
} // namespace

View File

@ -0,0 +1,59 @@
#include "Game/T6/AssetLoaders/AssetLoaderStringTable.h"
#include "Game/T6/GameT6.h"
#include "Mock/MockAssetLoadingManager.h"
#include "Mock/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <string>
using namespace T6;
using namespace std::literals;
namespace
{
TEST_CASE("AssetLoaderStringTable(T6): Can parse string table", "[t6][stringtable][assetloader]")
{
MockSearchPath searchPath;
searchPath.AddFileData("mp/cooltable.csv",
"test,data,lol\n"
"lorem,ipsum");
Zone zone("MockZone", 0, &g_GameT6);
MockAssetLoadingManager assetLoadingManager(&zone, &searchPath);
AssetLoaderStringTable assetLoader;
MemoryManager memory;
assetLoader.LoadFromRaw("mp/cooltable.csv", &searchPath, &memory, &assetLoadingManager, &zone);
auto* assetInfo = reinterpret_cast<XAssetInfo<StringTable>*>(assetLoadingManager.MockGetAddedAsset("mp/cooltable.csv"));
REQUIRE(assetInfo != nullptr);
const auto* stringTable = assetInfo->Asset();
REQUIRE(stringTable->name == "mp/cooltable.csv"s);
REQUIRE(stringTable->columnCount == 3);
REQUIRE(stringTable->rowCount == 2);
CHECK(stringTable->values[0].string == "test"s);
CHECK(stringTable->values[0].hash == 0x7c9e6865);
CHECK(stringTable->values[1].string == "data"s);
CHECK(stringTable->values[1].hash == 0x7c95915f);
CHECK(stringTable->values[2].string == "lol"s);
CHECK(stringTable->values[2].hash == 0xb888d0c);
CHECK(stringTable->values[3].string == "lorem"s);
CHECK(stringTable->values[3].hash == 0xfe02704);
CHECK(stringTable->values[4].string == "ipsum"s);
CHECK(stringTable->values[4].hash == 0xfaa7033);
CHECK(stringTable->values[5].string == ""s);
CHECK(stringTable->values[5].hash == 0x1505);
REQUIRE(stringTable->cellIndex != nullptr);
CHECK(stringTable->cellIndex[0] == 2);
CHECK(stringTable->cellIndex[1] == 4);
CHECK(stringTable->cellIndex[2] == 3);
CHECK(stringTable->cellIndex[3] == 1);
CHECK(stringTable->cellIndex[4] == 0);
}
} // namespace

2
thirdparty/catch2 vendored

@ -1 +1 @@
Subproject commit 863c662c0eff026300f4d729a7054e90d6d12cdd
Subproject commit 79205da6a67f5ad3d7874cf1c6423283dfeab199

2
thirdparty/json vendored

@ -1 +1 @@
Subproject commit a259ecc51e1951e12f757ce17db958e9881e9c6c
Subproject commit 7efe875495a3ed7d805ddbb01af0c7725f50c88b

2
thirdparty/zlib vendored

@ -1 +1 @@
Subproject commit 643e17b7498d12ab8d15565662880579692f769d
Subproject commit 7af6320ad78b390de42f414fabdc64dc6d67a5ea

36
tools/scripts/version.lua Normal file
View File

@ -0,0 +1,36 @@
local BuildSubFolderFolder = "premake"
local HeaderFileName = "GitVersion.h"
function GetGitVersion()
result, errorCode = os.outputof("git describe --tags")
if errorCode == 0 then
return result
end
return "Unknown"
end
function GetVersionHeaderFolder()
return path.join(BuildFolder(), BuildSubFolderFolder)
end
function WriteVersionHeader()
local folder = GetVersionHeaderFolder()
local file = path.join(folder, HeaderFileName)
local content = string.format([[
#pragma once
#define GIT_VERSION "%s"
]], GetGitVersion())
if os.isdir(folder) ~= True then
os.mkdir(folder)
end
local ok, err = os.writefile_ifnotequal(content, file)
if ok == -1 then
error("Could not create version file: " .. err)
end
end