Skip to content

Commit

Permalink
Merge pull request Laupetin#91 from Laupetin/iw3-stringtable
Browse files Browse the repository at this point in the history
feat: add StringTable loading for IW3
  • Loading branch information
Laupetin authored Jan 20, 2024
2 parents 5b08751 + c8d2505 commit 6083a91
Show file tree
Hide file tree
Showing 14 changed files with 522 additions and 213 deletions.
25 changes: 23 additions & 2 deletions src/ObjCommon/Csv/CsvStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,35 @@ 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;
while (c != EOF)
{
if (c == CSV_SEPARATOR)
{
out.emplace_back(col.str());
cb(col.str());
col.clear();
col.str(std::string());
}
Expand All @@ -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;
Expand Down
22 changes: 15 additions & 7 deletions src/ObjCommon/Csv/CsvStream.h
Original file line number Diff line number Diff line change
@@ -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;
};
39 changes: 39 additions & 0 deletions src/ObjLoading/Game/IW3/AssetLoaders/AssetLoaderStringTable.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
17 changes: 17 additions & 0 deletions src/ObjLoading/Game/IW3/AssetLoaders/AssetLoaderStringTable.h
Original file line number Diff line number Diff line change
@@ -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
46 changes: 3 additions & 43 deletions src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderStringTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Game/IW4/IW4.h"
#include "ObjLoading.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"

#include <cstring>

Expand All @@ -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);

Expand Down
46 changes: 3 additions & 43 deletions src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Game/IW5/IW5.h"
#include "ObjLoading.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"

#include <cstring>

Expand All @@ -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);

Expand Down
62 changes: 3 additions & 59 deletions src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Game/T5/CommonT5.h"
#include "Game/T5/T5.h"
#include "Pool/GlobalAssetPool.h"
#include "StringTable/StringTableLoader.h"

#include <cstring>

Expand All @@ -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);

Expand Down
Loading

0 comments on commit 6083a91

Please sign in to comment.