Merge pull request #569 from diamante0018/zonebuilder-moment
[ZoneBuilder]: Add .str parsing
This commit is contained in:
commit
45bd4e027c
@ -52,4 +52,33 @@ namespace Assets
|
||||
|
||||
buffer->popBlock();
|
||||
}
|
||||
|
||||
void ILocalizeEntry::ParseLocalizedStringsFile(Components::ZoneBuilder::Zone* builder, const std::string& name, const std::string& filename)
|
||||
{
|
||||
std::vector<Game::LocalizeEntry*> assets;
|
||||
const auto _0 = gsl::finally([]
|
||||
{
|
||||
Components::Localization::ParseOutput(nullptr);
|
||||
Components::Localization::PrefixOverride = {};
|
||||
});
|
||||
|
||||
Components::Localization::PrefixOverride = Utils::String::ToUpper(name) + "_";
|
||||
Components::Localization::ParseOutput([&assets](Game::LocalizeEntry* asset)
|
||||
{
|
||||
assets.push_back(asset);
|
||||
});
|
||||
|
||||
const auto* psLoadedFile = Game::SE_Load(filename.data(), false);
|
||||
if (psLoadedFile)
|
||||
{
|
||||
Game::Com_PrintError(Game::CON_CHANNEL_SYSTEM, "^1Localization ERROR: %s\n", psLoadedFile);
|
||||
return;
|
||||
}
|
||||
|
||||
auto type = Game::DB_GetXAssetNameType("localize");
|
||||
for (const auto& entry : assets)
|
||||
{
|
||||
builder->addRawAsset(type, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,11 @@ namespace Assets
|
||||
class ILocalizeEntry : public Components::AssetHandler::IAsset
|
||||
{
|
||||
public:
|
||||
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY; };
|
||||
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY; }
|
||||
|
||||
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
|
||||
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||
|
||||
static void ParseLocalizedStringsFile(Components::ZoneBuilder::Zone* builder, const std::string& name, const std::string& filename);
|
||||
};
|
||||
}
|
||||
|
@ -6,23 +6,36 @@ namespace Components
|
||||
Dvar::Var Localization::UseLocalization;
|
||||
std::unordered_map<std::string, Game::LocalizeEntry*> Localization::LocalizeMap;
|
||||
|
||||
void Localization::Set(const std::string& key, const std::string& value)
|
||||
std::optional<std::string> Localization::PrefixOverride;
|
||||
std::function<void(Game::LocalizeEntry*)> Localization::ParseCallback = nullptr;
|
||||
|
||||
void Localization::Set(const std::string& psLocalReference, const std::string& psNewString)
|
||||
{
|
||||
std::lock_guard _(Localization::LocalizeMutex);
|
||||
std::lock_guard _(LocalizeMutex);
|
||||
Utils::Memory::Allocator* allocator = Utils::Memory::GetAllocator();
|
||||
|
||||
if (Localization::LocalizeMap.contains(key))
|
||||
auto key = psLocalReference;
|
||||
if (PrefixOverride.has_value())
|
||||
{
|
||||
Game::LocalizeEntry* entry = Localization::LocalizeMap[key];
|
||||
key.insert(0, PrefixOverride.value());
|
||||
}
|
||||
|
||||
char* newStaticValue = allocator->duplicateString(value);
|
||||
if (LocalizeMap.contains(key))
|
||||
{
|
||||
auto* entry = LocalizeMap[key];
|
||||
|
||||
const auto* newStaticValue = allocator->duplicateString(psNewString);
|
||||
if (!newStaticValue) return;
|
||||
|
||||
if (entry->value) allocator->free(entry->value);
|
||||
entry->value = newStaticValue;
|
||||
|
||||
SaveParseOutput(entry);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Game::LocalizeEntry* entry = allocator->allocate<Game::LocalizeEntry>();
|
||||
auto* entry = allocator->allocate<Game::LocalizeEntry>();
|
||||
if (!entry) return;
|
||||
|
||||
entry->name = allocator->duplicateString(key);
|
||||
@ -32,7 +45,7 @@ namespace Components
|
||||
return;
|
||||
}
|
||||
|
||||
entry->value = allocator->duplicateString(value);
|
||||
entry->value = allocator->duplicateString(psNewString);
|
||||
if (!entry->value)
|
||||
{
|
||||
allocator->free(entry->name);
|
||||
@ -40,21 +53,23 @@ namespace Components
|
||||
return;
|
||||
}
|
||||
|
||||
Localization::LocalizeMap[key] = entry;
|
||||
SaveParseOutput(entry);
|
||||
|
||||
LocalizeMap[key] = entry;
|
||||
}
|
||||
|
||||
const char* Localization::Get(const char* key)
|
||||
{
|
||||
if (!Localization::UseLocalization.get<bool>()) return key;
|
||||
if (!UseLocalization.get<bool>()) return key;
|
||||
|
||||
Game::LocalizeEntry* entry = nullptr;
|
||||
|
||||
{
|
||||
std::lock_guard _(Localization::LocalizeMutex);
|
||||
std::lock_guard _(LocalizeMutex);
|
||||
|
||||
if (Localization::LocalizeMap.contains(key))
|
||||
if (LocalizeMap.contains(key))
|
||||
{
|
||||
entry = Localization::LocalizeMap[key];
|
||||
entry = LocalizeMap[key];
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,9 +86,22 @@ namespace Components
|
||||
return key;
|
||||
}
|
||||
|
||||
void __stdcall Localization::SetStringStub(const char* key, const char* value, bool /*isEnglish*/)
|
||||
void __stdcall Localization::SetStringStub(const char* psLocalReference, const char* psNewString, [[maybe_unused]] int bSentenceIsEnglish)
|
||||
{
|
||||
Localization::Set(key, value);
|
||||
Set(psLocalReference, psNewString);
|
||||
}
|
||||
|
||||
void Localization::ParseOutput(const std::function<void(Game::LocalizeEntry*)>& callback)
|
||||
{
|
||||
ParseCallback = callback;
|
||||
}
|
||||
|
||||
void Localization::SaveParseOutput(Game::LocalizeEntry* asset)
|
||||
{
|
||||
if (ParseCallback)
|
||||
{
|
||||
ParseCallback(asset);
|
||||
}
|
||||
}
|
||||
|
||||
void Localization::SetCredits()
|
||||
@ -161,7 +189,7 @@ namespace Components
|
||||
// I have no idea why, but the last 2 lines are invisible!
|
||||
credits.append("-\n-");
|
||||
|
||||
Localization::Set("IW4X_CREDITS", credits);
|
||||
Set("IW4X_CREDITS", credits);
|
||||
}
|
||||
|
||||
const char* Localization::SEH_LocalizeTextMessageStub(const char* pszInputBuffer, const char* pszMessageType, Game::msgLocErrType_t errType)
|
||||
@ -304,31 +332,31 @@ namespace Components
|
||||
|
||||
Localization::Localization()
|
||||
{
|
||||
Localization::SetCredits();
|
||||
SetCredits();
|
||||
|
||||
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, [](Game::XAssetType, const std::string& filename)
|
||||
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, [](Game::XAssetType, const std::string& name)
|
||||
{
|
||||
Game::XAssetHeader header = { nullptr };
|
||||
std::lock_guard _(Localization::LocalizeMutex);
|
||||
std::lock_guard _(LocalizeMutex);
|
||||
|
||||
if (Localization::LocalizeMap.contains(filename))
|
||||
if (const auto itr = LocalizeMap.find(name); itr != LocalizeMap.end())
|
||||
{
|
||||
header.localize = Localization::LocalizeMap[filename];
|
||||
header.localize = itr->second;
|
||||
}
|
||||
|
||||
return header;
|
||||
});
|
||||
|
||||
// Resolving hook
|
||||
Utils::Hook(0x629B90, Localization::Get, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x629B90, Get, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Overwrite SetString
|
||||
Utils::Hook(0x4CE5EE, Localization::SetStringStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4CE5EE, SetStringStub, HOOK_CALL).install()->quick();
|
||||
|
||||
Utils::Hook(0x49D4A0, Localization::SEH_LocalizeTextMessageStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x49D4A0, SEH_LocalizeTextMessageStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook::Nop(0x49D4A5, 1);
|
||||
|
||||
Localization::UseLocalization = Dvar::Register<bool>("ui_localize", true, Game::DVAR_NONE, "Use localization strings");
|
||||
UseLocalization = Dvar::Register<bool>("ui_localize", true, Game::DVAR_NONE, "Use localization strings");
|
||||
|
||||
// Generate localized entries for custom classes above 10
|
||||
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* /*restrict*/)
|
||||
@ -344,7 +372,7 @@ namespace Components
|
||||
std::string value = asset.localize->value;
|
||||
Utils::String::Replace(value, "1", std::to_string(i)); // Pretty ugly, but it should work
|
||||
|
||||
Localization::Set(key, value);
|
||||
Set(key, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -352,6 +380,6 @@ namespace Components
|
||||
|
||||
Localization::~Localization()
|
||||
{
|
||||
Localization::LocalizeMap.clear();
|
||||
LocalizeMap.clear();
|
||||
}
|
||||
}
|
||||
|
@ -8,15 +8,23 @@ namespace Components
|
||||
Localization();
|
||||
~Localization();
|
||||
|
||||
static void Set(const std::string& key, const std::string& value);
|
||||
static void Set(const std::string& psLocalReference, const std::string& psNewString);
|
||||
static const char* Get(const char* key);
|
||||
|
||||
static std::optional<std::string> PrefixOverride;
|
||||
static void ParseOutput(const std::function<void(Game::LocalizeEntry*)>& callback);
|
||||
|
||||
private:
|
||||
static std::recursive_mutex LocalizeMutex;
|
||||
static std::unordered_map<std::string, Game::LocalizeEntry*> LocalizeMap;
|
||||
static Dvar::Var UseLocalization;
|
||||
|
||||
static void __stdcall SetStringStub(const char* key, const char* value, bool isEnglish);
|
||||
static std::function<void(Game::LocalizeEntry*)> ParseCallback;
|
||||
|
||||
static void __stdcall SetStringStub(const char* psLocalReference, const char* psNewString, int bSentenceIsEnglish);
|
||||
|
||||
static void SaveParseOutput(Game::LocalizeEntry* asset);
|
||||
|
||||
static void SetCredits();
|
||||
|
||||
static const char* SEH_LocalizeTextMessageStub(const char* pszInputBuffer, const char* pszMessageType, Game::msgLocErrType_t errType);
|
||||
|
@ -16,7 +16,7 @@ namespace Components
|
||||
Game::SockadrToNetadr(addr, &this->address);
|
||||
}
|
||||
|
||||
bool Network::Address::operator==(const Network::Address& obj) const
|
||||
bool Network::Address::operator==(const Address& obj) const
|
||||
{
|
||||
return Game::NET_CompareAdr(this->address, obj.address);
|
||||
}
|
||||
@ -150,13 +150,11 @@ namespace Components
|
||||
|
||||
void Network::Send(Game::netsrc_t type, Address target, const std::string& data)
|
||||
{
|
||||
// NET_OutOfBandPrint only supports non-binary data!
|
||||
//Game::NET_OutOfBandPrint(type, *target.Get(), data.data());
|
||||
// Do not use NET_OutOfBandPrint. It only supports non-binary data!
|
||||
|
||||
std::string rawData;
|
||||
rawData.append("\xFF\xFF\xFF\xFF", 4);
|
||||
rawData.append(data);
|
||||
//rawData.append("\0", 1);
|
||||
|
||||
SendRaw(type, target, rawData);
|
||||
}
|
||||
@ -170,8 +168,7 @@ namespace Components
|
||||
{
|
||||
if (!target.isValid()) return;
|
||||
|
||||
// NET_OutOfBandData doesn't seem to work properly
|
||||
//Game::NET_OutOfBandData(type, *target.Get(), data.data(), data.size());
|
||||
// NET_OutOfBandData doesn't seem to work properly. Do not use it
|
||||
Game::Sys_SendPacket(type, data.size(), data.data(), *target.get());
|
||||
}
|
||||
|
||||
@ -294,7 +291,7 @@ namespace Components
|
||||
|
||||
const std::string data(reinterpret_cast<char*>(message->data) + offset, message->cursize - offset);
|
||||
|
||||
Address address_ = address;
|
||||
auto address_ = Address(address);
|
||||
handler->second(address_, data);
|
||||
return true;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ namespace Components
|
||||
class Address
|
||||
{
|
||||
public:
|
||||
Address() { setType(Game::netadrtype_t::NA_BAD); }
|
||||
Address() { setType(Game::NA_BAD); }
|
||||
Address(const std::string& addrString);
|
||||
Address(sockaddr* addr);
|
||||
Address(sockaddr addr) : Address(&addr) {}
|
||||
|
@ -30,7 +30,7 @@ namespace Components
|
||||
return;
|
||||
}
|
||||
|
||||
const auto addr = reinterpret_cast<Game::netadr_t*>(0xA5EA44);
|
||||
auto* addr = reinterpret_cast<Game::netadr_t*>(0xA5EA44);
|
||||
if (Password.empty())
|
||||
{
|
||||
Logger::Print("You need to be logged in and connected to a server!\n");
|
||||
@ -57,7 +57,7 @@ namespace Components
|
||||
|
||||
RconContainer.command = params->get(1);
|
||||
|
||||
const auto addr = reinterpret_cast<Game::netadr_t*>(0xA5EA44);
|
||||
auto* addr = reinterpret_cast<Game::netadr_t*>(0xA5EA44);
|
||||
Network::Address target(addr);
|
||||
if (!target.isValid() || target.getIP().full == 0)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "AssetInterfaces/ILocalizeEntry.hpp"
|
||||
|
||||
namespace Components
|
||||
{
|
||||
@ -146,30 +147,44 @@ namespace Components
|
||||
{
|
||||
for (std::size_t i = 0; i < this->dataMap.getRows(); ++i)
|
||||
{
|
||||
if (this->dataMap.getElementAt(i, 0) != "require")
|
||||
if (this->dataMap.getElementAt(i, 0) == "require"s)
|
||||
{
|
||||
if (this->dataMap.getColumns(i) > 2)
|
||||
{
|
||||
std::string oldName = this->dataMap.getElementAt(i, 1);
|
||||
std::string newName = this->dataMap.getElementAt(i, 2);
|
||||
std::string typeName = this->dataMap.getElementAt(i, 0);
|
||||
Game::XAssetType type = Game::DB_GetXAssetNameType(typeName.data());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type < Game::XAssetType::ASSET_TYPE_COUNT && type >= 0)
|
||||
{
|
||||
this->renameAsset(type, oldName, newName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::Error(Game::ERR_FATAL, "Unable to rename '{}' to '{}' as the asset type '{}' is invalid!", oldName, newName, typeName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->loadAssetByName(this->dataMap.getElementAt(i, 0), this->dataMap.getElementAt(i, 1), false))
|
||||
if (this->dataMap.getElementAt(i, 0) == "localize"s)
|
||||
{
|
||||
const auto filename = this->dataMap.getElementAt(i, 1);
|
||||
FileSystem::File file(std::format("localizedstrings/{}.str", filename));
|
||||
if (file.exists())
|
||||
{
|
||||
return false;
|
||||
Assets::ILocalizeEntry::ParseLocalizedStringsFile(this, filename, file.getName());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->dataMap.getColumns(i) > 2)
|
||||
{
|
||||
auto oldName = this->dataMap.getElementAt(i, 1);
|
||||
auto newName = this->dataMap.getElementAt(i, 2);
|
||||
auto typeName = this->dataMap.getElementAt(i, 0);
|
||||
auto type = Game::DB_GetXAssetNameType(typeName.data());
|
||||
|
||||
if (type < Game::XAssetType::ASSET_TYPE_COUNT && type >= 0)
|
||||
{
|
||||
this->renameAsset(type, oldName, newName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::Error(Game::ERR_FATAL, "Unable to rename '{}' to '{}' as the asset type '{}' is invalid!", oldName, newName, typeName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->loadAssetByName(this->dataMap.getElementAt(i, 0), this->dataMap.getElementAt(i, 1), false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -194,10 +209,9 @@ namespace Components
|
||||
{
|
||||
Game::XAssetType type = Game::DB_GetXAssetNameType(typeName.data());
|
||||
|
||||
if (name.find(" ", 0) != std::string::npos)
|
||||
if (name.find(' ', 0) != std::string::npos)
|
||||
{
|
||||
Logger::Warning(Game::CON_CHANNEL_DONT_FILTER,
|
||||
"Asset with name '{}' contains spaces. Check your zone source file to ensure this is correct!\n", name);
|
||||
Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Asset with name '{}' contains spaces. Check your zone source file to ensure this is correct!\n", name);
|
||||
}
|
||||
|
||||
// Sanitize name for empty assets
|
||||
@ -408,8 +422,7 @@ namespace Components
|
||||
Utils::IO::WriteFile(outFile, outBuffer);
|
||||
|
||||
Logger::Print("done.\n");
|
||||
Logger::Print("Zone '{}' written with {} assets and {} script strings\n",
|
||||
outFile, (this->aliasList.size() + this->loadedAssets.size()), this->scriptStrings.size());
|
||||
Logger::Print("Zone '{}' written with {} assets and {} script strings\n", outFile, (this->aliasList.size() + this->loadedAssets.size()), this->scriptStrings.size());
|
||||
}
|
||||
|
||||
void ZoneBuilder::Zone::saveData()
|
||||
@ -440,7 +453,7 @@ namespace Components
|
||||
// That's the reason why the count is incremented by 1, if scriptStrings are available.
|
||||
|
||||
// Write ScriptString pointer table
|
||||
for (size_t i = 0; i < this->scriptStrings.size(); ++i)
|
||||
for (std::size_t i = 0; i < this->scriptStrings.size(); ++i)
|
||||
{
|
||||
this->buffer.saveMax(4);
|
||||
}
|
||||
@ -606,6 +619,11 @@ namespace Components
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ZoneBuilder::Zone::addRawAsset(Game::XAssetType type, void* ptr)
|
||||
{
|
||||
this->loadedAssets.push_back({type, {ptr}});
|
||||
}
|
||||
|
||||
// Remap a scriptString to it's corresponding value in the local scriptString table.
|
||||
void ZoneBuilder::Zone::mapScriptString(unsigned short* gameIndex)
|
||||
{
|
||||
@ -907,11 +925,12 @@ namespace Components
|
||||
|
||||
void ZoneBuilder::HandleError(Game::errorParm_t code, const char* fmt, ...)
|
||||
{
|
||||
char buffer[4096] = {0};
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf_s(buffer, _TRUNCATE, fmt, args);
|
||||
va_end(args);
|
||||
char buffer[0x1000]{};
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (!Flags::HasFlag("stdout"))
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ namespace Components
|
||||
void storePointer(const void* pointer);
|
||||
|
||||
template<typename T>
|
||||
inline T* getPointer(const T* pointer) { return reinterpret_cast<T*>(this->safeGetPointer(pointer)); }
|
||||
T* getPointer(const T* pointer) { return reinterpret_cast<T*>(this->safeGetPointer(pointer)); }
|
||||
|
||||
int findAsset(Game::XAssetType type, std::string name);
|
||||
Game::XAssetHeader findSubAsset(Game::XAssetType type, std::string name);
|
||||
@ -58,6 +58,7 @@ namespace Components
|
||||
int addScriptString(unsigned short gameIndex);
|
||||
int addScriptString(const std::string& str);
|
||||
int findScriptString(const std::string& str);
|
||||
void addRawAsset(Game::XAssetType type, void* ptr);
|
||||
|
||||
void mapScriptString(unsigned short* gameIndex);
|
||||
|
||||
@ -101,6 +102,7 @@ namespace Components
|
||||
std::vector<Game::XAsset> markedAssets;
|
||||
std::vector<Game::XAsset> loadedSubAssets;
|
||||
std::vector<std::string> scriptStrings;
|
||||
|
||||
std::map<unsigned short, unsigned int> scriptStringMap;
|
||||
|
||||
std::map<std::string, std::string> renameMap[Game::XAssetType::ASSET_TYPE_COUNT];
|
||||
|
@ -377,7 +377,7 @@ namespace Game
|
||||
typedef int(*Script_CleanString_t)(char* buffer);
|
||||
extern Script_CleanString_t Script_CleanString;
|
||||
|
||||
typedef char*(*SE_Load_t)(const char* file, int Unk);
|
||||
typedef char*(*SE_Load_t)(const char* psFileName, bool forceEnglish);
|
||||
extern SE_Load_t SE_Load;
|
||||
|
||||
typedef char*(*SEH_StringEd_GetString_t)(const char* string);
|
||||
|
Loading…
Reference in New Issue
Block a user