Merge pull request #324 from XLabsProject/develop

Release v0.7.3
This commit is contained in:
Edo 2022-06-23 22:06:03 +02:00 committed by GitHub
commit 7473844a4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
195 changed files with 4990 additions and 3233 deletions

3
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-3.0
* @XLabsProject/Developers

5
.gitmodules vendored
View File

@ -25,10 +25,13 @@
[submodule "deps/protobuf"] [submodule "deps/protobuf"]
path = deps/protobuf path = deps/protobuf
url = https://github.com/google/protobuf.git url = https://github.com/google/protobuf.git
branch = 3.17.x branch = 3.20.x
[submodule "deps/udis86"] [submodule "deps/udis86"]
path = deps/udis86 path = deps/udis86
url = https://github.com/vmt/udis86.git url = https://github.com/vmt/udis86.git
[submodule "deps/dxsdk"] [submodule "deps/dxsdk"]
path = deps/dxsdk path = deps/dxsdk
url = https://github.com/devKlausS/dxsdk.git url = https://github.com/devKlausS/dxsdk.git
[submodule "deps/GSL"]
path = deps/GSL
url = https://github.com/microsoft/GSL.git

View File

@ -4,6 +4,35 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/). The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.7.3] - 2022-06-23
### Added
- Add SetName GSC method (#288)
- Add ResetName GSC method (#288)
- Add OnPlayerSay GSC function (#265)
- Add Give client command (works with weapons only) (#292)
- Add `sv_disableChat` Dvar (#290)
- Add `addMap` command (#302)
- Add `addGametype` command (#302)
### Changed
- `openLink` command was removed for security reasons (#286)
### Fixed
- Fix font generation (#277)
- Fix crash on clearing key binds (#278)
- Fix maps dropping out of the map rotation when using `sv_randomMapRotation` (#283)
### Known issue
- HTTPS is not supported for fast downloads at the moment.
- Sound issue fix is experimental as the bug is not fully understood.
- `reloadmenus` command does not free resources used by custom menus.
- Toast notifications have been disabled because they cause a crash that needs to be investigated
## [0.7.2] - 2022-05-10 ## [0.7.2] - 2022-05-10
### Added ### Added
@ -19,7 +48,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.
- Knife charge is fixed for controller players (#259) - Knife charge is fixed for controller players (#259)
- Fixed internet, local and favorites filters (#260) - Fixed internet, local and favorites filters (#260)
- `sv_lanOnly` Dvar now prevents the server from sending heatbeats to master if set to true (#246) - `sv_lanOnly` Dvar now prevents the server from sending heartbeats to master if set to true (#246)
### Known issue ### Known issue

View File

@ -21,7 +21,7 @@
| `--copy-pdb` | Copy debug information for binaries as well to the path given via --copy-to. | | `--copy-pdb` | Copy debug information for binaries as well to the path given via --copy-to. |
| `--force-unit-tests` | Always compile unit tests. | | `--force-unit-tests` | Always compile unit tests. |
| `--force-exception-handler` | Install custom unhandled exception handler even for Debug builds. | | `--force-exception-handler` | Install custom unhandled exception handler even for Debug builds. |
| `--force-minidump-upload` | Upload minidumps even for Debug builds. | | `--disable-binary-check` | Do not perform integrity checks on the exe. |
| `--iw4x-zones` | Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches. | | `--iw4x-zones` | Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches. |
## Command line arguments ## Command line arguments

1
deps/GSL vendored Submodule

@ -0,0 +1 @@
Subproject commit d9fc52e20e32fcc804502480a781120b210afd41

19
deps/premake/gsl.lua vendored Normal file
View File

@ -0,0 +1,19 @@
gsl = {
source = path.join(dependencies.basePath, "GSL"),
}
function gsl.import()
gsl.includes()
end
function gsl.includes()
includedirs {
path.join(gsl.source, "include")
}
end
function gsl.project()
end
table.insert(dependencies, gsl)

View File

@ -15,6 +15,7 @@ end
function json11.project() function json11.project()
project "json11" project "json11"
language "C++" language "C++"
cppdialect "C++11"
files files
{ {
@ -29,4 +30,4 @@ function json11.project()
kind "StaticLib" kind "StaticLib"
end end
table.insert(dependencies, json11) table.insert(dependencies, json11)

2
deps/protobuf vendored

@ -1 +1 @@
Subproject commit 5500c72c5b616da9f0125bcfab513987a1226e2b Subproject commit 6e9e60367d8744e86856590d8ea0e793c61deeec

View File

@ -82,8 +82,8 @@ newoption {
} }
newoption { newoption {
trigger = "force-minidump-upload", trigger = "disable-binary-check",
description = "Upload minidumps even for Debug builds." description = "Do not perform integrity checks on the exe."
} }
newoption { newoption {
@ -206,7 +206,7 @@ workspace "iw4x"
configurations {"Debug", "Release"} configurations {"Debug", "Release"}
language "C++" language "C++"
cppdialect "C++17" cppdialect "C++20"
architecture "x86" architecture "x86"
platforms "Win32" platforms "Win32"
@ -262,12 +262,12 @@ workspace "iw4x"
if _OPTIONS["force-unit-tests"] then if _OPTIONS["force-unit-tests"] then
defines {"FORCE_UNIT_TESTS"} defines {"FORCE_UNIT_TESTS"}
end end
if _OPTIONS["force-minidump-upload"] then
defines {"FORCE_MINIDUMP_UPLOAD"}
end
if _OPTIONS["force-exception-handler"] then if _OPTIONS["force-exception-handler"] then
defines {"FORCE_EXCEPTION_HANDLER"} defines {"FORCE_EXCEPTION_HANDLER"}
end end
if _OPTIONS["disable-binary-check"] then
defines {"DISABLE_BINARY_CHECK"}
end
if _OPTIONS["iw4x-zones"] then if _OPTIONS["iw4x-zones"] then
defines {"GENERATE_IW4X_SPECIFIC_ZONES"} defines {"GENERATE_IW4X_SPECIFIC_ZONES"}
end end

View File

@ -106,10 +106,18 @@ namespace Components
Loader::Register(new ClientCommand()); Loader::Register(new ClientCommand());
Loader::Register(new ScriptExtension()); Loader::Register(new ScriptExtension());
Loader::Register(new Branding()); Loader::Register(new Branding());
Loader::Register(new Debug());
Loader::Register(new RawMouse()); Loader::Register(new RawMouse());
Loader::Register(new Bullet()); Loader::Register(new Bullet());
Loader::Register(new MapRotation());
Loader::Register(new Ceg());
Loader::Register(new UserInfo());
Loader::Register(new Events());
Loader::Pregame = false; Loader::Pregame = false;
// Make sure preDestroy is called when the game shuts down
Scheduler::OnGameShutdown(Loader::PreDestroy);
} }
void Loader::Uninitialize() void Loader::Uninitialize()
@ -123,7 +131,7 @@ namespace Components
#ifdef DEBUG #ifdef DEBUG
if (!Loader::IsPerformingUnitTests()) if (!Loader::IsPerformingUnitTests())
{ {
Logger::Print("Unregistering component: %s\n", component->getName().data()); Logger::Print("Unregister component: {}\n", component->getName());
} }
#endif #endif
delete component; delete component;
@ -172,15 +180,15 @@ namespace Components
Logger::Print("Performing unit tests for components:\n"); Logger::Print("Performing unit tests for components:\n");
for (auto component : Loader::Components) for (const auto component : Loader::Components)
{ {
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(FORCE_UNIT_TESTS)
Logger::Print("Testing '%s'...\n", component->getName().data()); Logger::Debug("Testing '{}'...\n", component->getName());
#endif #endif
auto startTime = std::chrono::high_resolution_clock::now(); auto startTime = std::chrono::high_resolution_clock::now();
bool testRes = component->unitTest(); auto testRes = component->unitTest();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count();
Logger::Print("Test done (%llims): %s\n\n", duration, (testRes ? "Success" : "Error")); Logger::Print("Test done ({}ms): {}\n\n", duration, (testRes ? "Success" : "Error"));
result &= testRes; result &= testRes;
} }
@ -203,7 +211,7 @@ namespace Components
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
if (!Loader::IsPerformingUnitTests()) if (!Loader::IsPerformingUnitTests())
{ {
Logger::Print("Component registered: %s\n", component->getName().data()); Logger::Print("Component registered: {}\n", component->getName());
} }
#endif #endif
Loader::Components.push_back(component); Loader::Components.push_back(component);

View File

@ -5,8 +5,8 @@ namespace Components
class Component class Component
{ {
public: public:
Component() {}; Component() = default;
virtual ~Component() {}; virtual ~Component() = default;
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
virtual std::string getName() virtual std::string getName()
@ -20,8 +20,8 @@ namespace Components
// It's illegal to spawn threads in DLLMain, and apparently it causes problems if they are destroyed there as well. // It's illegal to spawn threads in DLLMain, and apparently it causes problems if they are destroyed there as well.
// This method is called before DLLMain (if possible) and should to destroy threads. // This method is called before DLLMain (if possible) and should to destroy threads.
// It's not 100% guaranteed that it's called outside DLLMain, as it depends on the game, but it's 100% guaranteed, that it is called at all. // It's not 100% guaranteed that it's called outside DLLMain, as it depends on the game, but it's 100% guaranteed, that it is called at all.
virtual void preDestroy() {}; virtual void preDestroy() {}
virtual bool unitTest() { return true; }; // Unit testing entry virtual bool unitTest() { return true; } // Unit testing entry
}; };
class Loader class Loader
@ -137,5 +137,10 @@ namespace Components
#include "Modules/Gamepad.hpp" #include "Modules/Gamepad.hpp"
#include "Modules/ScriptExtension.hpp" #include "Modules/ScriptExtension.hpp"
#include "Modules/Branding.hpp" #include "Modules/Branding.hpp"
#include "Modules/Debug.hpp"
#include "Modules/RawMouse.hpp" #include "Modules/RawMouse.hpp"
#include "Modules/Bullet.hpp" #include "Modules/Bullet.hpp"
#include "Modules/MapRotation.hpp"
#include "Modules/Ceg.hpp"
#include "Modules/UserInfo.hpp"
#include "Modules/Events.hpp"

View File

@ -1,5 +1,38 @@
#include <StdInclude.hpp> #include <StdInclude.hpp>
#include "AssetInterfaces/IFont_s.hpp"
#include "AssetInterfaces/IWeapon.hpp"
#include "AssetInterfaces/IXModel.hpp"
#include "AssetInterfaces/IFxWorld.hpp"
#include "AssetInterfaces/IMapEnts.hpp"
#include "AssetInterfaces/IRawFile.hpp"
#include "AssetInterfaces/IComWorld.hpp"
#include "AssetInterfaces/IGfxImage.hpp"
#include "AssetInterfaces/IGfxWorld.hpp"
#include "AssetInterfaces/IMaterial.hpp"
#include "AssetInterfaces/ISndCurve.hpp"
#include "AssetInterfaces/IMenuList.hpp"
#include "AssetInterfaces/IclipMap_t.hpp"
#include "AssetInterfaces/ImenuDef_t.hpp"
#include "AssetInterfaces/ITracerDef.hpp"
#include "AssetInterfaces/IPhysPreset.hpp"
#include "AssetInterfaces/IXAnimParts.hpp"
#include "AssetInterfaces/IFxEffectDef.hpp"
#include "AssetInterfaces/IGameWorldMp.hpp"
#include "AssetInterfaces/IGameWorldSp.hpp"
#include "AssetInterfaces/IGfxLightDef.hpp"
#include "AssetInterfaces/ILoadedSound.hpp"
#include "AssetInterfaces/IPhysCollmap.hpp"
#include "AssetInterfaces/IStringTable.hpp"
#include "AssetInterfaces/IXModelSurfs.hpp"
#include "AssetInterfaces/ILocalizeEntry.hpp"
#include "AssetInterfaces/Isnd_alias_list_t.hpp"
#include "AssetInterfaces/IMaterialPixelShader.hpp"
#include "AssetInterfaces/IMaterialTechniqueSet.hpp"
#include "AssetInterfaces/IMaterialVertexShader.hpp"
#include "AssetInterfaces/IStructuredDataDefSet.hpp"
#include "AssetInterfaces/IMaterialVertexDeclaration.hpp"
namespace Components namespace Components
{ {
thread_local int AssetHandler::BypassState = 0; thread_local int AssetHandler::BypassState = 0;
@ -23,14 +56,14 @@ namespace Components
return; return;
} }
if (AssetHandler::AssetInterfaces.find(iAsset->getType()) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.contains(iAsset->getType()))
{ {
Logger::Print("Duplicate asset interface: %s\n", Game::DB_GetXAssetTypeName(iAsset->getType())); Logger::Print("Duplicate asset interface: {}\n", Game::DB_GetXAssetTypeName(iAsset->getType()));
delete AssetHandler::AssetInterfaces[iAsset->getType()]; delete AssetHandler::AssetInterfaces[iAsset->getType()];
} }
else else
{ {
Logger::Print("Asset interface registered: %s\n", Game::DB_GetXAssetTypeName(iAsset->getType())); Logger::Print("Asset interface registered: {}\n", Game::DB_GetXAssetTypeName(iAsset->getType()));
} }
AssetHandler::AssetInterfaces[iAsset->getType()] = iAsset; AssetHandler::AssetInterfaces[iAsset->getType()] = iAsset;
@ -58,7 +91,7 @@ namespace Components
// Allow call DB_FindXAssetHeader within the hook // Allow call DB_FindXAssetHeader within the hook
AssetHandler::SetBypassState(true); AssetHandler::SetBypassState(true);
if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end()) if (AssetHandler::TypeCallbacks.contains(type))
{ {
header = AssetHandler::TypeCallbacks[type](type, filename); header = AssetHandler::TypeCallbacks[type](type, filename);
} }
@ -96,7 +129,7 @@ namespace Components
if (AssetHandler::BypassState < 0) if (AssetHandler::BypassState < 0)
{ {
AssetHandler::BypassState = 0; AssetHandler::BypassState = 0;
Logger::Error("Bypass state is below 0!"); Logger::Error(Game::ERR_FATAL, "Bypass state is below 0!");
} }
} }
@ -329,35 +362,35 @@ namespace Components
{ {
void* pointer = (*Game::g_streamBlocks)[offset->getUnpackedBlock()].data + offset->getUnpackedOffset(); void* pointer = (*Game::g_streamBlocks)[offset->getUnpackedBlock()].data + offset->getUnpackedOffset();
if (AssetHandler::Relocations.find(pointer) != AssetHandler::Relocations.end()) if (AssetHandler::Relocations.contains(pointer))
{ {
pointer = AssetHandler::Relocations[pointer]; pointer = AssetHandler::Relocations[pointer];
} }
offset->pointer = *reinterpret_cast<void**>(pointer); offset->pointer = *static_cast<void**>(pointer);
} }
void AssetHandler::ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder) void AssetHandler::ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder)
{ {
if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.contains(asset.type))
{ {
AssetHandler::AssetInterfaces[asset.type]->save(asset.header, builder); AssetHandler::AssetInterfaces[asset.type]->save(asset.header, builder);
} }
else else
{ {
Logger::Error("No interface for type '%s'!", Game::DB_GetXAssetTypeName(asset.type)); Logger::Error(Game::ERR_FATAL, "No interface for type '{}'!", Game::DB_GetXAssetTypeName(asset.type));
} }
} }
void AssetHandler::ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder) void AssetHandler::ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder)
{ {
if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.contains(asset.type))
{ {
AssetHandler::AssetInterfaces[asset.type]->mark(asset.header, builder); AssetHandler::AssetInterfaces[asset.type]->mark(asset.header, builder);
} }
else else
{ {
Logger::Error("No interface for type '%s'!", Game::DB_GetXAssetTypeName(asset.type)); Logger::Error(Game::ERR_FATAL, "No interface for type '{}'!", Game::DB_GetXAssetTypeName(asset.type));
} }
} }
@ -375,7 +408,7 @@ namespace Components
return { entry->second }; return { entry->second };
} }
if (AssetHandler::AssetInterfaces.find(type) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.contains(type))
{ {
AssetHandler::AssetInterfaces[type]->load(&header, filename, builder); AssetHandler::AssetInterfaces[type]->load(&header, filename, builder);
@ -514,18 +547,18 @@ namespace Components
if (!ZoneBuilder::IsEnabled()) Utils::Hook(0x5BB3F2, AssetHandler::MissingAssetError, HOOK_CALL).install()->quick(); if (!ZoneBuilder::IsEnabled()) Utils::Hook(0x5BB3F2, AssetHandler::MissingAssetError, HOOK_CALL).install()->quick();
// Log missing empty assets // Log missing empty assets
Scheduler::OnFrame([]() Scheduler::Loop([]
{ {
if (FastFiles::Ready() && !AssetHandler::EmptyAssets.empty()) if (FastFiles::Ready() && !AssetHandler::EmptyAssets.empty())
{ {
for (auto& asset : AssetHandler::EmptyAssets) for (auto& asset : AssetHandler::EmptyAssets)
{ {
Game::Com_PrintWarning(25, reinterpret_cast<const char*>(0x724428), Game::DB_GetXAssetTypeName(asset.first), asset.second.data()); Logger::Warning(Game::CON_CHANNEL_FILES, "Could not load {} \"{}\".\n", Game::DB_GetXAssetTypeName(asset.first), asset.second);
} }
AssetHandler::EmptyAssets.clear(); AssetHandler::EmptyAssets.clear();
} }
}); }, Scheduler::Pipeline::MAIN);
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*) AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*)
{ {

View File

@ -78,37 +78,3 @@ namespace Components
void reallocateEntryPool(); void reallocateEntryPool();
}; };
} }
#include "AssetInterfaces/IFont_s.hpp"
#include "AssetInterfaces/IWeapon.hpp"
#include "AssetInterfaces/IXModel.hpp"
#include "AssetInterfaces/IFxWorld.hpp"
#include "AssetInterfaces/IMapEnts.hpp"
#include "AssetInterfaces/IRawFile.hpp"
#include "AssetInterfaces/IComWorld.hpp"
#include "AssetInterfaces/IGfxImage.hpp"
#include "AssetInterfaces/IGfxWorld.hpp"
#include "AssetInterfaces/IMaterial.hpp"
#include "AssetInterfaces/ISndCurve.hpp"
#include "AssetInterfaces/IMenuList.hpp"
#include "AssetInterfaces/IclipMap_t.hpp"
#include "AssetInterfaces/ImenuDef_t.hpp"
#include "AssetInterfaces/ITracerDef.hpp"
#include "AssetInterfaces/IPhysPreset.hpp"
#include "AssetInterfaces/IXAnimParts.hpp"
#include "AssetInterfaces/IFxEffectDef.hpp"
#include "AssetInterfaces/IGameWorldMp.hpp"
#include "AssetInterfaces/IGameWorldSp.hpp"
#include "AssetInterfaces/IGfxLightDef.hpp"
#include "AssetInterfaces/ILoadedSound.hpp"
#include "AssetInterfaces/IPhysCollmap.hpp"
#include "AssetInterfaces/IStringTable.hpp"
#include "AssetInterfaces/IXModelSurfs.hpp"
#include "AssetInterfaces/ILocalizeEntry.hpp"
#include "AssetInterfaces/Isnd_alias_list_t.hpp"
#include "AssetInterfaces/IMaterialPixelShader.hpp"
#include "AssetInterfaces/IMaterialTechniqueSet.hpp"
#include "AssetInterfaces/IMaterialVertexShader.hpp"
#include "AssetInterfaces/IStructuredDataDefSet.hpp"
#include "AssetInterfaces/IMaterialVertexDeclaration.hpp"

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IComWorld.hpp"
#define IW4X_COMMAP_VERSION 0 #define IW4X_COMMAP_VERSION 0
@ -19,13 +20,13 @@ namespace Assets
__int64 magic = reader.read<__int64>(); __int64 magic = reader.read<__int64>();
if (std::memcmp(&magic, "IW4xComW", 8)) if (std::memcmp(&magic, "IW4xComW", 8))
{ {
Components::Logger::Error("Reading comworld '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading comworld '{}' failed, header is invalid!", name);
} }
int version = reader.read<int>(); int version = reader.read<int>();
if (version != IW4X_COMMAP_VERSION) if (version != IW4X_COMMAP_VERSION)
{ {
Components::Logger::Error("Reading comworld '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_COMMAP_VERSION, version); Components::Logger::Error(Game::ERR_FATAL, "Reading comworld '{}' failed, expected version is {}, but it was {}!", name, IW4X_COMMAP_VERSION, version);
} }
Game::ComWorld* asset = reader.readObject<Game::ComWorld>(); Game::ComWorld* asset = reader.readObject<Game::ComWorld>();

View File

@ -5,10 +5,10 @@ namespace Assets
class IComWorld : public Components::AssetHandler::IAsset class IComWorld : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_COMWORLD; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_COMWORLD; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IFont_s.hpp"
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.h> #include <stb_truetype.h>
@ -104,13 +105,13 @@ namespace Assets
if (!errors.empty()) if (!errors.empty())
{ {
Components::Logger::Error("Font define %s is broken: %s.", name.data(), errors.data()); Components::Logger::Error(Game::ERR_FATAL, "Font define {} is broken: {}", name, errors);
return; return;
} }
if (!fontDef.is_object()) if (!fontDef.is_object())
{ {
Components::Logger::Error("Font define %s is invaild.", name.data(), errors.data()); Components::Logger::Error(Game::ERR_FATAL, "Font define {} is invalid {}", name, errors);
return; return;
} }
@ -135,7 +136,10 @@ namespace Assets
auto* material = builder->getAllocator()->allocate<Game::Material>(); auto* material = builder->getAllocator()->allocate<Game::Material>();
std::memcpy(material, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc").material, sizeof(Game::Material)); std::memcpy(material, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc").material, sizeof(Game::Material));
material->textureTable = builder->getAllocator()->allocate<Game::MaterialTextureDef>(); auto textureTable = builder->getAllocator()->allocate<Game::MaterialTextureDef>();
std::memcpy(textureTable, material->textureTable, sizeof(Game::MaterialTextureDef));
material->textureTable = textureTable;
material->textureTable->u.image = image; material->textureTable->u.image = image;
material->info.name = fontName; material->info.name = fontName;
@ -159,7 +163,7 @@ namespace Assets
{ {
if (std::find(charset.begin(), charset.end(), i) == charset.end()) if (std::find(charset.begin(), charset.end(), i) == charset.end())
{ {
Components::Logger::Error("Font %s missing codepoint %d.", name.data(), i); Components::Logger::Error(Game::ERR_FATAL, "Font {} missing codepoint {}", name.data(), i);
} }
} }
} }
@ -183,15 +187,15 @@ namespace Assets
if (result == -1) if (result == -1)
{ {
Components::Logger::Error("Truetype font %s is broken.", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Truetype font {} is broken", name);
} }
else if (result < 0) else if (result < 0)
{ {
Components::Logger::Error("Texture size of font %s is not enough.", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Texture size of font {} is not enough", name);
} }
else if(h - result > size) else if(h - result > size)
{ {
Components::Logger::Print("Warn: Texture of font %s have too much left over space: %d\n", name.data(), h - result); Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Texture of font {} have too much left over space: {}\n", name, h - result);
} }
header->font = font; header->font = font;

View File

@ -5,10 +5,10 @@ namespace Assets
class IFont_s : public Components::AssetHandler::IAsset class IFont_s : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FONT; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FONT; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IFxEffectDef.hpp"
#define IW4X_FX_VERSION 1 #define IW4X_FX_VERSION 1
@ -72,13 +73,13 @@ namespace Assets
__int64 magic = buffer.read<__int64>(); __int64 magic = buffer.read<__int64>();
if (std::memcmp(&magic, "IW4xFx ", 8)) if (std::memcmp(&magic, "IW4xFx ", 8))
{ {
Components::Logger::Error("Reading fx '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading fx '{}' failed, header is invalid!", name);
} }
int version = buffer.read<int>(); int version = buffer.read<int>();
if (version != IW4X_FX_VERSION) if (version != IW4X_FX_VERSION)
{ {
Components::Logger::Error("Reading fx '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_FX_VERSION, version); Components::Logger::Error(Game::ERR_FATAL, "Reading fx '{}' failed, expected version is {}, but it was {}!", name, IW4X_FX_VERSION, version);
} }
Game::FxEffectDef* asset = buffer.readObject<Game::FxEffectDef>(); Game::FxEffectDef* asset = buffer.readObject<Game::FxEffectDef>();
@ -188,7 +189,7 @@ namespace Assets
} }
else if (elemDef->extended.trailDef) else if (elemDef->extended.trailDef)
{ {
Components::Logger::Error("Fx element of type %d has traildef, that's impossible?\n", elemDef->elemType); Components::Logger::Error(Game::ERR_FATAL, "Fx element of type {} has traildef, that's impossible?\n", elemDef->elemType);
} }
} }
} }
@ -211,14 +212,14 @@ namespace Assets
if (format != "iwfx"s) if (format != "iwfx"s)
{ {
Game::Com_EndParseSession(); Game::Com_EndParseSession();
Components::Logger::Error("Effect needs to be updated from the legacy format.\n"); Components::Logger::Error(Game::ERR_FATAL, "Effect needs to be updated from the legacy format.\n");
} }
int version = atoi(Game::Com_Parse(&session)); int version = atoi(Game::Com_Parse(&session));
if (version > 2) if (version > 2)
{ {
Game::Com_EndParseSession(); Game::Com_EndParseSession();
Components::Logger::Error("Version %i is too high. I can only handle up to %i.\n", version, 2); Components::Logger::Error(Game::ERR_FATAL, "Version {} is too high. I can only handle up to 2.\n", version);
} }
Utils::Memory::Allocator allocator; Utils::Memory::Allocator allocator;
@ -231,12 +232,12 @@ namespace Assets
if (!value) break; if (!value) break;
if (*value != '{') if (*value != '{')
{ {
Components::Logger::Error("Expected '{' to start a new segment, found '%s' instead.\n", value); Components::Logger::Error(Game::ERR_FATAL, "Expected '{' to start a new segment, found '{}' instead.\n", value);
} }
if (efx->elemCount >= ARRAYSIZE(efx->elems)) if (efx->elemCount >= ARRAYSIZE(efx->elems))
{ {
Components::Logger::Error("Cannot have more than %i segments.\n", ARRAYSIZE(efx->elems)); Components::Logger::Error(Game::ERR_FATAL, "Cannot have more than {} segments.\n", ARRAYSIZE(efx->elems));
} }
Game::FxEditorElemDef* element = &efx->elems[efx->elemCount]; Game::FxEditorElemDef* element = &efx->elems[efx->elemCount];
@ -253,13 +254,13 @@ namespace Assets
{ {
// TODO: Allow loading assets from raw! // TODO: Allow loading assets from raw!
if (Game::s_elemFields[i].handler(&session, element)) break; if (Game::s_elemFields[i].handler(&session, element)) break;
Components::Logger::Error("Failed to parse element %s!\n", newValue.data()); Components::Logger::Error(Game::ERR_FATAL, "Failed to parse element {}!\n", newValue);
} }
} }
if (!Game::Com_MatchToken(&session, ";", 1)) if (!Game::Com_MatchToken(&session, ";", 1))
{ {
Components::Logger::Error("Expected token ';'\n"); Components::Logger::Error(Game::ERR_FATAL, "Expected token ';'\n");
} }
} }
} }

View File

@ -5,11 +5,11 @@ namespace Assets
class IFxEffectDef : public Components::AssetHandler::IAsset class IFxEffectDef : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FX; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FX; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private: private:
void markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder); void markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IFxWorld.hpp"
namespace Assets namespace Assets
{ {
@ -184,11 +185,12 @@ namespace Assets
} }
} }
} }
void IFxWorld::load(Game::XAssetHeader* /*header*/, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) void IFxWorld::load(Game::XAssetHeader* /*header*/, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{ {
Game::FxWorld* map = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FXWORLD, name.data()).fxWorld; Game::FxWorld* map = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FXWORLD, name.data()).fxWorld;
if (map) return; if (map) return;
Components::Logger::Error("Missing fx_map %s... you can't make them yet you idiot.", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Missing fx_map {}... you can't make them yet you idiot.", name);
} }
} }

View File

@ -5,10 +5,10 @@ namespace Assets
class IFxWorld : public Components::AssetHandler::IAsset class IFxWorld : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FXWORLD; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FXWORLD; };
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IGameWorldMp.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,8 +5,8 @@ namespace Assets
class IGameWorldMp : public Components::AssetHandler::IAsset class IGameWorldMp : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IGameWorldSp.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,10 +5,10 @@ namespace Assets
class IGameWorldSp : public Components::AssetHandler::IAsset class IGameWorldSp : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private: private:
void savepathnode_tree_info_t(Game::pathnode_tree_t* nodeTree, Game::pathnode_tree_t* destNodeTree, Components::ZoneBuilder::Zone* builder); void savepathnode_tree_info_t(Game::pathnode_tree_t* nodeTree, Game::pathnode_tree_t* destNodeTree, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IGfxImage.hpp"
#define IW4X_IMG_VERSION "0" #define IW4X_IMG_VERSION "0"
@ -12,7 +13,7 @@ namespace Assets
image = builder->getAllocator()->allocate<Game::GfxImage>(); image = builder->getAllocator()->allocate<Game::GfxImage>();
if (!image) if (!image)
{ {
Components::Logger::Error("Failed to allocate GfxImage structure!"); Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate GfxImage structure!");
return; return;
} }
@ -30,7 +31,7 @@ namespace Assets
__int64 magic = reader.read<__int64>(); __int64 magic = reader.read<__int64>();
if (std::memcmp(&magic, "IW4xImg" IW4X_IMG_VERSION, 8)) if (std::memcmp(&magic, "IW4xImg" IW4X_IMG_VERSION, 8))
{ {
Components::Logger::Error(0, "Reading image '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading image '{}' failed, header is invalid!", name);
} }
image->mapType = reader.read<char>(); image->mapType = reader.read<char>();
@ -53,7 +54,7 @@ namespace Assets
if (image->texture.loadDef->resourceSize != dataLength) if (image->texture.loadDef->resourceSize != dataLength)
{ {
Components::Logger::Error("Resource size doesn't match the data length (%s)!\n", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Resource size doesn't match the data length ({})!\n", name);
} }
image->width = loadDef.dimensions[0]; image->width = loadDef.dimensions[0];
@ -72,7 +73,7 @@ namespace Assets
if (!iwi.exists()) if (!iwi.exists())
{ {
Components::Logger::Error("Loading image '%s' failed!", iwi.getName().data()); Components::Logger::Error(Game::ERR_FATAL, "Loading image '{}' failed!", iwi.getName());
return; return;
} }
@ -82,7 +83,7 @@ namespace Assets
if (std::memcmp(iwiHeader->tag, "IWi", 3) && iwiHeader->version == 8) if (std::memcmp(iwiHeader->tag, "IWi", 3) && iwiHeader->version == 8)
{ {
Components::Logger::Error("Image is not a valid IWi!"); Components::Logger::Error(Game::ERR_FATAL, "Image is not a valid IWi!");
return; return;
} }
@ -93,7 +94,7 @@ namespace Assets
image->texture.loadDef = builder->getAllocator()->allocate<Game::GfxImageLoadDef>(); image->texture.loadDef = builder->getAllocator()->allocate<Game::GfxImageLoadDef>();
if (!image->texture.loadDef) if (!image->texture.loadDef)
{ {
Components::Logger::Error("Failed to allocate GfxImageLoadDef structure!"); Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate GfxImageLoadDef structure!");
return; return;
} }

View File

@ -5,9 +5,9 @@ namespace Assets
class IGfxImage : public Components::AssetHandler::IAsset class IGfxImage : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_IMAGE; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_IMAGE; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IGfxLightDef.hpp"
#define IW4X_LIGHT_VERSION "0" #define IW4X_LIGHT_VERSION "0"
@ -15,14 +16,14 @@ namespace Assets
char* magic = reader.readArray<char>(7); char* magic = reader.readArray<char>(7);
if (std::memcmp(magic, "IW4xLit", 7)) if (std::memcmp(magic, "IW4xLit", 7))
{ {
Components::Logger::Error(0, "Reading light '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading light '{}' failed, header is invalid!", name);
} }
std::string version; std::string version;
version.push_back(reader.read<char>()); version.push_back(reader.read<char>());
if (version != IW4X_LIGHT_VERSION) if (version != IW4X_LIGHT_VERSION)
{ {
Components::Logger::Error("Reading light '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_LIGHT_VERSION), atoi(version.data())); Components::Logger::Error(Game::ERR_FATAL, "Reading light '{}' failed, expected version is {}, but it was {}!", name, IW4X_LIGHT_VERSION, version);
} }
Game::GfxLightDef* asset = reader.readObject<Game::GfxLightDef>(); Game::GfxLightDef* asset = reader.readObject<Game::GfxLightDef>();

View File

@ -5,10 +5,10 @@ namespace Assets
class IGfxLightDef : public Components::AssetHandler::IAsset class IGfxLightDef : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LIGHT_DEF; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LIGHT_DEF; }
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IGfxWorld.hpp"
#define IW4X_GFXMAP_VERSION 1 #define IW4X_GFXMAP_VERSION 1
@ -137,13 +138,13 @@ namespace Assets
__int64 magic = reader.read<__int64>(); __int64 magic = reader.read<__int64>();
if (std::memcmp(&magic, "IW4xGfxW", 8)) if (std::memcmp(&magic, "IW4xGfxW", 8))
{ {
Components::Logger::Error("Reading gfxworld '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading gfxworld '{}' failed, header is invalid!", name);
} }
int version = reader.read<int>(); int version = reader.read<int>();
if (version != IW4X_GFXMAP_VERSION) if (version != IW4X_GFXMAP_VERSION)
{ {
Components::Logger::Error("Reading gfxworld '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_GFXMAP_VERSION, version); Components::Logger::Error(Game::ERR_FATAL, "Reading gfxworld '{}' failed, expected version is {}, but it was {}!", name, IW4X_GFXMAP_VERSION, version);
} }
Game::GfxWorld* asset = reader.readObject<Game::GfxWorld>(); Game::GfxWorld* asset = reader.readObject<Game::GfxWorld>();
@ -950,7 +951,7 @@ namespace Assets
} }
buffer->popBlock(); buffer->popBlock();
SaveLogExit(); SaveLogExit();
} }
void IGfxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IGfxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)

View File

@ -5,11 +5,12 @@ namespace Assets
class IGfxWorld : public Components::AssetHandler::IAsset class IGfxWorld : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GFXWORLD; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GFXWORLD; };
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private: private:
void saveGfxWorldDpvsPlanes(Game::GfxWorld* world, Game::GfxWorldDpvsPlanes* asset, Game::GfxWorldDpvsPlanes* dest, Components::ZoneBuilder::Zone* builder); void saveGfxWorldDpvsPlanes(Game::GfxWorld* world, Game::GfxWorldDpvsPlanes* asset, Game::GfxWorldDpvsPlanes* dest, Components::ZoneBuilder::Zone* builder);
void saveGfxWorldDraw(Game::GfxWorldDraw* asset, Game::GfxWorldDraw* dest, Components::ZoneBuilder::Zone* builder); void saveGfxWorldDraw(Game::GfxWorldDraw* asset, Game::GfxWorldDraw* dest, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "ILoadedSound.hpp"
namespace Assets namespace Assets
{ {
@ -29,7 +30,7 @@ namespace Assets
unsigned int chunkIDBuffer = reader.read<unsigned int>(); unsigned int chunkIDBuffer = reader.read<unsigned int>();
if (chunkIDBuffer != 0x46464952) // RIFF if (chunkIDBuffer != 0x46464952) // RIFF
{ {
Components::Logger::Error(0, "Reading sound '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, header is invalid!", name);
return; return;
} }
@ -38,7 +39,7 @@ namespace Assets
unsigned int format = reader.read<unsigned int>(); unsigned int format = reader.read<unsigned int>();
if (format != 0x45564157) // WAVE if (format != 0x45564157) // WAVE
{ {
Components::Logger::Error(0, "Reading sound '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, header is invalid!", name);
return; return;
} }
@ -55,7 +56,7 @@ namespace Assets
sound->sound.info.format = reader.read<short>(); sound->sound.info.format = reader.read<short>();
if (sound->sound.info.format != 1 && sound->sound.info.format != 17) if (sound->sound.info.format != 1 && sound->sound.info.format != 17)
{ {
Components::Logger::Error(0, "Reading sound '%s' failed, invalid format!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, invalid format!", name);
return; return;
} }
@ -89,11 +90,11 @@ namespace Assets
if (!sound->sound.info.data_ptr) if (!sound->sound.info.data_ptr)
{ {
Components::Logger::Error(0, "Reading sound '%s' failed, invalid format!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, invalid format!", name);
return; return;
} }
sound->name = builder->getAllocator()->duplicateString(name.c_str()); sound->name = builder->getAllocator()->duplicateString(name.data());
header->loadSnd = sound; header->loadSnd = sound;
} }

View File

@ -5,9 +5,9 @@ namespace Assets
class ILoadedSound : public Components::AssetHandler::IAsset class ILoadedSound : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOADED_SOUND; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOADED_SOUND; };
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "ILocalizeEntry.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,8 +5,8 @@ namespace Assets
class ILocalizeEntry : public Components::AssetHandler::IAsset class ILocalizeEntry : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY; };
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IMapEnts.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,10 +5,10 @@ namespace Assets
class IMapEnts : public Components::AssetHandler::IAsset class IMapEnts : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MAP_ENTS; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MAP_ENTS; }
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IMaterial.hpp"
#define IW4X_MAT_VERSION "1" #define IW4X_MAT_VERSION "1"
@ -64,14 +65,14 @@ namespace Assets
char* magic = reader.readArray<char>(7); char* magic = reader.readArray<char>(7);
if (std::memcmp(magic, "IW4xMat", 7)) if (std::memcmp(magic, "IW4xMat", 7))
{ {
Components::Logger::Error(0, "Reading material '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading material '{}' failed, header is invalid!", name);
} }
std::string version; std::string version;
version.push_back(reader.read<char>()); version.push_back(reader.read<char>());
if (version != IW4X_MAT_VERSION) if (version != IW4X_MAT_VERSION)
{ {
Components::Logger::Error("Reading material '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_MAT_VERSION), atoi(version.data())); Components::Logger::Error(Game::ERR_FATAL, "Reading material '{}' failed, expected version is {}, but it was {}!", name, IW4X_MAT_VERSION, version);
} }
Game::Material* asset = reader.readObject<Game::Material>(); Game::Material* asset = reader.readObject<Game::Material>();
@ -106,18 +107,18 @@ namespace Assets
asset->techniqueSet = techsetPtr; asset->techniqueSet = techsetPtr;
if (asset->techniqueSet->name[0] == ',') continue; // Try to find a better one if (asset->techniqueSet->name[0] == ',') continue; // Try to find a better one
Components::Logger::Print("Techset '%s' has been mapped to '%s'\n", techsetName.data(), asset->techniqueSet->name); Components::Logger::Print("Techset '{}' has been mapped to '{}'\n", techsetName, asset->techniqueSet->name);
break; break;
} }
} }
} }
else { else {
Components::Logger::Print("Techset %s exists with the same name in iw4, and was mapped 1:1 with %s\n", techsetName.data(), asset->techniqueSet->name); Components::Logger::Print("Techset {} exists with the same name in iw4, and was mapped 1:1 with %s\n", techsetName, asset->techniqueSet->name);
} }
if (!asset->techniqueSet) if (!asset->techniqueSet)
{ {
Components::Logger::Error("Missing techset: '%s' not found", techsetName.data()); Components::Logger::Error(Game::ERR_FATAL, "Missing techset: '{}' not found", techsetName);
} }
} }
@ -195,7 +196,7 @@ namespace Assets
std::memcpy(asset->stateBitsEntry, header.material->stateBitsEntry, 48); std::memcpy(asset->stateBitsEntry, header.material->stateBitsEntry, 48);
asset->constantCount = header.material->constantCount; asset->constantCount = header.material->constantCount;
asset->constantTable = header.material->constantTable; asset->constantTable = header.material->constantTable;
Components::Logger::Print("For %s, copied constants & statebits from %s\n", asset->info.name, header.material->info.name); Components::Logger::Print("For {}, copied constants & statebits from {}\n", asset->info.name, header.material->info.name);
replacementFound = true; replacementFound = true;
} }
} }
@ -231,7 +232,7 @@ namespace Assets
if (techsetMatches(header.material, asset)) if (techsetMatches(header.material, asset))
{ {
Components::Logger::Print("Material %s with techset %s has been mapped to %s\n", asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name); Components::Logger::Print("Material {} with techset {} has been mapped to {}\n", asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name);
asset->info.sortKey = header.material->info.sortKey; asset->info.sortKey = header.material->info.sortKey;
replacementFound = true; replacementFound = true;
} }
@ -241,9 +242,10 @@ namespace Assets
if (!replacementFound && asset->techniqueSet) if (!replacementFound && asset->techniqueSet)
{ {
Components::Logger::Print("No replacement found for material %s with techset %s\n", asset->info.name, asset->techniqueSet->name); Components::Logger::Print("No replacement found for material {} with techset {}\n", asset->info.name, asset->techniqueSet->name);
std::string techName = asset->techniqueSet->name; std::string techName = asset->techniqueSet->name;
if (techSetCorrespondance.find(techName) != techSetCorrespondance.end()) { if (techSetCorrespondance.contains(techName))
{
auto iw4TechSetName = techSetCorrespondance[techName]; auto iw4TechSetName = techSetCorrespondance[techName];
Game::XAssetEntry* iw4TechSet = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, iw4TechSetName.data()); Game::XAssetEntry* iw4TechSet = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, iw4TechSetName.data());
@ -257,9 +259,8 @@ namespace Assets
if (header.material->techniqueSet == iw4TechSet->asset.header.techniqueSet) if (header.material->techniqueSet == iw4TechSet->asset.header.techniqueSet)
{ {
Components::Logger::Print("Material %s with techset %s has been mapped to %s (last chance!), taking the sort key of material %s\n", Components::Logger::Print("Material {} with techset {} has been mapped to {} (last chance!), taking the sort key of material {}\n",
asset->info.name, asset->techniqueSet->name, asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name, header.material->info.name);
header.material->techniqueSet->name, header.material->info.name);
asset->info.sortKey = header.material->info.sortKey; asset->info.sortKey = header.material->info.sortKey;
asset->techniqueSet = iw4TechSet->asset.header.techniqueSet; asset->techniqueSet = iw4TechSet->asset.header.techniqueSet;
@ -278,23 +279,23 @@ namespace Assets
if (!replacementFound) if (!replacementFound)
{ {
Components::Logger::Print("Could not find any loaded material with techset %s (in replacement of %s), so I cannot set the sortkey for material %s\n", iw4TechSetName.data(), asset->techniqueSet->name, asset->info.name); Components::Logger::Print("Could not find any loaded material with techset {} (in replacement of {}), so I cannot set the sortkey for material {}\n", iw4TechSetName, asset->techniqueSet->name, asset->info.name);
} }
} }
else else
{ {
Components::Logger::Print("Could not find any loaded techset with iw4 name %s for iw3 techset %s\n", iw4TechSetName.data(), asset->techniqueSet->name); Components::Logger::Print("Could not find any loaded techset with iw4 name {} for iw3 techset {}\n", iw4TechSetName, asset->techniqueSet->name);
} }
} }
else else
{ {
Components::Logger::Print("Could not match iw3 techset %s with any of the techsets I know! This is a critical error, there's a good chance the map will not be playable.\n", techName.data()); Components::Logger::Print("Could not match iw3 techset {} with any of the techsets I know! This is a critical error, there's a good chance the map will not be playable.\n", techName);
} }
} }
if (!reader.end()) if (!reader.end())
{ {
Components::Logger::Error("Material data left!"); Components::Logger::Error(Game::ERR_FATAL, "Material data left!");
} }
/*char baseIndex = 0; /*char baseIndex = 0;
@ -339,7 +340,7 @@ namespace Assets
if (!infoData.is_object()) if (!infoData.is_object())
{ {
Components::Logger::Error("Failed to load material information for %s!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Failed to load material information for {}!", name);
return; return;
} }
@ -347,7 +348,7 @@ namespace Assets
if (!base.is_string()) if (!base.is_string())
{ {
Components::Logger::Error("No valid material base provided for %s!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "No valid material base provided for {}!", name);
return; return;
} }
@ -355,7 +356,7 @@ namespace Assets
if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!? if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!?
{ {
Components::Logger::Error("Basematerial '%s' not found for %s!", base.string_value().data(), name.data()); Components::Logger::Error(Game::ERR_FATAL, "Basematerial '{}' not found for {}!", base.string_value(), name);
return; return;
} }
@ -363,7 +364,7 @@ namespace Assets
if (!material) if (!material)
{ {
Components::Logger::Error("Failed to allocate material structure!"); Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate material structure!");
return; return;
} }
@ -451,7 +452,8 @@ namespace Assets
if (!applied) if (!applied)
{ {
Components::Logger::Error(0, "Unable to find texture for map '%s' in %s!", map.string_value().data(), baseMaterial->info.name); Components::Logger::Error(Game::ERR_FATAL, "Unable to find texture for map '{}' in {}!",
map.string_value(), baseMaterial->info.name);
} }
} }
else else
@ -468,7 +470,7 @@ namespace Assets
if (!textureTable) if (!textureTable)
{ {
Components::Logger::Error("Failed to allocate texture table!"); Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate texture table!");
return; return;
} }

View File

@ -5,11 +5,11 @@ namespace Assets
class IMaterial : public Components::AssetHandler::IAsset class IMaterial : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MATERIAL; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MATERIAL; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadJson(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadJson(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);

View File

@ -1,55 +1,57 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IMaterialPixelShader.hpp"
#define IW4X_TECHSET_VERSION "0" #define IW4X_TECHSET_VERSION "0"
namespace Assets namespace Assets
{ {
void IMaterialPixelShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialPixelShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
} }
void IMaterialPixelShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) void IMaterialPixelShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{ {
header->pixelShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).pixelShader; header->pixelShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).pixelShader;
} }
void IMaterialPixelShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialPixelShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File psFile(Utils::String::VA("ps/%s.iw4xPS", name.data())); Components::FileSystem::File psFile(Utils::String::VA("ps/%s.iw4xPS", name.data()));
if (!psFile.exists()) return; if (!psFile.exists()) return;
Utils::Stream::Reader reader(builder->getAllocator(), psFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), psFile.getBuffer());
char* magic = reader.readArray<char>(8); char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xPIXL", 8)) if (std::memcmp(magic, "IW4xPIXL", 8))
{ {
Components::Logger::Error(0, "Reading pixel shader '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading pixel shader '{}' failed, header is invalid!", name);
} }
std::string version; std::string version;
version.push_back(reader.read<char>()); version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION) if (version != IW4X_TECHSET_VERSION)
{ {
Components::Logger::Error("Reading pixel shader '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_TECHSET_VERSION), atoi(version.data())); Components::Logger::Error(Game::ERR_FATAL,
} "Reading pixel shader '{}' failed, expected version is {}, but it was {}!", name, IW4X_TECHSET_VERSION, version);
}
Game::MaterialPixelShader* asset = reader.readObject<Game::MaterialPixelShader>(); Game::MaterialPixelShader* asset = reader.readObject<Game::MaterialPixelShader>();
if (asset->name) if (asset->name)
{ {
asset->name = reader.readCString(); asset->name = reader.readCString();
} }
if (asset->prog.loadDef.program) if (asset->prog.loadDef.program)
{ {
asset->prog.loadDef.program = reader.readArray<unsigned int>(asset->prog.loadDef.programSize); asset->prog.loadDef.program = reader.readArray<unsigned int>(asset->prog.loadDef.programSize);
} }
header->pixelShader = asset; header->pixelShader = asset;
} }
void IMaterialPixelShader::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMaterialPixelShader::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {

View File

@ -5,12 +5,12 @@ namespace Assets
class IMaterialPixelShader : public Components::AssetHandler::IAsset class IMaterialPixelShader : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PIXELSHADER; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PIXELSHADER; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
}; };
} }

View File

@ -1,141 +1,144 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IMaterialTechniqueSet.hpp"
#define IW4X_TECHSET_VERSION "0" #define IW4X_TECHSET_VERSION "0"
namespace Assets namespace Assets
{ {
void IMaterialTechniqueSet::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialTechniqueSet::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
} }
void IMaterialTechniqueSet::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) void IMaterialTechniqueSet::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{ {
header->techniqueSet = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).techniqueSet; header->techniqueSet = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).techniqueSet;
} }
void IMaterialTechniqueSet::loadBinaryTechnique(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialTechniqueSet::loadBinaryTechnique(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::MaterialPass, 20); AssertSize(Game::MaterialPass, 20);
Components::FileSystem::File techFile(Utils::String::VA("techniques/%s.iw4xTech", name.data())); Components::FileSystem::File techFile(Utils::String::VA("techniques/%s.iw4xTech", name.data()));
if (!techFile.exists()) { if (!techFile.exists()) {
*tech = nullptr; *tech = nullptr;
Components::Logger::Print("Warning: Missing technique '%s'\n", name.data()); Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Missing technique '{}'\n", name);
return; return;
} }
Utils::Stream::Reader reader(builder->getAllocator(), techFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), techFile.getBuffer());
char* magic = reader.readArray<char>(8); char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xTECH", 8)) if (std::memcmp(magic, "IW4xTECH", 8))
{ {
Components::Logger::Error(0, "Reading technique '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading technique '{}' failed, header is invalid!", name);
} }
std::string version; std::string version;
version.push_back(reader.read<char>()); version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION) if (version != IW4X_TECHSET_VERSION)
{ {
Components::Logger::Error("Reading technique '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_TECHSET_VERSION), atoi(version.data())); Components::Logger::Error(Game::ERR_FATAL,
} "Reading technique '{}' failed, expected version is {}, but it was {}!", name, IW4X_TECHSET_VERSION, version.data());
}
unsigned short flags = reader.read<unsigned short>(); unsigned short flags = reader.read<unsigned short>();
unsigned short passCount = reader.read<unsigned short>(); unsigned short passCount = reader.read<unsigned short>();
Game::MaterialTechnique* asset = (Game::MaterialTechnique*)builder->getAllocator()->allocateArray<unsigned char>(sizeof(Game::MaterialTechnique) + (sizeof(Game::MaterialPass) * (passCount - 1))); Game::MaterialTechnique* asset = (Game::MaterialTechnique*)builder->getAllocator()->allocateArray<unsigned char>(sizeof(Game::MaterialTechnique) + (sizeof(Game::MaterialPass) * (passCount - 1)));
asset->name = builder->getAllocator()->duplicateString(name); asset->name = builder->getAllocator()->duplicateString(name);
asset->flags = flags; asset->flags = flags;
asset->passCount = passCount; asset->passCount = passCount;
Game::MaterialPass* passes = reader.readArray<Game::MaterialPass>(passCount); Game::MaterialPass* passes = reader.readArray<Game::MaterialPass>(passCount);
std::memcpy(asset->passArray, passes, sizeof(Game::MaterialPass) * passCount); std::memcpy(asset->passArray, passes, sizeof(Game::MaterialPass) * passCount);
for (unsigned short i = 0; i < asset->passCount; i++) for (unsigned short i = 0; i < asset->passCount; i++)
{ {
Game::MaterialPass* pass = &asset->passArray[i]; Game::MaterialPass* pass = &asset->passArray[i];
if (pass->vertexDecl) if (pass->vertexDecl)
{ {
const char* declName = reader.readCString(); const char* declName = reader.readCString();
pass->vertexDecl = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXDECL, declName, builder).vertexDecl; pass->vertexDecl = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXDECL, declName, builder).vertexDecl;
} }
if (pass->vertexShader) if (pass->vertexShader)
{ {
const char* vsName = reader.readCString(); const char* vsName = reader.readCString();
pass->vertexShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, vsName, builder).vertexShader; pass->vertexShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, vsName, builder).vertexShader;
} }
if (pass->pixelShader) if (pass->pixelShader)
{ {
const char* psName = reader.readCString(); const char* psName = reader.readCString();
pass->pixelShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_PIXELSHADER, psName, builder).pixelShader; pass->pixelShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_PIXELSHADER, psName, builder).pixelShader;
} }
pass->args = reader.readArray<Game::MaterialShaderArgument>(pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount); pass->args = reader.readArray<Game::MaterialShaderArgument>(pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount);
for (int j = 0; j < pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount; j++) for (int j = 0; j < pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount; j++)
{ {
if (pass->args[j].type == 1 || pass->args[j].type == 7) if (pass->args[j].type == 1 || pass->args[j].type == 7)
{ {
pass->args[j].u.literalConst = reader.readArray<float>(4); pass->args[j].u.literalConst = reader.readArray<float>(4);
} }
if (pass->args[j].type == 3 || pass->args[j].type == 5) if (pass->args[j].type == 3 || pass->args[j].type == 5)
{ {
pass->args[j].u.codeConst.index = *reader.readObject<unsigned short>(); pass->args[j].u.codeConst.index = *reader.readObject<unsigned short>();
pass->args[j].u.codeConst.firstRow = *reader.readObject<unsigned char>(); pass->args[j].u.codeConst.firstRow = *reader.readObject<unsigned char>();
pass->args[j].u.codeConst.rowCount = *reader.readObject<unsigned char>(); pass->args[j].u.codeConst.rowCount = *reader.readObject<unsigned char>();
} }
} }
} }
*tech = asset; *tech = asset;
} }
void IMaterialTechniqueSet::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialTechniqueSet::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File tsFile(Utils::String::VA("techsets/%s.iw4xTS", name.data())); Components::FileSystem::File tsFile(Utils::String::VA("techsets/%s.iw4xTS", name.data()));
if (!tsFile.exists()) return; if (!tsFile.exists()) return;
Utils::Stream::Reader reader(builder->getAllocator(), tsFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), tsFile.getBuffer());
char* magic = reader.readArray<char>(8); char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xTSET", 8)) if (std::memcmp(magic, "IW4xTSET", 8))
{ {
Components::Logger::Error(0, "Reading techset '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading techset '{}' failed, header is invalid!", name);
} }
std::string version; std::string version;
version.push_back(reader.read<char>()); version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION) if (version != IW4X_TECHSET_VERSION)
{ {
Components::Logger::Error("Reading techset '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_TECHSET_VERSION), atoi(version.data())); Components::Logger::Error(Game::ERR_FATAL, "Reading techset '{}' failed, expected version is {}, but it was {}!",
} name, IW4X_TECHSET_VERSION, version);
}
Game::MaterialTechniqueSet* asset = reader.readObject<Game::MaterialTechniqueSet>(); Game::MaterialTechniqueSet* asset = reader.readObject<Game::MaterialTechniqueSet>();
if (asset->name) if (asset->name)
{ {
asset->name = reader.readCString(); asset->name = reader.readCString();
} }
for (int i = 0; i < 48; i++) for (int i = 0; i < 48; i++)
{ {
if (asset->techniques[i]) if (asset->techniques[i])
{ {
const char* techName = reader.readCString(); const char* techName = reader.readCString();
this->loadBinaryTechnique(&asset->techniques[i], techName, builder); this->loadBinaryTechnique(&asset->techniques[i], techName, builder);
} }
} }
header->techniqueSet = asset; header->techniqueSet = asset;
} }
void IMaterialTechniqueSet::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMaterialTechniqueSet::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {

View File

@ -5,15 +5,15 @@ namespace Assets
class IMaterialTechniqueSet : public Components::AssetHandler::IAsset class IMaterialTechniqueSet : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinaryTechnique(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadBinaryTechnique(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder);
}; };
} }

View File

@ -1,49 +1,51 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IMaterialVertexDeclaration.hpp"
#define IW4X_TECHSET_VERSION "0" #define IW4X_TECHSET_VERSION "0"
namespace Assets namespace Assets
{ {
void IMaterialVertexDeclaration::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialVertexDeclaration::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
} }
void IMaterialVertexDeclaration::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) void IMaterialVertexDeclaration::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{ {
header->vertexDecl = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexDecl; header->vertexDecl = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexDecl;
} }
void IMaterialVertexDeclaration::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialVertexDeclaration::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File declFile(Utils::String::VA("decl/%s.iw4xDECL", name.data())); Components::FileSystem::File declFile(Utils::String::VA("decl/%s.iw4xDECL", name.data()));
if (!declFile.exists()) return; if (!declFile.exists()) return;
Utils::Stream::Reader reader(builder->getAllocator(), declFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), declFile.getBuffer());
char* magic = reader.readArray<char>(8); char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xDECL", 8)) if (std::memcmp(magic, "IW4xDECL", 8))
{ {
Components::Logger::Error(0, "Reading vertex declaration '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading vertex declaration '{}' failed, header is invalid!", name);
} }
std::string version; std::string version;
version.push_back(reader.read<char>()); version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION) if (version != IW4X_TECHSET_VERSION)
{ {
Components::Logger::Error("Reading vertex declaration '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_TECHSET_VERSION), atoi(version.data())); Components::Logger::Error(Game::ERR_FATAL, "Reading vertex declaration '{}' failed, expected version is {}, but it was {}!",
} name, IW4X_TECHSET_VERSION, version.data());
}
Game::MaterialVertexDeclaration* asset = reader.readObject<Game::MaterialVertexDeclaration>(); Game::MaterialVertexDeclaration* asset = reader.readObject<Game::MaterialVertexDeclaration>();
if (asset->name) if (asset->name)
{ {
asset->name = reader.readCString(); asset->name = reader.readCString();
} }
header->vertexDecl = asset; header->vertexDecl = asset;
} }
void IMaterialVertexDeclaration::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMaterialVertexDeclaration::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {

View File

@ -5,12 +5,12 @@ namespace Assets
class IMaterialVertexDeclaration : public Components::AssetHandler::IAsset class IMaterialVertexDeclaration : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_VERTEXDECL; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_VERTEXDECL; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
}; };
} }

View File

@ -1,54 +1,56 @@
#include <StdInclude.hpp> #include <STDInclude.hpp>
#include "IMaterialVertexShader.hpp"
#define IW4X_TECHSET_VERSION "0" #define IW4X_TECHSET_VERSION "0"
namespace Assets namespace Assets
{ {
void IMaterialVertexShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialVertexShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
} }
void IMaterialVertexShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) void IMaterialVertexShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{ {
header->vertexShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexShader; header->vertexShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexShader;
} }
void IMaterialVertexShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMaterialVertexShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File vsFile(Utils::String::VA("vs/%s.iw4xVS", name.data())); Components::FileSystem::File vsFile(Utils::String::VA("vs/%s.iw4xVS", name.data()));
if (!vsFile.exists()) return; if (!vsFile.exists()) return;
Utils::Stream::Reader reader(builder->getAllocator(), vsFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), vsFile.getBuffer());
char* magic = reader.readArray<char>(8); char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xVERT", 8)) if (std::memcmp(magic, "IW4xVERT", 8))
{ {
Components::Logger::Error(0, "Reading vertex shader '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading vertex shader '{}' failed, header is invalid!", name);
} }
std::string version; std::string version;
version.push_back(reader.read<char>()); version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION) if (version != IW4X_TECHSET_VERSION)
{ {
Components::Logger::Error("Reading vertex shader '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_TECHSET_VERSION), atoi(version.data())); Components::Logger::Error(Game::ERR_FATAL, "Reading vertex shader '{}' failed, expected version is {}, but it was {}!",
} name, IW4X_TECHSET_VERSION, version);
}
Game::MaterialVertexShader* asset = reader.readObject<Game::MaterialVertexShader>(); Game::MaterialVertexShader* asset = reader.readObject<Game::MaterialVertexShader>();
if (asset->name) if (asset->name)
{ {
asset->name = reader.readCString(); asset->name = reader.readCString();
} }
if (asset->prog.loadDef.program) if (asset->prog.loadDef.program)
{ {
asset->prog.loadDef.program = reader.readArray<unsigned int>(asset->prog.loadDef.programSize); asset->prog.loadDef.program = reader.readArray<unsigned int>(asset->prog.loadDef.programSize);
} }
header->vertexShader = asset; header->vertexShader = asset;
} }
void IMaterialVertexShader::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMaterialVertexShader::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {

View File

@ -5,12 +5,12 @@ namespace Assets
class IMaterialVertexShader : public Components::AssetHandler::IAsset class IMaterialVertexShader : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_VERTEXSHADER; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_VERTEXSHADER; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
}; };
} }

View File

@ -1,37 +1,38 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IMenuList.hpp"
namespace Assets namespace Assets
{ {
void IMenuList::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) void IMenuList::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{ {
Utils::Memory::Allocator* allocator = builder->getAllocator(); Utils::Memory::Allocator* allocator = builder->getAllocator();
// actually gets the whole list // actually gets the whole list
auto menus = Components::Menus::LoadMenu(name); auto menus = Components::Menus::LoadMenu(name);
if (menus.empty()) return; if (menus.empty()) return;
// Allocate new menu list // Allocate new menu list
Game::MenuList* newList = allocator->allocate<Game::MenuList>(); Game::MenuList* newList = allocator->allocate<Game::MenuList>();
if (!newList) return; if (!newList) return;
newList->menus = allocator->allocateArray<Game::menuDef_t*>(menus.size()); newList->menus = allocator->allocateArray<Game::menuDef_t*>(menus.size());
if (!newList->menus) if (!newList->menus)
{ {
allocator->free(newList); allocator->free(newList);
return; return;
} }
newList->name = allocator->duplicateString(name); newList->name = allocator->duplicateString(name);
newList->menuCount = menus.size(); newList->menuCount = menus.size();
// Copy new menus // Copy new menus
for (unsigned int i = 0; i < menus.size(); ++i) for (unsigned int i = 0; i < menus.size(); ++i)
{ {
newList->menus[i] = menus[i].second; newList->menus[i] = menus[i].second;
} }
header->menuList = newList; header->menuList = newList;
} }
void IMenuList::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMenuList::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
Game::MenuList *asset = header.menuList; Game::MenuList *asset = header.menuList;

View File

@ -5,10 +5,10 @@ namespace Assets
class IMenuList : public Components::AssetHandler::IAsset class IMenuList : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MENULIST; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MENULIST; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IPhysCollmap.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,9 +5,9 @@ namespace Assets
class IPhysCollmap : public Components::AssetHandler::IAsset class IPhysCollmap : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private: private:
void savePhysGeomInfoArray(Components::ZoneBuilder::Zone* builder, Game::PhysGeomInfo* geoms, unsigned int count); void savePhysGeomInfoArray(Components::ZoneBuilder::Zone* builder, Game::PhysGeomInfo* geoms, unsigned int count);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IPhysPreset.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,8 +5,8 @@ namespace Assets
class IPhysPreset : public Components::AssetHandler::IAsset class IPhysPreset : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSPRESET; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSPRESET; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IRawFile.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,9 +5,9 @@ namespace Assets
class IRawFile : public Components::AssetHandler::IAsset class IRawFile : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_RAWFILE; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_RAWFILE; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "ISndCurve.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,8 +5,8 @@ namespace Assets
class ISndCurve : public Components::AssetHandler::IAsset class ISndCurve : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND_CURVE; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND_CURVE; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IStringTable.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,9 +5,9 @@ namespace Assets
class IStringTable : public Components::AssetHandler::IAsset class IStringTable : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_STRINGTABLE; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_STRINGTABLE; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private: private:
void saveStringTableCellArray(Components::ZoneBuilder::Zone* builder, Game::StringTableCell* values, int count); void saveStringTableCellArray(Components::ZoneBuilder::Zone* builder, Game::StringTableCell* values, int count);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IStructuredDataDefSet.hpp"
namespace Assets namespace Assets
{ {

View File

@ -5,9 +5,9 @@ namespace Assets
class IStructuredDataDefSet : public Components::AssetHandler::IAsset class IStructuredDataDefSet : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_STRUCTURED_DATA_DEF; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_STRUCTURED_DATA_DEF; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void saveStructuredDataEnumArray(Game::StructuredDataEnum* enums, int numEnums, Components::ZoneBuilder::Zone* builder); void saveStructuredDataEnumArray(Game::StructuredDataEnum* enums, int numEnums, Components::ZoneBuilder::Zone* builder);
void saveStructuredDataStructArray(Game::StructuredDataStruct* structs, int numStructs, Components::ZoneBuilder::Zone* builder); void saveStructuredDataStructArray(Game::StructuredDataStruct* structs, int numStructs, Components::ZoneBuilder::Zone* builder);

View File

@ -1,44 +1,45 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "ITracerDef.hpp"
namespace Assets namespace Assets
{ {
void ITracerDef::load(Game::XAssetHeader* /*header*/, const std::string& /*name*/, Components::ZoneBuilder::Zone* /*builder*/) void ITracerDef::load(Game::XAssetHeader* /*header*/, const std::string& /*name*/, Components::ZoneBuilder::Zone* /*builder*/)
{ {
return; // don't load from filesystem right now // don't load from filesystem right now
} }
void ITracerDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void ITracerDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
Game::TracerDef* asset = header.tracerDef; Game::TracerDef* asset = header.tracerDef;
if (asset->material) if (asset->material)
{ {
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->material); builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->material);
} }
} }
void ITracerDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void ITracerDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::TracerDef, 0x70); AssertSize(Game::TracerDef, 0x70);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::TracerDef* asset = header.tracerDef; Game::TracerDef* asset = header.tracerDef;
Game::TracerDef* dest = buffer->dest<Game::TracerDef>(); Game::TracerDef* dest = buffer->dest<Game::TracerDef>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->material) if (asset->material)
{ {
dest->material = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->material).material; dest->material = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->material).material;
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -2,13 +2,13 @@
namespace Assets namespace Assets
{ {
class ITracerDef : public Components::AssetHandler::IAsset class ITracerDef : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_TRACER; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_TRACER; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -5,11 +5,11 @@ namespace Assets
class IWeapon : public Components::AssetHandler::IAsset class IWeapon : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_WEAPON; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_WEAPON; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private: private:
void writeWeaponDef(Game::WeaponDef* def, Components::ZoneBuilder::Zone* builder, Utils::Stream* buffer); void writeWeaponDef(Game::WeaponDef* def, Components::ZoneBuilder::Zone* builder, Utils::Stream* buffer);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IXAnimParts.hpp"
#define IW4X_ANIM_VERSION 1 #define IW4X_ANIM_VERSION 1
@ -15,13 +16,13 @@ namespace Assets
__int64 magic = reader.read<__int64>(); __int64 magic = reader.read<__int64>();
if (std::memcmp(&magic, "IW4xAnim", 8)) if (std::memcmp(&magic, "IW4xAnim", 8))
{ {
Components::Logger::Error(0, "Reading animation '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, header is invalid!", name);
} }
int version = reader.read<int>(); int version = reader.read<int>();
if (version != IW4X_ANIM_VERSION) if (version != IW4X_ANIM_VERSION)
{ {
Components::Logger::Error(0, "Reading animation '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_ANIM_VERSION, version); Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, expected version is {}, but it was {}!", name, IW4X_ANIM_VERSION, version);
} }
Game::XAnimParts* xanim = reader.readArray<Game::XAnimParts>(); Game::XAnimParts* xanim = reader.readArray<Game::XAnimParts>();
@ -96,7 +97,7 @@ namespace Assets
if (!reader.end()) if (!reader.end())
{ {
Components::Logger::Error(0, "Reading animation '%s' failed, remaining raw data found!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, remaining raw data found!", name);
} }
header->parts = xanim; header->parts = xanim;

View File

@ -5,11 +5,11 @@ namespace Assets
class IXAnimParts : public Components::AssetHandler::IAsset class IXAnimParts : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XANIMPARTS; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XANIMPARTS; }
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private: private:
void saveXAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder); void saveXAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IXModel.hpp"
#define IW4X_MODEL_VERSION 5 #define IW4X_MODEL_VERSION 5
@ -48,20 +49,20 @@ namespace Assets
} }
// Access index block // Access index block
if (surf->triIndices) if (surf->triIndices)
{ {
void* oldPtr = surf->triIndices; void* oldPtr = surf->triIndices;
surf->triIndices = reader->readArray<unsigned short>(surf->triCount * 3); surf->triIndices = reader->readArray<unsigned short>(surf->triCount * 3);
if (builder->getAllocator()->isPointerMapped(oldPtr)) if (builder->getAllocator()->isPointerMapped(oldPtr))
{ {
surf->triIndices = builder->getAllocator()->getPointer<unsigned short>(oldPtr); surf->triIndices = builder->getAllocator()->getPointer<unsigned short>(oldPtr);
} }
else else
{ {
builder->getAllocator()->mapPointer(oldPtr, surf->triIndices); builder->getAllocator()->mapPointer(oldPtr, surf->triIndices);
} }
} }
} }
void IXModel::loadXModelSurfs(Game::XModelSurfs* asset, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder) void IXModel::loadXModelSurfs(Game::XModelSurfs* asset, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder)
@ -100,18 +101,18 @@ namespace Assets
__int64 magic = reader.read<__int64>(); __int64 magic = reader.read<__int64>();
if (std::memcmp(&magic, "IW4xModl", 8)) if (std::memcmp(&magic, "IW4xModl", 8))
{ {
Components::Logger::Error(0, "Reading model '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading model '{}' failed, header is invalid!", name);
} }
int version = reader.read<int>(); int version = reader.read<int>();
if (version != IW4X_MODEL_VERSION) if (version != IW4X_MODEL_VERSION)
{ {
Components::Logger::Error(0, "Reading model '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_MODEL_VERSION, version); Components::Logger::Error(Game::ERR_FATAL, "Reading model '{}' failed, expected version is {}, but it was {}!", name, IW4X_MODEL_VERSION, version);
} }
if (version == 4) if (version == 4)
{ {
Components::Logger::Print("WARNING: Model '%s' is in legacy format, please update it!\n", name.data()); Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Model '{}' is in legacy format, please update it!\n", name);
} }
Game::XModel* asset = reader.readObject<Game::XModel>(); Game::XModel* asset = reader.readObject<Game::XModel>();
@ -310,7 +311,7 @@ namespace Assets
if (!reader.end()) if (!reader.end())
{ {
Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading model '{}' failed, remaining raw data found!", name);
} }
header->model = asset; header->model = asset;

View File

@ -5,14 +5,14 @@ namespace Assets
class IXModel : public Components::AssetHandler::IAsset class IXModel : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XMODEL; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XMODEL; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private: private:
std::map<void*, void*> triIndicies; std::map<void*, void*> triIndicies;
void loadXModelSurfs(Game::XModelSurfs* asset, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder); void loadXModelSurfs(Game::XModelSurfs* asset, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder);
void loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder); void loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder);
void loadXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Utils::Stream::Reader* reader); void loadXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Utils::Stream::Reader* reader);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IXModelSurfs.hpp"
namespace Assets namespace Assets
{ {
@ -81,16 +82,16 @@ namespace Assets
// Access index block // Access index block
buffer->pushBlock(Game::XFILE_BLOCK_INDEX); buffer->pushBlock(Game::XFILE_BLOCK_INDEX);
if (builder->hasPointer(surf->triIndices)) if (builder->hasPointer(surf->triIndices))
{ {
destSurf->triIndices = builder->getPointer(surf->triIndices); destSurf->triIndices = builder->getPointer(surf->triIndices);
} }
else else
{ {
buffer->align(Utils::Stream::ALIGN_16); buffer->align(Utils::Stream::ALIGN_16);
buffer->saveArray(surf->triIndices, surf->triCount * 3); buffer->saveArray(surf->triIndices, surf->triCount * 3);
Utils::Stream::ClearPointer(&destSurf->triIndices); Utils::Stream::ClearPointer(&destSurf->triIndices);
} }
buffer->popBlock(); buffer->popBlock();
} }

View File

@ -5,9 +5,9 @@ namespace Assets
class IXModelSurfs : public Components::AssetHandler::IAsset class IXModelSurfs : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XMODEL_SURFS; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XMODEL_SURFS; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private: private:
void saveXSurface(Game::XSurface* surf, Game::XSurface* destSurf, Components::ZoneBuilder::Zone* builder); void saveXSurface(Game::XSurface* surf, Game::XSurface* destSurf, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "IclipMap_t.hpp"
#define IW4X_CLIPMAP_VERSION 2 #define IW4X_CLIPMAP_VERSION 2
@ -601,13 +602,13 @@ namespace Assets
__int64 magic = reader.read<__int64>(); __int64 magic = reader.read<__int64>();
if (std::memcmp(&magic, "IW4xClip", 8)) if (std::memcmp(&magic, "IW4xClip", 8))
{ {
Components::Logger::Error(0, "Reading clipMap_t '%s' failed, header is invalid!", name.data()); Components::Logger::Error(Game::ERR_FATAL, "Reading clipMap_t '{}' failed, header is invalid!", name);
} }
int version = reader.read<int>(); int version = reader.read<int>();
if (version > IW4X_CLIPMAP_VERSION) if (version > IW4X_CLIPMAP_VERSION)
{ {
Components::Logger::Error(0, "Reading clipmap '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_CLIPMAP_VERSION, version); Components::Logger::Error(Game::ERR_FATAL, "Reading clipmap '{}' failed, expected version is {}, but it was {}!", name, IW4X_CLIPMAP_VERSION, version);
} }
clipMap->name = reader.readCString(); clipMap->name = reader.readCString();
@ -682,7 +683,7 @@ namespace Assets
int planeIndex = reader.read<int>(); int planeIndex = reader.read<int>();
if (planeIndex < 0 || planeIndex >= clipMap->planeCount) if (planeIndex < 0 || planeIndex >= clipMap->planeCount)
{ {
Components::Logger::Error("invalid plane index"); Components::Logger::Error(Game::ERR_FATAL, "invalid plane index");
return; return;
} }
clipMap->brushsides[i].plane = &clipMap->planes[planeIndex]; clipMap->brushsides[i].plane = &clipMap->planes[planeIndex];
@ -705,7 +706,7 @@ namespace Assets
int planeIndex = reader.read<int>(); int planeIndex = reader.read<int>();
if (planeIndex < 0 || planeIndex >= clipMap->planeCount) if (planeIndex < 0 || planeIndex >= clipMap->planeCount)
{ {
Components::Logger::Error("invalid plane index\n"); Components::Logger::Error(Game::ERR_FATAL, "invalid plane index\n");
return; return;
} }
clipMap->nodes[i].plane = &clipMap->planes[planeIndex]; clipMap->nodes[i].plane = &clipMap->planes[planeIndex];
@ -773,7 +774,7 @@ namespace Assets
int index = reader.read<int>(); int index = reader.read<int>();
if (index < 0 || index > clipMap->borderCount) if (index < 0 || index > clipMap->borderCount)
{ {
Components::Logger::Error("invalid border index\n"); Components::Logger::Error(Game::ERR_FATAL, "invalid border index\n");
return; return;
} }
clipMap->partitions[i].borders = &clipMap->borders[index]; clipMap->partitions[i].borders = &clipMap->borders[index];
@ -800,10 +801,10 @@ namespace Assets
clipMap->brushes[i].numsides = reader.read<unsigned int>() & 0xFFFF; // todo: check for overflow here clipMap->brushes[i].numsides = reader.read<unsigned int>() & 0xFFFF; // todo: check for overflow here
if (clipMap->brushes[i].numsides > 0) if (clipMap->brushes[i].numsides > 0)
{ {
unsigned int index = reader.read<unsigned int>(); auto index = reader.read<unsigned int>();
if (index < 0 || index > clipMap->numBrushSides) if (index < 0 || index > clipMap->numBrushSides)
{ {
Components::Logger::Error("invalid side index\n"); Components::Logger::Error(Game::ERR_FATAL, "invalid side index\n");
return; return;
} }
clipMap->brushes[i].sides = &clipMap->brushsides[index]; clipMap->brushes[i].sides = &clipMap->brushsides[index];
@ -813,10 +814,10 @@ namespace Assets
clipMap->brushes[i].sides = nullptr; clipMap->brushes[i].sides = nullptr;
} }
unsigned int index = reader.read<unsigned int>(); auto index = reader.read<unsigned int>();
if (index > clipMap->numBrushEdges) if (index > clipMap->numBrushEdges)
{ {
Components::Logger::Error("invalid edge index\n"); Components::Logger::Error(Game::ERR_FATAL, "invalid edge index\n");
return; return;
} }
clipMap->brushes[i].baseAdjacentSide = &clipMap->brushEdges[index]; clipMap->brushes[i].baseAdjacentSide = &clipMap->brushEdges[index];
@ -935,7 +936,7 @@ namespace Assets
if (!reader.end()) if (!reader.end())
{ {
Components::Logger::Error("Clipmap data left!"); Components::Logger::Error(Game::ERR_FATAL, "Clipmap data left!");
} }
header->clipMap = clipMap; header->clipMap = clipMap;

View File

@ -5,11 +5,11 @@ namespace Assets
class IclipMap_t : public Components::AssetHandler::IAsset class IclipMap_t : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_CLIPMAP_MP; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_CLIPMAP_MP; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private: private:
class SModelQuadtree class SModelQuadtree

View File

@ -1,20 +1,21 @@
#include <StdInclude.hpp> #include <STDInclude.hpp>
#include "ImenuDef_t.hpp"
namespace Assets namespace Assets
{ {
std::unordered_map<std::string, Game::menuDef_t*> ImenuDef_t::LoadedMenus; std::unordered_map<std::string, Game::menuDef_t*> ImenuDef_t::LoadedMenus;
void ImenuDef_t::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) void ImenuDef_t::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{ {
// load from disk // load from disk
auto menus = Components::Menus::LoadMenu(Utils::String::VA("ui_mp/%s.menu", name.data())); auto menus = Components::Menus::LoadMenu(Utils::String::VA("ui_mp/%s.menu", name.data()));
if (menus.size() == 0) return; if (menus.size() == 0) return;
if (menus.size() > 1) Components::Logger::Print("Menu '%s' on disk has more than one menudef in it. Only saving the first one\n", name.data()); if (menus.size() > 1) Components::Logger::Print("Menu '{}' on disk has more than one menudef in it. Only saving the first one\n", name);
header->menu = menus[0].second; header->menu = menus[0].second;
} }
void ImenuDef_t::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void ImenuDef_t::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
@ -53,7 +54,7 @@ namespace Assets
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("ExpressionSupportingData"); buffer->enterStruct("ExpressionSupportingData");
#endif #endif
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
@ -127,18 +128,18 @@ namespace Assets
} }
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
void ImenuDef_t::save_Statement_s(Game::Statement_s* asset, Components::ZoneBuilder::Zone* builder) void ImenuDef_t::save_Statement_s(Game::Statement_s* asset, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::Statement_s, 24); AssertSize(Game::Statement_s, 24);
AssertSize(Game::expressionEntry, 12); AssertSize(Game::expressionEntry, 12);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("Statement_s"); buffer->enterStruct("Statement_s");
#endif #endif
// Write header data // Write header data
@ -149,7 +150,7 @@ namespace Assets
if (asset->entries) if (asset->entries)
{ {
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("statement entries"); buffer->enterStruct("statement entries");
#endif #endif
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
@ -161,7 +162,7 @@ namespace Assets
for (int i = 0; i < asset->numEntries; ++i) for (int i = 0; i < asset->numEntries; ++i)
{ {
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("entry"); buffer->enterStruct("entry");
#endif #endif
if (asset->entries[i].type) if (asset->entries[i].type)
{ {
@ -193,11 +194,11 @@ namespace Assets
} }
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
@ -207,7 +208,7 @@ namespace Assets
Utils::Stream::ClearPointer(&dest->supportingData); Utils::Stream::ClearPointer(&dest->supportingData);
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
@ -217,7 +218,7 @@ namespace Assets
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("MenuEventHandlerSet"); buffer->enterStruct("MenuEventHandlerSet");
#endif #endif
// Write header data // Write header data
@ -239,7 +240,7 @@ namespace Assets
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("MenuEventHandler"); buffer->enterStruct("MenuEventHandler");
#endif #endif
// Write menu event handler // Write menu event handler
@ -329,7 +330,7 @@ namespace Assets
break; break;
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
} }
@ -337,7 +338,7 @@ namespace Assets
Utils::Stream::ClearPointer(&destset->eventHandlers); Utils::Stream::ClearPointer(&destset->eventHandlers);
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
@ -347,7 +348,7 @@ namespace Assets
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("ItemKeyHandler"); buffer->enterStruct("ItemKeyHandler");
#endif #endif
while (asset) while (asset)
@ -374,7 +375,7 @@ namespace Assets
asset = asset->next; asset = asset->next;
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
@ -404,7 +405,7 @@ namespace Assets
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("itemDefData_t"); buffer->enterStruct("itemDefData_t");
#endif #endif
// feeder // feeder
@ -490,7 +491,7 @@ namespace Assets
Utils::Stream::ClearPointer(&dest->typeData.data); Utils::Stream::ClearPointer(&dest->typeData.data);
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
@ -502,12 +503,12 @@ namespace Assets
Game::itemDef_s* dest = buffer->dest<Game::itemDef_s>(); Game::itemDef_s* dest = buffer->dest<Game::itemDef_s>();
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
if (asset->window.name) if (asset->window.name)
buffer->enterStruct(Utils::String::VA("itemDef_s: name = '%s'", asset->window.name)); buffer->enterStruct(Utils::String::VA("itemDef_s: name = '%s'", asset->window.name));
else if (asset->window.background) else if (asset->window.background)
buffer->enterStruct(Utils::String::VA("itemDef_s: bg = '%s'", asset->window.background->info.name)); buffer->enterStruct(Utils::String::VA("itemDef_s: bg = '%s'", asset->window.background->info.name));
else else
buffer->enterStruct("itemDef_s"); buffer->enterStruct("itemDef_s");
#endif #endif
buffer->save(asset); buffer->save(asset);
@ -583,7 +584,7 @@ namespace Assets
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("floatExpressions"); buffer->enterStruct("floatExpressions");
#endif #endif
Game::ItemFloatExpression* destExp = buffer->dest<Game::ItemFloatExpression>(); Game::ItemFloatExpression* destExp = buffer->dest<Game::ItemFloatExpression>();
@ -599,7 +600,7 @@ namespace Assets
Utils::Stream::ClearPointer(&dest->floatExpressions); Utils::Stream::ClearPointer(&dest->floatExpressions);
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
@ -610,7 +611,7 @@ namespace Assets
STATEMENT(materialExp); STATEMENT(materialExp);
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
} }
@ -619,7 +620,7 @@ namespace Assets
AssertSize(Game::menuDef_t, 400); AssertSize(Game::menuDef_t, 400);
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->enterStruct("ImenuDef_t"); buffer->enterStruct("ImenuDef_t");
#endif #endif
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
@ -700,7 +701,7 @@ namespace Assets
} }
} }
#ifdef WRITE_LOGS #ifdef WRITE_LOGS
buffer->leaveStruct(); buffer->leaveStruct();
#endif #endif
buffer->popBlock(); buffer->popBlock();

View File

@ -5,13 +5,13 @@ namespace Assets
class ImenuDef_t : public Components::AssetHandler::IAsset class ImenuDef_t : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MENU; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MENU; }
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
static std::unordered_map<std::string, Game::menuDef_t*> LoadedMenus; static std::unordered_map<std::string, Game::menuDef_t*> LoadedMenus;
private: private:
template <typename T> void save_windowDef_t(Game::windowDef_t* asset, T* dest, Components::ZoneBuilder::Zone* builder) template <typename T> void save_windowDef_t(Game::windowDef_t* asset, T* dest, Components::ZoneBuilder::Zone* builder)

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "Isnd_alias_list_t.hpp"
namespace Assets namespace Assets
{ {
@ -42,7 +43,7 @@ namespace Assets
if (!infoData.is_object()) if (!infoData.is_object())
{ {
Components::Logger::Error("Failed to load sound %s!", name.c_str()); Components::Logger::Error(Game::ERR_FATAL, "Failed to load sound {}!", name);
return; return;
} }
@ -86,14 +87,14 @@ namespace Assets
{ {
soundFile = head["soundfile"]; soundFile = head["soundfile"];
Components::Logger::Print("Fixed casing on %s\n", name.c_str()); Components::Logger::Print("Fixed casing on {}\n", name);
} }
if (type.is_null() || soundFile.is_null()) if (type.is_null() || soundFile.is_null())
{ {
Components::Logger::Print("Type is %s\n", type.dump().c_str()); Components::Logger::Print("Type is {}\n", type.dump());
Components::Logger::Print("SoundFile is %s\n", soundFile.dump().c_str()); Components::Logger::Print("SoundFile is {}\n", soundFile.dump());
Components::Logger::Error("Failed to parse sound %s! Each alias must have at least a type and a soundFile\n", name.c_str()); Components::Logger::Error(Game::ERR_FATAL, "Failed to parse sound {}! Each alias must have at least a type and a soundFile\n", name);
return; return;
} }
@ -102,102 +103,102 @@ namespace Assets
// TODO: actually support all of those properties // TODO: actually support all of those properties
if (!CHECK(type, number)) if (!CHECK(type, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "type", type.type(), type.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "type", Utils::Json::TypeToString(type.type()), type.dump());
} }
if (!CHECK(subtitle, string)) if (!CHECK(subtitle, string))
{ {
Components::Logger::Print("%s is not string but %d (%s)\n", "subtitle", subtitle.type(), subtitle.dump().c_str()); Components::Logger::Print("{} is not string but {} ({})\n", "subtitle", Utils::Json::TypeToString(subtitle.type()), subtitle.dump());
} }
if (!CHECK(aliasName, string)) if (!CHECK(aliasName, string))
{ {
Components::Logger::Print("%s is not string but %d (%s)\n", "aliasName", aliasName.type(), aliasName.dump().c_str()); Components::Logger::Print("{} is not string but {} ({})\n", "aliasName", Utils::Json::TypeToString(aliasName.type()), aliasName.dump());
} }
if (!CHECK(secondaryAliasName, string)) if (!CHECK(secondaryAliasName, string))
{ {
Components::Logger::Print("%s is not string but %d (%s)\n", "secondaryAliasName", secondaryAliasName.type(), secondaryAliasName.dump().c_str()); Components::Logger::Print("{} is not string but {} ({})\n", "secondaryAliasName", Utils::Json::TypeToString(secondaryAliasName.type()), secondaryAliasName.dump());
} }
if (!CHECK(chainAliasName, string)) if (!CHECK(chainAliasName, string))
{ {
Components::Logger::Print("%s is not string but %d (%s)\n", "chainAliasName", chainAliasName.type(), chainAliasName.dump().c_str()); Components::Logger::Print("{} is not string but {} ({})\n", "chainAliasName", Utils::Json::TypeToString(chainAliasName.type()), chainAliasName.dump());
} }
if (!CHECK(soundFile, string)) if (!CHECK(soundFile, string))
{ {
Components::Logger::Print("%s is not string but %d (%s)\n", "soundFile", soundFile.type(), soundFile.dump().c_str()); Components::Logger::Print("{} is not string but {} ({})\n", "soundFile", Utils::Json::TypeToString(soundFile.type()), soundFile.dump());
} }
if (!CHECK(sequence, number)) if (!CHECK(sequence, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "sequence", sequence.type(), sequence.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "sequence", Utils::Json::TypeToString(sequence.type()), sequence.dump());
} }
if (!CHECK(volMin, number)) if (!CHECK(volMin, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "volMin", volMin.type(), volMin.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "volMin", Utils::Json::TypeToString(volMin.type()), volMin.dump());
} }
if (!CHECK(volMax, number)) if (!CHECK(volMax, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "volMax", volMax.type(), volMax.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "volMax", Utils::Json::TypeToString(volMax.type()), volMax.dump());
} }
if (!CHECK(pitchMin, number)) if (!CHECK(pitchMin, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "pitchMin", pitchMin.type(), pitchMin.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "pitchMin", Utils::Json::TypeToString(pitchMin.type()), pitchMin.dump());
} }
if (!CHECK(pitchMax, number)) if (!CHECK(pitchMax, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "pitchMax", pitchMax.type(), pitchMax.dump().c_str()); Components::Logger::Print("{} is not number but {} ()\n", "pitchMax", Utils::Json::TypeToString(pitchMax.type()), pitchMax.dump());
} }
if (!CHECK(probability, number)) if (!CHECK(probability, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "probability", probability.type(), probability.dump().c_str()); Components::Logger::Print("{} is not number but {} ({}))\n", "probability", Utils::Json::TypeToString(probability.type()), probability.dump());
} }
if (!CHECK(lfePercentage, number)) if (!CHECK(lfePercentage, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "lfePercentage", lfePercentage.type(), lfePercentage.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "lfePercentage", Utils::Json::TypeToString(lfePercentage.type()), lfePercentage.dump());
} }
if (!CHECK(centerPercentage, number)) if (!CHECK(centerPercentage, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "centerPercentage", centerPercentage.type(), centerPercentage.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "centerPercentage", Utils::Json::TypeToString(centerPercentage.type()), centerPercentage.dump());
} }
if (!CHECK(startDelay, number)) if (!CHECK(startDelay, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "startDelay", startDelay.type(), startDelay.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "startDelay", Utils::Json::TypeToString(startDelay.type()), startDelay.dump());
} }
if (!CHECK(volumeFalloffCurve, string)) if (!CHECK(volumeFalloffCurve, string))
{ {
Components::Logger::Print("%s is not string but %d (%s)\n", "volumeFalloffCurve", volumeFalloffCurve.type(), volumeFalloffCurve.dump().c_str()); Components::Logger::Print("{}s is not string but {} ({})\n", "volumeFalloffCurve", Utils::Json::TypeToString(volumeFalloffCurve.type()), volumeFalloffCurve.dump());
} }
if (!CHECK(envelopMin, number)) if (!CHECK(envelopMin, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "envelopMin", envelopMin.type(), envelopMin.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "envelopMin", Utils::Json::TypeToString(envelopMin.type()), envelopMin.dump());
} }
if (!CHECK(envelopMax, number)) if (!CHECK(envelopMax, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "envelopMax", envelopMax.type(), envelopMax.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "envelopMax", Utils::Json::TypeToString(envelopMax.type()), envelopMax.dump());
} }
if (!CHECK(envelopPercentage, number)) if (!CHECK(envelopPercentage, number))
{ {
Components::Logger::Print("%s is not number but %d (%s)\n", "envelopPercentage", envelopPercentage.type(), envelopPercentage.dump().c_str()); Components::Logger::Print("{} is not number but {} ({})\n", "envelopPercentage", Utils::Json::TypeToString(envelopPercentage.type()), envelopPercentage.dump());
} }
if (!CHECK(speakerMap, object)) if (!CHECK(speakerMap, object))
{ {
Components::Logger::Print("%s is not object but %d (%s)\n", "speakerMap", speakerMap.type(), speakerMap.dump().c_str()); Components::Logger::Print("{} is not object but {} ({})\n", "speakerMap", Utils::Json::TypeToString(speakerMap.type()), speakerMap.dump());
} }
@ -248,7 +249,7 @@ namespace Assets
alias->speakerMap = builder->getAllocator()->allocate<Game::SpeakerMap>(); alias->speakerMap = builder->getAllocator()->allocate<Game::SpeakerMap>();
if (!alias->speakerMap) if (!alias->speakerMap)
{ {
Components::Logger::Print("Error allocating memory for speakermap in sound alias%s!\n", alias->aliasName); Components::Logger::Print("Error allocating memory for speakermap in sound alias{}!\n", alias->aliasName);
return; return;
} }
@ -328,7 +329,7 @@ namespace Assets
} }
else else
{ {
Components::Logger::Error("Failed to parse sound %s! Invalid sound type %s\n", name.c_str(), type.string_value().c_str()); Components::Logger::Error(Game::ERR_FATAL, "Failed to parse sound {}! Invalid sound type {}\n", name, type.string_value());
return; return;
} }
@ -336,7 +337,7 @@ namespace Assets
} }
else else
{ {
Components::Logger::Error("Failed to parse sound %s!\n", name.c_str()); Components::Logger::Error(Game::ERR_FATAL, "Failed to parse sound {}!\n", name);
return; return;
} }
} }

View File

@ -5,10 +5,10 @@ namespace Assets
class Isnd_alias_list_t : public Components::AssetHandler::IAsset class Isnd_alias_list_t : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND; }; Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND; }
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
}; };
} }

View File

@ -41,7 +41,7 @@ namespace Components
Auth::TokenContainer.generating = false; Auth::TokenContainer.generating = false;
Auth::StoreKey(); Auth::StoreKey();
Logger::Print("Security level is %d\n", Auth::GetSecurityLevel()); Logger::Debug("Security level is {}", Auth::GetSecurityLevel());
Command::Execute("closemenu security_increase_popmenu", false); Command::Execute("closemenu security_increase_popmenu", false);
if (!Auth::TokenContainer.cancel) if (!Auth::TokenContainer.cancel)
@ -67,14 +67,14 @@ namespace Components
Steam::SteamUser()->GetSteamID(); Steam::SteamUser()->GetSteamID();
if (!Auth::GuidKey.isValid()) if (!Auth::GuidKey.isValid())
{ {
Logger::SoftError("Connecting failed: Guid key is invalid!"); Logger::Error(Game::ERR_SERVERDISCONNECT, "Connecting failed: Guid key is invalid!");
return; return;
} }
if (std::find(Auth::BannedUids.begin(), Auth::BannedUids.end(), Steam::SteamUser()->GetSteamID().bits) != Auth::BannedUids.end()) if (std::find(Auth::BannedUids.begin(), Auth::BannedUids.end(), Steam::SteamUser()->GetSteamID().bits) != Auth::BannedUids.end())
{ {
Auth::GenerateKey(); Auth::GenerateKey();
Logger::SoftError("Your online profile is invalid. A new key has been generated."); Logger::Error(Game::ERR_SERVERDISCONNECT, "Your online profile is invalid. A new key has been generated.");
return; return;
} }
@ -86,7 +86,7 @@ namespace Components
if (params.size() < 3) if (params.size() < 3)
{ {
Game::SV_Cmd_EndTokenizedString(); Game::SV_Cmd_EndTokenizedString();
Logger::SoftError("Connecting failed: Command parsing error!"); Logger::Error(Game::ERR_SERVERDISCONNECT, "Connecting failed: Command parsing error!");
return; return;
} }
@ -96,7 +96,7 @@ namespace Components
if (challenge.empty()) if (challenge.empty())
{ {
Game::SV_Cmd_EndTokenizedString(); Game::SV_Cmd_EndTokenizedString();
Logger::SoftError("Connecting failed: Challenge parsing error!"); Logger::Error(Game::ERR_SERVERDISCONNECT, "Connecting failed: Challenge parsing error!");
return; return;
} }
@ -233,7 +233,7 @@ namespace Components
return; return;
} }
Logger::Print("Verified XUID %llX (%d) from %s\n", xuid, userLevel, address.getCString()); Logger::Debug("Verified XUID {:#X} ({}) from {}", xuid, userLevel, address.getCString());
Game::SV_DirectConnect(*address.get()); Game::SV_DirectConnect(*address.get());
} }
#endif #endif
@ -429,7 +429,7 @@ namespace Components
Auth::LoadKey(true); Auth::LoadKey(true);
Steam::SteamUser()->GetSteamID(); Steam::SteamUser()->GetSteamID();
Scheduler::OnFrame(Auth::Frame); Scheduler::Loop(Auth::Frame, Scheduler::Pipeline::MAIN);
// Register dvar // Register dvar
Dvar::Register<int>("sv_securityLevel", 23, 0, 512, Game::dvar_flag::DVAR_SERVERINFO, "Security level for GUID certificates (POW)"); Dvar::Register<int>("sv_securityLevel", 23, 0, 512, Game::dvar_flag::DVAR_SERVERINFO, "Security level for GUID certificates (POW)");
@ -448,7 +448,7 @@ namespace Components
// Guid command // Guid command
Command::Add("guid", [](Command::Params*) Command::Add("guid", [](Command::Params*)
{ {
Logger::Print("Your guid: %llX\n", Steam::SteamUser()->GetSteamID().bits); Logger::Print("Your guid: {:#X}\n", Steam::SteamUser()->GetSteamID().bits);
}); });
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled()) if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
@ -457,16 +457,16 @@ namespace Components
{ {
if (params->size() < 2) if (params->size() < 2)
{ {
uint32_t level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.getPublicKey()); const auto level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.getPublicKey());
Logger::Print("Your current security level is %d\n", level); Logger::Print("Your current security level is {}\n", level);
Logger::Print("Your security token is: %s\n", Utils::String::DumpHex(Auth::GuidToken.toString(), "").data()); Logger::Print("Your security token is: {}\n", Utils::String::DumpHex(Auth::GuidToken.toString(), ""));
Logger::Print("Your computation token is: %s\n", Utils::String::DumpHex(Auth::ComputeToken.toString(), "").data()); Logger::Print("Your computation token is: {}\n", Utils::String::DumpHex(Auth::ComputeToken.toString(), ""));
Toast::Show("cardicon_locked", "^5Security Level", Utils::String::VA("Your security level is %d", level), 3000); Toast::Show("cardicon_locked", "^5Security Level", Utils::String::VA("Your security level is %d", level), 3000);
} }
else else
{ {
uint32_t level = static_cast<uint32_t>(atoi(params->get(1))); const auto level = static_cast<uint32_t>(atoi(params->get(1)));
Auth::IncreaseSecurityLevel(level); Auth::IncreaseSecurityLevel(level);
} }
}); });

View File

@ -13,7 +13,7 @@ namespace Components
if (entry.first.bits) if (entry.first.bits)
{ {
for (auto& idEntry : list.idList) for (const auto& idEntry : list.idList)
{ {
if (idEntry.bits == entry.first.bits) if (idEntry.bits == entry.first.bits)
{ {
@ -89,21 +89,21 @@ namespace Components
std::vector<std::string> idVector; std::vector<std::string> idVector;
std::vector<std::string> ipVector; std::vector<std::string> ipVector;
for (auto& idEntry : list->idList) for (const auto& idEntry : list->idList)
{ {
idVector.push_back(Utils::String::VA("%llX", idEntry.bits)); idVector.emplace_back(Utils::String::VA("%llX", idEntry.bits));
} }
for (auto& ipEntry : list->ipList) for (const auto& ipEntry : list->ipList)
{ {
ipVector.push_back(Utils::String::VA("%u.%u.%u.%u", ipVector.emplace_back(Utils::String::VA("%u.%u.%u.%u",
ipEntry.bytes[0] & 0xFF, ipEntry.bytes[0] & 0xFF,
ipEntry.bytes[1] & 0xFF, ipEntry.bytes[1] & 0xFF,
ipEntry.bytes[2] & 0xFF, ipEntry.bytes[2] & 0xFF,
ipEntry.bytes[3] & 0xFF)); ipEntry.bytes[3] & 0xFF));
} }
json11::Json bans = json11::Json::object const json11::Json bans = json11::Json::object
{ {
{ "ip", ipVector }, { "ip", ipVector },
{ "id", idVector }, { "id", idVector },
@ -126,7 +126,7 @@ namespace Components
if (!error.empty()) if (!error.empty())
{ {
Logger::Error("Failed to parse bans (bans.json): %s", error.data()); Logger::Error(Game::ERR_FATAL, "Failed to parse bans (bans.json): {}", error);
} }
if (!list) return; if (!list) return;
@ -176,7 +176,7 @@ namespace Components
if (*Game::svs_clientCount <= num) if (*Game::svs_clientCount <= num)
{ {
Logger::Print("Player %d is not on the server\n", num); Logger::Print("Player {} is not on the server\n", num);
return; return;
} }
@ -253,7 +253,7 @@ namespace Components
Network::Address address(params->get(2)); Network::Address address(params->get(2));
Bans::UnbanClient(address.getIP()); Bans::UnbanClient(address.getIP());
Logger::Print("Unbanned IP %s\n", params->get(2)); Logger::Print("Unbanned IP {}\n", params->get(2));
} }
else if (type == "guid"s) else if (type == "guid"s)
@ -263,15 +263,15 @@ namespace Components
Bans::UnbanClient(id); Bans::UnbanClient(id);
Logger::Print("Unbanned GUID %s\n", params->get(2)); Logger::Print("Unbanned GUID {}\n", params->get(2));
} }
}); });
// Verify the list on startup // Verify the list on startup
Scheduler::Once([]() Scheduler::OnGameInitialized([]
{ {
Bans::BanList list; Bans::BanList list;
Bans::LoadBans(&list); Bans::LoadBans(&list);
}); }, Scheduler::Pipeline::SERVER);
} }
} }

View File

@ -83,28 +83,30 @@ namespace Components
void Bots::Spawn(unsigned int count) void Bots::Spawn(unsigned int count)
{ {
for (auto i = 0u; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
{ {
Scheduler::OnDelay([]() Scheduler::Once([]
{ {
auto* ent = Game::SV_AddTestClient(); auto* ent = Game::SV_AddTestClient();
if (ent == nullptr) if (ent == nullptr)
return; return;
Scheduler::OnDelay([ent]() Scheduler::Once([ent]
{ {
Game::Scr_AddString("autoassign"); Game::Scr_AddString("autoassign");
Game::Scr_AddString("team_marinesopfor"); Game::Scr_AddString("team_marinesopfor");
Game::Scr_Notify(ent, Game::SL_GetString("menuresponse", 0), 2); Game::Scr_Notify(ent, Game::SL_GetString("menuresponse", 0), 2);
Scheduler::OnDelay([ent]() Scheduler::Once([ent]
{ {
Game::Scr_AddString(Utils::String::VA("class%u", Utils::Cryptography::Rand::GenerateInt() % 5u)); Game::Scr_AddString(Utils::String::VA("class%u", Utils::Cryptography::Rand::GenerateInt() % 5u));
Game::Scr_AddString("changeclass"); Game::Scr_AddString("changeclass");
Game::Scr_Notify(ent, Game::SL_GetString("menuresponse", 0), 2); Game::Scr_Notify(ent, Game::SL_GetString("menuresponse", 0), 2);
}, 1s); }, Scheduler::Pipeline::SERVER, 1s);
}, 1s);
}, 500ms * (i + 1)); }, Scheduler::Pipeline::SERVER, 1s);
}, Scheduler::Pipeline::SERVER, 500ms * (i + 1));
} }
} }
@ -307,18 +309,6 @@ namespace Components
} }
} }
/*
* Should be called when a client drops from the server
* but not "between levels" (Quake-III-Arena)
*/
void Bots::ClientDisconnect_Hk(int clientNum)
{
g_botai[clientNum].active = false;
// Call original function
Utils::Hook::Call<void(int)>(0x4AA430)(clientNum);
}
Bots::Bots() Bots::Bots()
{ {
AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); AssertOffset(Game::client_s, bIsTestClient, 0x41AF0);
@ -335,7 +325,10 @@ namespace Components
Utils::Hook(0x441B80, Bots::G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick(); Utils::Hook(0x441B80, Bots::G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick();
// Reset BotMovementInfo.active when client is dropped // Reset BotMovementInfo.active when client is dropped
Utils::Hook(0x625235, Bots::ClientDisconnect_Hk, HOOK_CALL).install()->quick(); Events::OnClientDisconnect([](const int clientNum)
{
g_botai[clientNum].active = false;
});
// Zero the bot command array // Zero the bot command array
for (auto i = 0u; i < std::extent_v<decltype(g_botai)>; i++) for (auto i = 0u; i < std::extent_v<decltype(g_botai)>; i++)
@ -362,8 +355,7 @@ namespace Components
if (input == end) if (input == end)
{ {
Logger::Print("Warning: %s is not a valid input\n" Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "{} is not a valid input\nUsage: {} optional <number of bots> or optional <\"all\">\n",
"Usage: %s optional <number of bots> or optional <\"all\">\n",
input, params->get(0)); input, params->get(0));
return; return;
} }
@ -381,7 +373,7 @@ namespace Components
} }
Toast::Show("cardicon_headshot", "^2Success", Utils::String::VA("Spawning %d %s...", count, (count == 1 ? "bot" : "bots")), 3000); Toast::Show("cardicon_headshot", "^2Success", Utils::String::VA("Spawning %d %s...", count, (count == 1 ? "bot" : "bots")), 3000);
Logger::Print("Spawning %d %s...\n", count, (count == 1 ? "bot" : "bots")); Logger::Debug("Spawning {} {}", count, (count == 1 ? "bot" : "bots"));
Bots::Spawn(count); Bots::Spawn(count);
}); });
@ -389,9 +381,9 @@ namespace Components
Bots::AddMethods(); Bots::AddMethods();
// In case a loaded mod didn't call "BotStop" before the VM shutdown // In case a loaded mod didn't call "BotStop" before the VM shutdown
Script::OnVMShutdown([] Events::OnVMShutdown([]
{ {
for (auto i = 0u; i < std::extent_v<decltype(g_botai)>; i++) for (std::size_t i = 0; i < std::extent_v<decltype(g_botai)>; i++)
{ {
g_botai[i].active = false; g_botai[i].active = false;
} }

View File

@ -22,7 +22,5 @@ namespace Components
static void G_SelectWeaponIndex(int clientNum, int iWeaponIndex); static void G_SelectWeaponIndex(int clientNum, int iWeaponIndex);
static void G_SelectWeaponIndex_Hk(); static void G_SelectWeaponIndex_Hk();
static void ClientDisconnect_Hk(int clientNum);
}; };
} }

View File

@ -7,6 +7,12 @@ namespace Components
Dvar::Var Branding::CGDrawVersionY; Dvar::Var Branding::CGDrawVersionY;
Game::dvar_t** Branding::Version = reinterpret_cast<Game::dvar_t**>(0x1AD7930); Game::dvar_t** Branding::Version = reinterpret_cast<Game::dvar_t**>(0x1AD7930);
#ifdef _DEBUG
constexpr auto* BUILD_TYPE = "IW4x_DEV MP";
#else
constexpr auto* BUILD_TYPE = "IW4x MP";
#endif
void Branding::CG_DrawVersion() void Branding::CG_DrawVersion()
{ {
// Default values // Default values
@ -45,15 +51,9 @@ namespace Components
const char* Branding::GetVersionString() const char* Branding::GetVersionString()
{ {
#ifdef _DEBUG
const auto* buildType = "IW4x_DEV MP";
#else
const auto* buildType = "IW4x MP";
#endif
// IW4x is technically a beta // IW4x is technically a beta
const auto* result = Utils::String::VA("%s %s build %s %s", const auto* result = Utils::String::VA("%s %s build %s %s",
buildType, "(Beta)", Branding::GetBuildNumber(), reinterpret_cast<const char*>(0x7170A0)); BUILD_TYPE, "(Beta)", Branding::GetBuildNumber(), reinterpret_cast<const char*>(0x7170A0));
return result; return result;
} }
@ -75,7 +75,7 @@ namespace Components
[[maybe_unused]] float y, float min, float max, [[maybe_unused]] int flags, const char* description) [[maybe_unused]] float y, float min, float max, [[maybe_unused]] int flags, const char* description)
{ {
return Game::Dvar_RegisterVec2(dvarName, -60.0f, return Game::Dvar_RegisterVec2(dvarName, -60.0f,
474.0f, min, max, Game::dvar_flag::DVAR_READONLY, description); 474.0f, min, max, Game::dvar_flag::DVAR_ROM, description);
} }
void Branding::RegisterBrandingDvars() void Branding::RegisterBrandingDvars()
@ -95,7 +95,7 @@ namespace Components
Branding::Branding() Branding::Branding()
{ {
Dvar::OnInit(Branding::RegisterBrandingDvars); Branding::RegisterBrandingDvars();
// UI version string // UI version string
Utils::Hook::Set<const char*>(0x43F73B, "IW4x: " VERSION); Utils::Hook::Set<const char*>(0x43F73B, "IW4x: " VERSION);
@ -103,6 +103,14 @@ namespace Components
// Short version dvar // Short version dvar
Utils::Hook::Set<const char*>(0x60BD91, SHORTVERSION); Utils::Hook::Set<const char*>(0x60BD91, SHORTVERSION);
// Com_Init_Try_Block_Function
Utils::Hook::Set<const char*>(0x60BAF4, BUILD_TYPE);
Utils::Hook::Set<const char*>(0x60BAEf, SHORTVERSION);
Utils::Hook::Set<const char*>(0x60BAE5, __DATE__);
// G_InitGame
Utils::Hook::Set<const char*>(0x48EBA1, __DATE__);
Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick(); Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick();
// Version string color // Version string color

View File

@ -44,15 +44,12 @@ namespace Components
Bullet::Bullet() Bullet::Bullet()
{ {
Dvar::OnInit([] BGSurfacePenetration = Dvar::Register<float>("bg_surfacePenetration", 0.0f,
{ 0.0f, std::numeric_limits<float>::max(), Game::dvar_flag::DVAR_CODINFO,
BGSurfacePenetration = Dvar::Register<float>("bg_surfacePenetration", 0.0f, "Set to a value greater than 0 to override the surface penetration depth");
0.0f, std::numeric_limits<float>::max(), Game::dvar_flag::DVAR_CODINFO, BGBulletRange = Game::Dvar_RegisterFloat("bg_bulletRange", 8192.0f,
"Set to a value greater than 0 to override the surface penetration depth"); 0.0f, std::numeric_limits<float>::max(), Game::dvar_flag::DVAR_CODINFO,
BGBulletRange = Game::Dvar_RegisterFloat("bg_bulletRange", 8192.0f, "Max range used when calculating the bullet end position");
0.0f, std::numeric_limits<float>::max(), Game::dvar_flag::DVAR_CODINFO,
"Max range used when calculating the bullet end position");
});
Utils::Hook(0x4F6980, BG_GetSurfacePenetrationDepthStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x4F6980, BG_GetSurfacePenetrationDepthStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x440340, Bullet_FireStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x440340, Bullet_FireStub, HOOK_JUMP).install()->quick();

View File

@ -173,8 +173,8 @@ namespace Components
list.append(Utils::String::VA("\\%s\\%s", std::to_string(i).c_str(), playerTitle)); list.append(Utils::String::VA("\\%s\\%s", std::to_string(i).c_str(), playerTitle));
} }
std::string command = Utils::String::VA("%c customTitles \"%s\"", 21, list.data()); const auto* command = Utils::String::VA("%c customTitles \"%s\"", 21, list.data());
Game::SV_GameSendServerCommand(-1, 0, command.data()); Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, command);
} }
void CardTitles::ParseCustomTitles(const char* msg) void CardTitles::ParseCustomTitles(const char* msg)
@ -190,10 +190,10 @@ namespace Components
CardTitles::CardTitles() CardTitles::CardTitles()
{ {
Dvar::OnInit([]() Scheduler::Once([]
{ {
CardTitles::CustomTitleDvar = Dvar::Register<const char*>("customtitle", "", Game::dvar_flag::DVAR_USERINFO | Game::dvar_flag::DVAR_ARCHIVE, "Custom card title"); CardTitles::CustomTitleDvar = Dvar::Register<const char*>("customtitle", "", Game::dvar_flag::DVAR_USERINFO | Game::dvar_flag::DVAR_ARCHIVE, "Custom card title");
}); }, Scheduler::Pipeline::MAIN);
ServerCommands::OnCommand(21, [](Command::Params* params) ServerCommands::OnCommand(21, [](Command::Params* params)
{ {

View File

@ -0,0 +1,51 @@
#include <STDInclude.hpp>
namespace Components
{
Ceg::Ceg()
{
Utils::Hook::Signature signature(0x401000, 0x740000);
// Generic killer caller.
signature.add({
"\x56\x8B\x00\x24\x0c\x85\xF6\x7F\x0E", "xx?xxxxxx", [](char* address)
{
Utils::Hook::Set<BYTE>(address, 0xC3);
}
});
signature.process();
// Some more generic obfuscation (mov al, 1; retn)
Utils::Hook::Set<DWORD>(0x471B20, 0xC301B0);
Utils::Hook::Set<DWORD>(0x43A070, 0xC301B0);
Utils::Hook::Set<DWORD>(0x4C8B30, 0xC301B0);
Utils::Hook::Set<DWORD>(0x469340, 0xC301B0);
// Other checks
Utils::Hook::Set<DWORD>(0x401000, 0xC301B0);
Utils::Hook::Set<DWORD>(0x45F8B0, 0xC301B0);
Utils::Hook::Set<DWORD>(0x46FAE0, 0xC301B0);
// Removed in 159 SP binaries
Utils::Hook::Nop(0x46B173, 9);
Utils::Hook::Nop(0x43CA16, 9);
Utils::Hook::Nop(0x505426, 9);
// Disable some checks on certain game events
Utils::Hook::Nop(0x43EC96, 9);
Utils::Hook::Nop(0x4675C6, 9);
// Something useless that can be skipped
Utils::Hook::Nop(0x4BB671, 2);
Utils::Hook::Nop(0x40A54D, 2);
// Random checks scattered throughout the binary
Utils::Hook::Set<BYTE>(0x499F90, 0xC3);
Utils::Hook::Set<BYTE>(0x4FC700, 0xC3);
Utils::Hook::Set<BYTE>(0x4C4170, 0xC3);
Utils::Hook::Set<BYTE>(0x49E8C0, 0xC3);
Utils::Hook::Set<BYTE>(0x42DB00, 0xC3);
Utils::Hook::Set<BYTE>(0x4F4CF0, 0xC3);
}
}

View File

@ -0,0 +1,10 @@
#pragma once
namespace Components
{
class Ceg : public Component
{
public:
Ceg();
};
}

View File

@ -2,8 +2,10 @@
namespace Components namespace Components
{ {
Game::dvar_t** Chat::cg_chatHeight = reinterpret_cast<Game::dvar_t**>(0x7ED398);
Dvar::Var Chat::cg_chatWidth; Dvar::Var Chat::cg_chatWidth;
Dvar::Var Chat::sv_disableChat;
Game::dvar_t** Chat::cg_chatHeight = reinterpret_cast<Game::dvar_t**>(0x7ED398);
Game::dvar_t** Chat::cg_chatTime = reinterpret_cast<Game::dvar_t**>(0x9F5DE8); Game::dvar_t** Chat::cg_chatTime = reinterpret_cast<Game::dvar_t**>(0x9F5DE8);
bool Chat::SendChat; bool Chat::SendChat;
@ -11,23 +13,34 @@ namespace Components
std::mutex Chat::AccessMutex; std::mutex Chat::AccessMutex;
std::unordered_set<std::uint64_t> Chat::MuteList; std::unordered_set<std::uint64_t> Chat::MuteList;
const char* Chat::EvaluateSay(char* text, Game::gentity_t* player) bool Chat::CanAddCallback = true;
std::vector<Scripting::Function> Chat::SayCallbacks;
const char* Chat::EvaluateSay(char* text, Game::gentity_t* player, int mode)
{ {
Chat::SendChat = true; SendChat = true;
const auto _0 = gsl::finally([]
{
CanAddCallback = true;
});
// Prevent callbacks from adding a new callback (would make the vector iterator invalid)
CanAddCallback = false;
if (text[1] == '/') if (text[1] == '/')
{ {
Chat::SendChat = false; SendChat = false;
text[1] = text[0]; text[1] = text[0];
++text; ++text;
} }
std::unique_lock<std::mutex> lock(Chat::AccessMutex); std::unique_lock lock(AccessMutex);
if (Chat::MuteList.find(Game::svs_clients[player->s.number].steamID) != Chat::MuteList.end()) if (MuteList.contains(Game::svs_clients[player->s.number].steamID))
{ {
lock.unlock(); lock.unlock();
Chat::SendChat = false; SendChat = false;
Game::SV_GameSendServerCommand(player->s.number, 0, Game::SV_GameSendServerCommand(player->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"You are muted\"", 0x65)); Utils::String::VA("%c \"You are muted\"", 0x65));
} }
@ -37,6 +50,21 @@ namespace Components
lock.unlock(); lock.unlock();
} }
for (const auto& callback : SayCallbacks)
{
if (!ChatCallback(player, callback.getPos(), (text + 1), mode))
{
SendChat = false;
}
}
if (sv_disableChat.get<bool>())
{
SendChat = false;
Game::SV_GameSendServerCommand(player->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"Chat is disabled\"", 0x65));
}
TextRenderer::StripMaterialTextIcons(text, text, strlen(text) + 1); TextRenderer::StripMaterialTextIcons(text, text, strlen(text) + 1);
Game::Scr_AddEntity(player); Game::Scr_AddEntity(player);
@ -50,21 +78,22 @@ namespace Components
{ {
__asm __asm
{ {
mov eax, [esp + 100h + 10h] mov eax, [esp + 0x100 + 0x10]
push eax push eax
pushad pushad
push [esp + 100h + 28h] push [esp + 0x100 + 0x30] // mode
push eax push [esp + 0x100 + 0x2C] // player
call Chat::EvaluateSay push eax // text
add esp, 8h call EvaluateSay
add esp, 0xC
mov [esp + 20h], eax mov [esp + 0x20], eax
popad popad
pop eax pop eax
mov [esp + 100h + 10h], eax mov [esp + 0x100 + 0x10], eax
jmp PlayerName::CleanStrStub jmp PlayerName::CleanStrStub
} }
@ -78,7 +107,7 @@ namespace Components
push eax push eax
xor eax, eax xor eax, eax
mov al, Chat::SendChat mov al, SendChat
test al, al test al, al
jnz return jnz return
@ -215,42 +244,42 @@ namespace Components
void Chat::MuteClient(const Game::client_t* client) void Chat::MuteClient(const Game::client_t* client)
{ {
std::unique_lock<std::mutex> lock(Chat::AccessMutex); std::unique_lock lock(AccessMutex);
if (Chat::MuteList.find(client->steamID) == Chat::MuteList.end()) if (!MuteList.contains(client->steamID))
{ {
Chat::MuteList.insert(client->steamID); MuteList.insert(client->steamID);
lock.unlock(); lock.unlock();
Logger::Print("%s was muted\n", client->name); Logger::Print("{} was muted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, 0, Game::SV_GameSendServerCommand(client->gentity->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"You were muted\"", 0x65)); Utils::String::VA("%c \"You were muted\"", 0x65));
return; return;
} }
lock.unlock(); lock.unlock();
Logger::Print("%s is already muted\n", client->name); Logger::Print("{} is already muted\n", client->name);
Game::SV_GameSendServerCommand(-1, 0, Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"%s is already muted\"", 0x65, client->name)); Utils::String::VA("%c \"%s is already muted\"", 0x65, client->name));
} }
void Chat::UnmuteClient(const Game::client_t* client) void Chat::UnmuteClient(const Game::client_t* client)
{ {
Chat::UnmuteInternal(client->steamID); UnmuteInternal(client->steamID);
Logger::Print("%s was unmuted\n", client->name); Logger::Print("{} was unmuted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, 0, Game::SV_GameSendServerCommand(client->gentity->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"You were unmuted\"", 0x65)); Utils::String::VA("%c \"You were unmuted\"", 0x65));
} }
void Chat::UnmuteInternal(const std::uint64_t id, bool everyone) void Chat::UnmuteInternal(const std::uint64_t id, bool everyone)
{ {
std::unique_lock<std::mutex> lock(Chat::AccessMutex); std::unique_lock lock(AccessMutex);
if (everyone) if (everyone)
Chat::MuteList.clear(); MuteList.clear();
else else
Chat::MuteList.erase(id); MuteList.erase(id);
} }
void Chat::AddChatCommands() void Chat::AddChatCommands()
@ -266,14 +295,14 @@ namespace Components
const auto* cmd = params->get(0); const auto* cmd = params->get(0);
if (params->size() < 2) if (params->size() < 2)
{ {
Logger::Print("Usage: %s <client number> : prevent the player from using the chat\n", cmd); Logger::Print("Usage: {} <client number> : prevent the player from using the chat\n", cmd);
return; return;
} }
const auto* client = Game::SV_GetPlayerByNum(); const auto* client = Game::SV_GetPlayerByNum();
if (client != nullptr) if (client != nullptr)
{ {
Chat::MuteClient(client); MuteClient(client);
} }
}); });
@ -288,7 +317,7 @@ namespace Components
const auto* cmd = params->get(0); const auto* cmd = params->get(0);
if (params->size() < 2) if (params->size() < 2)
{ {
Logger::Print("Usage: %s <client number or guid>\n%s all = unmute everyone\n", cmd, cmd); Logger::Print("Usage: {} <client number or guid>\n{} all = unmute everyone\n", cmd, cmd);
return; return;
} }
@ -296,30 +325,92 @@ namespace Components
if (client != nullptr) if (client != nullptr)
{ {
Chat::UnmuteClient(client); UnmuteClient(client);
return; return;
} }
if (std::strcmp(params->get(1), "all") == 0) if (std::strcmp(params->get(1), "all") == 0)
{ {
Logger::Print("All players were unmuted\n"); Logger::Print("All players were unmuted\n");
Chat::UnmuteInternal(0, true); UnmuteInternal(0, true);
} }
else else
{ {
const auto steamId = std::strtoull(params->get(1), nullptr, 16); const auto steamId = std::strtoull(params->get(1), nullptr, 16);
Chat::UnmuteInternal(steamId); UnmuteInternal(steamId);
} }
}); });
} }
int Chat::GetCallbackReturn()
{
if (Game::scrVmPub->inparamcount == 0)
{
// Nothing. Let's not mute the player
return 1;
}
Game::Scr_ClearOutParams();
Game::scrVmPub->outparamcount = Game::scrVmPub->inparamcount;
Game::scrVmPub->inparamcount = 0;
const auto* result = &Game::scrVmPub->top[1 - Game::scrVmPub->outparamcount];
if (result->type != Game::scrParamType_t::VAR_INTEGER)
{
// Garbage was returned
return 1;
}
return result->u.intValue;
}
int Chat::ChatCallback(Game::gentity_s* self, const char* codePos, const char* message, int mode)
{
const auto entityId = Game::Scr_GetEntityId(self->s.number, 0);
Game::Scr_AddInt(mode);
Game::Scr_AddString(message);
Game::VariableValue value;
value.type = Game::scrParamType_t::VAR_OBJECT;
value.u.uintValue = entityId;
Game::AddRefToValue(value.type, value.u);
const auto localId = Game::AllocThread(entityId);
const auto result = Game::VM_Execute_0(localId, codePos, 2);
Game::RemoveRefToObject(result);
return GetCallbackReturn();
}
void Chat::AddScriptFunctions()
{
Script::AddFunction("OnPlayerSay", [] // gsc: OnPlayerSay(<function>)
{
if (Game::Scr_GetNumParam() != 1)
{
Game::Scr_Error("^1OnPlayerSay: Needs one function pointer!\n");
return;
}
if (!CanAddCallback)
{
Game::Scr_Error("^1OnPlayerSay: Cannot add a callback in this context");
return;
}
const auto* func = Script::GetCodePosForParam(0);
SayCallbacks.emplace_back(func);
});
}
Chat::Chat() Chat::Chat()
{ {
Dvar::OnInit([] cg_chatWidth = Dvar::Register<int>("cg_chatWidth", 52, 1, std::numeric_limits<int>::max(), Game::DVAR_ARCHIVE, "The normalized maximum width of a chat message");
{ sv_disableChat = Dvar::Register<bool>("sv_disableChat", false, Game::dvar_flag::DVAR_NONE, "Disable chat messages from clients");
cg_chatWidth = Dvar::Register<int>("cg_chatWidth", 52, 1, std::numeric_limits<int>::max(), Game::DVAR_ARCHIVE, "The normalized maximum width of a chat message"); Scheduler::OnGameInitialized(AddChatCommands, Scheduler::Pipeline::SERVER);
Chat::AddChatCommands();
});
// Intercept chat sending // Intercept chat sending
Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick();
@ -328,5 +419,13 @@ namespace Components
// Change logic that does word splitting with new lines for chat messages to support fonticons // Change logic that does word splitting with new lines for chat messages to support fonticons
Utils::Hook(0x592E10, CG_AddToTeamChat_Stub, HOOK_JUMP).install()->quick(); Utils::Hook(0x592E10, CG_AddToTeamChat_Stub, HOOK_JUMP).install()->quick();
AddScriptFunctions();
// Avoid duplicates
Events::OnVMShutdown([]
{
SayCallbacks.clear();
});
} }
} }

View File

@ -9,8 +9,11 @@ namespace Components
Chat(); Chat();
private: private:
static Game::dvar_t** cg_chatHeight;
static Dvar::Var cg_chatWidth; static Dvar::Var cg_chatWidth;
static Dvar::Var sv_disableChat;
// Game dvars
static Game::dvar_t** cg_chatHeight;
static Game::dvar_t** cg_chatTime; static Game::dvar_t** cg_chatTime;
static bool SendChat; static bool SendChat;
@ -18,7 +21,10 @@ namespace Components
static std::mutex AccessMutex; static std::mutex AccessMutex;
static std::unordered_set<std::uint64_t> MuteList; static std::unordered_set<std::uint64_t> MuteList;
static const char* EvaluateSay(char* text, Game::gentity_t* player); static bool CanAddCallback; // ClientCommand & GSC thread are the same
static std::vector<Scripting::Function> SayCallbacks;
static const char* EvaluateSay(char* text, Game::gentity_t* player, int mode);
static void PreSayStub(); static void PreSayStub();
static void PostSayStub(); static void PostSayStub();
@ -31,5 +37,9 @@ namespace Components
static void UnmuteClient(const Game::client_t* client); static void UnmuteClient(const Game::client_t* client);
static void UnmuteInternal(const std::uint64_t id, bool everyone = false); static void UnmuteInternal(const std::uint64_t id, bool everyone = false);
static void AddChatCommands(); static void AddChatCommands();
static int GetCallbackReturn();
static int ChatCallback(Game::gentity_s* self, const char* codePos, const char* message, int mode);
static void AddScriptFunctions();
}; };
} }

View File

@ -32,7 +32,7 @@ namespace Components
} }
std::string command = Utils::String::VA("%c clantags \"%s\"", 22, list.data()); std::string command = Utils::String::VA("%c clantags \"%s\"", 22, list.data());
Game::SV_GameSendServerCommand(-1, 0, command.data()); Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, command.data());
} }
const char* ClanTags::GetUserClantag(std::uint32_t /*clientnum*/, const char* playername) const char* ClanTags::GetUserClantag(std::uint32_t /*clientnum*/, const char* playername)
@ -73,10 +73,11 @@ namespace Components
ClanTags::ClanTags() ClanTags::ClanTags()
{ {
// Create clantag dvar // Create clantag dvar
Dvar::OnInit([]() Scheduler::Once([]
{ {
Dvar::Register<const char*>("clantag", "", Game::dvar_flag::DVAR_USERINFO | Game::dvar_flag::DVAR_ARCHIVE, "If set, your clantag will be shown on the scoreboard."); Dvar::Register<const char*>("clantag", "", Game::dvar_flag::DVAR_USERINFO | Game::dvar_flag::DVAR_ARCHIVE,
}); "If set, your clantag will be shown on the scoreboard.");
}, Scheduler::Pipeline::MAIN);
// Servercommand hook // Servercommand hook
ServerCommands::OnCommand(22, [](Command::Params* params) ServerCommands::OnCommand(22, [](Command::Params* params)

View File

@ -10,15 +10,15 @@ namespace Components
if (!Dvar::Var("sv_cheats").get<bool>()) if (!Dvar::Var("sv_cheats").get<bool>())
{ {
Logger::Print("CheatsOk: cheats are disabled!\n"); Logger::Debug("Cheats are disabled!");
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"GAME_CHEATSNOTENABLED\"", 0x65)); Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"GAME_CHEATSNOTENABLED\"", 0x65));
return false; return false;
} }
if (ent->health < 1) if (ent->health < 1)
{ {
Logger::Print("CheatsOk: entity %i must be alive to use this command!\n", entNum); Logger::Debug("Entity {} must be alive to use this command!", entNum);
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"GAME_MUSTBEALIVECOMMAND\"", 0x65)); Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"GAME_MUSTBEALIVECOMMAND\"", 0x65));
return false; return false;
} }
@ -38,7 +38,7 @@ namespace Components
if (ent->client == nullptr) if (ent->client == nullptr)
{ {
Logger::Print("ClientCommand: client %d is not fully in game yet\n", clientNum); Logger::Debug("ClientCommand: client {} is not fully in game yet", clientNum);
return; return;
} }
@ -64,9 +64,9 @@ namespace Components
ent->client->flags ^= Game::PLAYER_FLAG_NOCLIP; ent->client->flags ^= Game::PLAYER_FLAG_NOCLIP;
const auto entNum = ent->s.number; const auto entNum = ent->s.number;
Logger::Print("Noclip toggled for entity %i\n", entNum); Logger::Debug("Noclip toggled for entity {}", entNum);
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"%s\"", 0x65, Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 0x65,
(ent->client->flags & Game::PLAYER_FLAG_NOCLIP) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF")); (ent->client->flags & Game::PLAYER_FLAG_NOCLIP) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF"));
}); });
@ -78,9 +78,9 @@ namespace Components
ent->client->flags ^= Game::PLAYER_FLAG_UFO; ent->client->flags ^= Game::PLAYER_FLAG_UFO;
const auto entNum = ent->s.number; const auto entNum = ent->s.number;
Logger::Print("UFO toggled for entity %i\n", entNum); Logger::Debug("UFO toggled for entity {}", entNum);
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"%s\"", 0x65, Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 0x65,
(ent->client->flags & Game::PLAYER_FLAG_UFO) ? "GAME_UFOON" : "GAME_UFOOFF")); (ent->client->flags & Game::PLAYER_FLAG_UFO) ? "GAME_UFOON" : "GAME_UFOOFF"));
}); });
@ -92,9 +92,9 @@ namespace Components
ent->flags ^= Game::FL_GODMODE; ent->flags ^= Game::FL_GODMODE;
const auto entNum = ent->s.number; const auto entNum = ent->s.number;
Logger::Print("God toggled for entity %i\n", entNum); Logger::Debug("God toggled for entity {}", entNum);
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"%s\"", 0x65, Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 0x65,
(ent->flags & Game::FL_GODMODE) ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF")); (ent->flags & Game::FL_GODMODE) ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF"));
}); });
@ -106,9 +106,9 @@ namespace Components
ent->flags ^= Game::FL_DEMI_GODMODE; ent->flags ^= Game::FL_DEMI_GODMODE;
const auto entNum = ent->s.number; const auto entNum = ent->s.number;
Logger::Print("Demigod toggled for entity %i\n", entNum); Logger::Debug("Demigod toggled for entity {}", entNum);
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"%s\"", 0x65, Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 0x65,
(ent->flags & Game::FL_DEMI_GODMODE) ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF")); (ent->flags & Game::FL_DEMI_GODMODE) ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF"));
}); });
@ -120,9 +120,9 @@ namespace Components
ent->flags ^= Game::FL_NOTARGET; ent->flags ^= Game::FL_NOTARGET;
const auto entNum = ent->s.number; const auto entNum = ent->s.number;
Logger::Print("Notarget toggled for entity %i\n", entNum); Logger::Debug("Notarget toggled for entity {}", entNum);
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"%s\"", 0x65, Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 0x65,
(ent->flags & Game::FL_NOTARGET) ? "GAME_NOTARGETON" : "GAME_NOTARGETOFF")); (ent->flags & Game::FL_NOTARGET) ? "GAME_NOTARGETON" : "GAME_NOTARGETOFF"));
}); });
@ -137,7 +137,7 @@ namespace Components
if (params->size() < 4 || params->size() > 6) if (params->size() < 4 || params->size() > 6)
{ {
Game::SV_GameSendServerCommand(ent->s.number, 0, Game::SV_GameSendServerCommand(ent->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"GAME_USAGE\x15: setviewpos x y z [yaw] [pitch]\n\"", 0x65)); Utils::String::VA("%c \"GAME_USAGE\x15: setviewpos x y z [yaw] [pitch]\n\"", 0x65));
return; return;
} }
@ -157,8 +157,90 @@ namespace Components
angles[0] = std::strtof(params->get(5), nullptr); // Pitch angles[0] = std::strtof(params->get(5), nullptr); // Pitch
} }
Logger::Debug("Teleported entity {} to {:f} {:f} {:f}\nviewpos {:f} {:f}", ent->s.number,
origin[0], origin[1], origin[2], angles[0], angles[2]);
Game::TeleportPlayer(ent, origin, angles); Game::TeleportPlayer(ent, origin, angles);
}); });
ClientCommand::Add("give", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (!ClientCommand::CheatsOk(ent))
return;
if (params->size() < 2)
{
Game::SV_GameSendServerCommand(ent->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"GAME_USAGE\x15: give <weapon name>\"", 0x65));
return;
}
Game::level->initializing = 1;
const auto* weaponName = params->get(1);
Logger::Debug("Giving weapon {} to entity {}", weaponName, ent->s.number);
const auto weaponIndex = Game::G_GetWeaponIndexForName(weaponName);
if (weaponIndex == 0)
{
Game::level->initializing = 0;
return;
}
if (Game::BG_GetWeaponDef(weaponIndex)->inventoryType == Game::weapInventoryType_t::WEAPINVENTORY_ALTMODE)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR,
"You can't directly spawn the altfire weapon '{}'. Spawn a weapon that has this altmode instead.\n", weaponName);
Game::level->initializing = 0;
return;
}
auto* weapEnt = Game::G_Spawn();
std::memcpy(weapEnt->r.currentOrigin, ent->r.currentOrigin, sizeof(std::float_t[3]));
Game::G_GetItemClassname(static_cast<int>(weaponIndex), weapEnt);
Game::G_SpawnItem(weapEnt, static_cast<int>(weaponIndex));
weapEnt->active = 1;
const auto offHandClass = Game::BG_GetWeaponDef(weaponIndex)->offhandClass;
if (offHandClass != Game::OFFHAND_CLASS_NONE)
{
auto* client = ent->client;
if ((client->ps.weapCommon.offhandPrimary != offHandClass) && (client->ps.weapCommon.offhandSecondary != offHandClass))
{
switch (offHandClass)
{
case Game::OFFHAND_CLASS_FRAG_GRENADE:
case Game::OFFHAND_CLASS_THROWINGKNIFE:
case Game::OFFHAND_CLASS_OTHER:
Logger::Debug("Setting offhandPrimary");
client->ps.weapCommon.offhandPrimary = offHandClass;
break;
default:
Logger::Debug("Setting offhandSecondary");
client->ps.weapCommon.offhandSecondary = offHandClass;
break;
}
}
}
Game::Touch_Item(weapEnt, ent, 0);
weapEnt->active = 0;
if (weapEnt->r.isInUse)
{
Logger::Debug("Freeing up entity {}", weapEnt->s.number);
Game::G_FreeEntity(weapEnt);
}
Game::level->initializing = 0;
for (std::size_t i = 0; i < std::extent_v<decltype(Game::playerState_s::weaponsEquipped)>; ++i)
{
const auto index = ent->client->ps.weaponsEquipped[i];
if (index != 0)
{
Game::Add_Ammo(ent, index, 0, 998, 1);
}
}
});
} }
void ClientCommand::AddDevelopmentCommands() void ClientCommand::AddDevelopmentCommands()
@ -180,7 +262,7 @@ namespace Components
ClientCommand::Add("entitycount", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) ClientCommand::Add("entitycount", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{ {
Logger::Print("Entity count = %i\n", Game::level->num_entities); Logger::Print("Entity count = {}\n", Game::level->num_entities);
}); });
// Also known as: "vis" // Also known as: "vis"
@ -208,7 +290,7 @@ namespace Components
strncpy_s(ent->client->visionName[visMode], strncpy_s(ent->client->visionName[visMode],
sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE); sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE);
Game::SV_GameSendServerCommand(ent->s.number, 1, Game::SV_GameSendServerCommand(ent->s.number, Game::SV_CMD_RELIABLE,
Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration));
}); });
@ -236,14 +318,33 @@ namespace Components
strncpy_s(ent->client->visionName[visMode], strncpy_s(ent->client->visionName[visMode],
sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE); sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE);
Game::SV_GameSendServerCommand(ent->s.number, 1, Game::SV_GameSendServerCommand(ent->s.number, Game::SV_CMD_RELIABLE,
Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration));
}); });
ClientCommand::Add("g_testCmd", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) ClientCommand::Add("g_testCmd", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{ {
assert(ent != nullptr); assert(ent != nullptr);
ent->client->ps.stunTime = 1000 + Game::level->time; // 1000 is the default test stun time ent->client->ps.stunTime = 1000 + Game::level->time; // 1000 is the default test stun time
Logger::Debug("playerState_s.stunTime is {}", ent->client->ps.stunTime);
});
ClientCommand::Add("kill", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
assert(ent->client != nullptr);
assert(ent->client->connected != Game::clientConnected_t::CON_DISCONNECTED);
if (ent->client->sessionState != Game::sessionState_t::SESS_STATE_PLAYING || !ClientCommand::CheatsOk(ent))
return;
Scheduler::Once([ent]
{
ent->flags &= ~(Game::entityFlag::FL_GODMODE | Game::entityFlag::FL_DEMI_GODMODE);
ent->health = 0;
ent->client->ps.stats[0] = 0;
Game::player_die(ent, ent, ent, 100000, 12, 0, nullptr, Game::hitLocation_t::HITLOC_NONE, 0);
}, Scheduler::Pipeline::SERVER);
}); });
} }

View File

@ -60,11 +60,19 @@ namespace Components
return Game::sv_cmd_args->argv[this->nesting_][index]; return Game::sv_cmd_args->argv[this->nesting_][index];
} }
void Command::Add(const char* name, std::function<void(Command::Params*)> callback) void Command::Add(const char* name, const std::function<void()>& callback)
{
Add(name, [callback]([[maybe_unused]] const Command::Params* params)
{
callback();
});
}
void Command::Add(const char* name, const std::function<void(Command::Params*)>& callback)
{ {
const auto command = Utils::String::ToLower(name); const auto command = Utils::String::ToLower(name);
if (Command::FunctionMap.find(command) == Command::FunctionMap.end()) if (!Command::FunctionMap.contains(command))
{ {
Command::AddRaw(name, Command::MainCallback); Command::AddRaw(name, Command::MainCallback);
} }
@ -72,11 +80,11 @@ namespace Components
Command::FunctionMap.insert_or_assign(command, std::move(callback)); Command::FunctionMap.insert_or_assign(command, std::move(callback));
} }
void Command::AddSV(const char* name, std::function<void(Command::Params*)> callback) void Command::AddSV(const char* name, const std::function<void(Command::Params*)>& callback)
{ {
if (Loader::IsPregame()) if (Loader::IsPregame())
{ {
MessageBoxA(nullptr, "Registering server commands in pregamestate is illegal!", nullptr, MB_ICONERROR); MessageBoxA(nullptr, "Registering server commands in pregame state is illegal!", nullptr, MB_ICONERROR);
#ifdef DEBUG #ifdef DEBUG
__debugbreak(); __debugbreak();
@ -87,7 +95,7 @@ namespace Components
const auto command = Utils::String::ToLower(name); const auto command = Utils::String::ToLower(name);
if (Command::FunctionMapSV.find(command) == Command::FunctionMapSV.end()) if (!Command::FunctionMapSV.contains(command))
{ {
Command::AddRawSV(name, Command::MainCallbackSV); Command::AddRawSV(name, Command::MainCallbackSV);
@ -95,7 +103,7 @@ namespace Components
Command::AddRaw(name, Game::Cbuf_AddServerText); Command::AddRaw(name, Game::Cbuf_AddServerText);
} }
FunctionMapSV.insert_or_assign(command, std::move(callback)); FunctionMapSV.insert_or_assign(command, callback);
} }
void Command::AddRaw(const char* name, void(*callback)(), bool key) void Command::AddRaw(const char* name, void(*callback)(), bool key)
@ -168,17 +176,4 @@ namespace Components
got->second(&params); got->second(&params);
} }
} }
Command::Command()
{
AssertSize(Game::cmd_function_t, 24);
Command::Add("openLink", [](Command::Params* params)
{
if (params->size() > 1)
{
Utils::OpenUrl(params->get(1));
}
});
}
} }

View File

@ -5,6 +5,8 @@ namespace Components
class Command : public Component class Command : public Component
{ {
public: public:
static_assert(sizeof(Game::cmd_function_t) == 0x18);
class Params class Params
{ {
public: public:
@ -45,14 +47,14 @@ namespace Components
int nesting_; int nesting_;
}; };
Command(); Command() = default;
static Game::cmd_function_t* Allocate(); static Game::cmd_function_t* Allocate();
static void Add(const char* name, std::function<void(Command::Params*)> callback); static void Add(const char* name, const std::function<void()>& callback);
static void AddSV(const char* name, std::function<void(Command::Params*)> callback); static void Add(const char* name, const std::function<void(Command::Params*)>& callback);
static void AddRaw(const char* name, void(*callback)(), bool key = false); static void AddRaw(const char* name, void(*callback)(), bool key = false);
static void AddRawSV(const char* name, void(*callback)()); static void AddSV(const char* name, const std::function<void(Command::Params*)>& callback);
static void Execute(std::string command, bool sync = true); static void Execute(std::string command, bool sync = true);
static Game::cmd_function_t* Find(const std::string& command); static Game::cmd_function_t* Find(const std::string& command);
@ -61,6 +63,8 @@ namespace Components
static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMap; static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMap;
static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMapSV; static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMapSV;
static void AddRawSV(const char* name, void(*callback)());
static void MainCallback(); static void MainCallback();
static void MainCallbackSV(); static void MainCallbackSV();
}; };

View File

@ -213,7 +213,7 @@ namespace Components
}); });
// Invocation handler // Invocation handler
Scheduler::OnReady(ConnectProtocol::Invocation); Scheduler::OnGameInitialized(ConnectProtocol::Invocation, Scheduler::Pipeline::MAIN);
ConnectProtocol::InstallProtocol(); ConnectProtocol::InstallProtocol();
ConnectProtocol::EvaluateProtocol(); ConnectProtocol::EvaluateProtocol();
@ -232,10 +232,10 @@ namespace Components
// Only skip intro here, invocation will be done later. // Only skip intro here, invocation will be done later.
Utils::Hook::Set<BYTE>(0x60BECF, 0xEB); Utils::Hook::Set<BYTE>(0x60BECF, 0xEB);
Scheduler::OnDelay([]() Scheduler::Once([]
{ {
Command::Execute("openmenu popup_reconnectingtoparty", false); Command::Execute("openmenu popup_reconnectingtoparty", false);
}, 8s); }, Scheduler::Pipeline::CLIENT, 8s);
} }
} }
} }

View File

@ -13,8 +13,8 @@ namespace Components
int Console::Height = 25; int Console::Height = 25;
int Console::Width = 80; int Console::Width = 80;
char Console::LineBuffer[1024] = { 0 }; char Console::LineBuffer[1024] = {0};
char Console::LineBuffer2[1024] = { 0 }; char Console::LineBuffer2[1024] = {0};
int Console::LineBufferIndex = 0; int Console::LineBufferIndex = 0;
bool Console::HasConsole = false; bool Console::HasConsole = false;
@ -24,7 +24,7 @@ namespace Components
Game::SafeArea Console::OriginalSafeArea; Game::SafeArea Console::OriginalSafeArea;
char** Console::GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType) char** Console::GetAutoCompleteFileList(const char* path, const char* extension, Game::FsListBehavior_e behavior, int* numfiles, int allocTrackType)
{ {
if (path == reinterpret_cast<char*>(0xBAADF00D) || path == reinterpret_cast<char*>(0xCDCDCDCD) || ::Utils::Memory::IsBadReadPtr(path)) return nullptr; if (path == reinterpret_cast<char*>(0xBAADF00D) || path == reinterpret_cast<char*>(0xCDCDCDCD) || ::Utils::Memory::IsBadReadPtr(path)) return nullptr;
return Game::FS_GetFileList(path, extension, behavior, numfiles, allocTrackType); return Game::FS_GetFileList(path, extension, behavior, numfiles, allocTrackType);
@ -44,8 +44,8 @@ namespace Components
void Console::RefreshStatus() void Console::RefreshStatus()
{ {
std::string mapname = Dvar::Var("mapname").get<const char*>(); const auto mapname = Dvar::Var("mapname").get<std::string>();
std::string hostname = TextRenderer::StripColors(Dvar::Var("sv_hostname").get<const char*>()); const auto hostname = TextRenderer::StripColors(Dvar::Var("sv_hostname").get<std::string>());
if (Console::HasConsole) if (Console::HasConsole)
{ {
@ -72,7 +72,7 @@ namespace Components
} }
wclear(Console::InfoWindow); wclear(Console::InfoWindow);
wprintw(Console::InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxclientCount, (mapname.size() ? mapname.data() : "none")); wprintw(Console::InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxclientCount, (!mapname.empty()) ? mapname.data() : "none");
wnoutrefresh(Console::InfoWindow); wnoutrefresh(Console::InfoWindow);
} }
else if (IsWindow(Console::GetWindow()) != FALSE) else if (IsWindow(Console::GetWindow()) != FALSE)
@ -318,17 +318,16 @@ namespace Components
Console::RefreshOutput(); Console::RefreshOutput();
} }
void Console::Error(const char* format, ...) void Console::Error(const char* fmt, ...)
{ {
static char buffer[32768]; char buf[4096] = {0};
va_list va; va_list va;
va_start(va, format); va_start(va, fmt);
_vsnprintf_s(buffer, sizeof(buffer), format, va); _vsnprintf_s(buf, _TRUNCATE, fmt, va);
va_end(va); va_end(va);
Game::Com_Printf(0, "ERROR:\n"); Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}", buf);
Game::Com_Printf(0, buffer);
Console::RefreshOutput(); Console::RefreshOutput();
@ -426,13 +425,13 @@ namespace Components
fflush(stdout); fflush(stdout);
} }
void Console::StdOutError(const char* format, ...) void Console::StdOutError(const char* fmt, ...)
{ {
char buffer[0x1000] = { 0 }; char buffer[4096] = {0};
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, fmt);
_vsnprintf_s(buffer, sizeof(buffer), format, ap); _vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
va_end(ap); va_end(ap);
perror(buffer); perror(buffer);
@ -520,7 +519,7 @@ namespace Components
{ "con_outputWindowColor", { 0.25f, 0.25f, 0.25f, 0.85f } }, { "con_outputWindowColor", { 0.25f, 0.25f, 0.25f, 0.85f } },
}; };
for (int i = 0; i < ARRAYSIZE(patchedColors); ++i) for (std::size_t i = 0; i < ARRAYSIZE(patchedColors); ++i)
{ {
if (std::strcmp(dvarName, patchedColors[i].name) == 0) if (std::strcmp(dvarName, patchedColors[i].name) == 0)
{ {
@ -544,7 +543,10 @@ namespace Components
static float consoleColor[] = { 0.70f, 1.00f, 0.00f, 1.00f }; static float consoleColor[] = { 0.70f, 1.00f, 0.00f, 1.00f };
Utils::Hook::Set<float*>(0x5A451A, consoleColor); Utils::Hook::Set<float*>(0x5A451A, consoleColor);
Utils::Hook::Set<float*>(0x5A4400, consoleColor); Utils::Hook::Set<float*>(0x5A4400, consoleColor);
// Remove the need to type '\' or '/' to send a console command
Utils::Hook::Set<BYTE>(0x431565, 0xEB);
// Internal console // Internal console
Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).install()->quick(); Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).install()->quick();
Utils::Hook(0x4F65A5, Console::ToggleConsole, HOOK_JUMP).install()->quick(); Utils::Hook(0x4F65A5, Console::ToggleConsole, HOOK_JUMP).install()->quick();
@ -577,7 +579,7 @@ namespace Components
if (Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled()) if (Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
{ {
Scheduler::OnFrame(Console::RefreshStatus); Scheduler::Loop(Console::RefreshStatus, Scheduler::Pipeline::MAIN);
} }
// Code below is not necessary when performing unit tests! // Code below is not necessary when performing unit tests!
@ -619,10 +621,10 @@ namespace Components
} }
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
Scheduler::OnFrame([]() Scheduler::Loop([]
{ {
Console::LastRefresh = Game::Sys_Milliseconds(); Console::LastRefresh = Game::Sys_Milliseconds();
}); }, Scheduler::Pipeline::MAIN);
} }
else if (Dedicated::IsEnabled()/* || ZoneBuilder::IsEnabled()*/) else if (Dedicated::IsEnabled()/* || ZoneBuilder::IsEnabled()*/)
{ {

View File

@ -50,12 +50,12 @@ namespace Components
static const char* Input(); static const char* Input();
static void Print(const char* message); static void Print(const char* message);
static void Error(const char* format, ...); static void Error(const char* fmt, ...);
static void Create(); static void Create();
static void Destroy(); static void Destroy();
static void StdOutPrint(const char* message); static void StdOutPrint(const char* message);
static void StdOutError(const char* format, ...); static void StdOutError(const char* fmt, ...);
static void ConsoleRunner(); static void ConsoleRunner();

View File

@ -573,7 +573,7 @@ namespace Components
// TODO: Fix the actual error! // TODO: Fix the actual error!
if (IsBadReadPtr(pConstantData, Vector4fCount * 16)) if (IsBadReadPtr(pConstantData, Vector4fCount * 16))
{ {
//Logger::Print("Invalid shader constant array!\n"); Logger::Debug("Invalid shader constant array!");
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
} }

View File

@ -0,0 +1,240 @@
#include <STDInclude.hpp>
namespace Components
{
Dvar::Var Debug::DebugOverlay;
Game::dvar_t** Debug::PlayerDebugHealth = reinterpret_cast<Game::dvar_t**>(0x7A9F7C);
const char* Debug::PMFlagsValues[] =
{
"PMF_PRONE",
"PMF_DUCKED",
"PMF_MANTLE",
"PMF_LADDER",
"PMF_SIGHT_AIMING",
"PMF_BACKWARDS_RUN",
"PMF_WALKING",
"PMF_TIME_HARDLANDING",
"PMF_TIME_KNOCKBACK",
"PMF_PRONEMOVE_OVERRIDDEN",
"PMF_RESPAWNED",
"PMF_FROZEN",
"PMF_LADDER_FALL",
"PMF_JUMPING",
"PMF_SPRINTING",
"PMF_SHELLSHOCKED",
"PMF_MELEE_CHARGE",
"PMF_NO_SPRINT",
"PMF_NO_JUMP",
"PMF_REMOTE_CONTROLLING",
"PMF_ANIM_SCRIPTED",
"PMF_UNK1",
"PMF_DIVING",
};
const char* Debug::POFlagsValues[] =
{
"POF_INVULNERABLE",
"POF_REMOTE_EYES",
"POF_LASER_ALTVIEW",
"POF_THERMAL_VISION",
"POF_THERMAL_VISION_OVERLAY_FOF",
"POF_REMOTE_CAMERA_SOUNDS",
"POF_ALT_SCENE_REAR_VIEW",
"POF_ALT_SCENE_TAG_VIEW",
"POF_SHIELD_ATTACHED_TO_WORLD_MODEL",
"POF_DONT_LERP_VIEWANGLES",
"POF_EMP_JAMMED",
"POF_FOLLOW",
"POF_PLAYER",
"POF_SPEC_ALLOW_CYCLE",
"POF_SPEC_ALLOW_FREELOOK",
"POF_AC130",
"POF_COMPASS_PING",
"POF_ADS_THIRD_PERSON_TOGGLE",
};
const char* Debug::PLFlagsValues[] =
{
"PLF_ANGLES_LOCKED",
"PLF_USES_OFFSET",
"PLF_WEAPONVIEW_ONLY",
};
const char* Debug::PEFlagsValues[] =
{
"EF_NONSOLID_BMODEL",
"EF_TELEPORT_BIT",
"EF_CROUCHING",
"EF_PRONE",
"EF_UNK1",
"EF_NODRAW",
"EF_TIMED_OBJECT",
"EF_VOTED",
"EF_TALK",
"EF_FIRING",
"EF_TURRET_ACTIVE_PRONE",
"EF_TURRET_ACTIVE_DUCK",
"EF_LOCK_LIGHT_VIS",
"EF_AIM_ASSIST",
"EF_LOOP_RUMBLE",
"EF_LASER_SIGHT",
"EF_MANTLE",
"EF_DEAD",
"EF_ADS",
"EF_NEW",
"EF_VEHICLE_ACTIVE",
"EF_JAMMING",
"EF_COMPASS_PING",
"EF_SOFT",
};
std::string Debug::BuildPMFlagsString(const Game::playerState_s* ps)
{
std::string result;
for (size_t i = 0; i < ARRAYSIZE(PMFlagsValues); ++i)
{
result.append(Utils::String::VA("^%c%s\n", ((ps->pm_flags & (1 << i)) == 0) ? '7' : '2', PMFlagsValues[i]));
}
return result;
}
std::string Debug::BuildPOFlagsString(const Game::playerState_s* ps)
{
std::string result;
for (size_t i = 0; i < ARRAYSIZE(POFlagsValues); ++i)
{
result.append(Utils::String::VA("^%c%s\n", ((ps->otherFlags & (1 << i)) == 0) ? '7' : '2', POFlagsValues[i]));
}
return result;
}
std::string Debug::BuildPLFlagsString(const Game::playerState_s* ps)
{
std::string result;
for (size_t i = 0; i < ARRAYSIZE(PLFlagsValues); ++i)
{
result.append(Utils::String::VA("^%c%s\n", ((ps->linkFlags & (1 << i)) == 0) ? '7' : '2', PLFlagsValues[i]));
}
return result;
}
std::string Debug::BuildPEFlagsString(const Game::playerState_s* ps)
{
std::string result;
for (size_t i = 0; i < ARRAYSIZE(PEFlagsValues); ++i)
{
result.append(Utils::String::VA("^%c%s\n", ((ps->eFlags & (1 << i)) == 0) ? '7' : '2', PEFlagsValues[i]));
}
return result;
}
void Debug::CG_Debug_DrawPSFlags(const int localClientNum)
{
const auto* cgameGlob = Game::cgArray;
auto* const scrPlace = Game::ScrPlace_GetActivePlacement(localClientNum);
constexpr auto maxChars = 4096;
constexpr float colorWhite[] = {1.0f, 1.0f, 1.0f, 1.0f};
auto* const font1 = Game::UI_GetFontHandle(scrPlace, 6, MY_SCALE_2);
auto* const font2 = Game::UI_GetFontHandle(scrPlace, 6, MY_SCALE2);
Game::UI_DrawText(scrPlace, "Client View of Flags", maxChars, font2, -60.0f, 0, 1, 1,
MY_SCALE2, colorWhite, 1);
const auto pmf = BuildPMFlagsString(&cgameGlob->predictedPlayerState);
Game::UI_DrawText(scrPlace, pmf.data(), maxChars, font1, 30.0f, 20.0f, 1, 1, MY_SCALE_2, colorWhite, 3);
const auto pof = BuildPOFlagsString(&cgameGlob->predictedPlayerState);
Game::UI_DrawText(scrPlace, pof.data(), maxChars, font1, 350.0f, 20.0f, 1, 1, MY_SCALE_2, colorWhite, 3);
const auto plf = BuildPLFlagsString(&cgameGlob->predictedPlayerState);
Game::UI_DrawText(scrPlace, plf.data(), maxChars, font1, 350.0f, 250.0f, 1, 1, MY_SCALE_2, colorWhite, 3);
const auto pef = BuildPEFlagsString(&cgameGlob->predictedPlayerState);
Game::UI_DrawText(scrPlace, pef.data(), maxChars, font1, 525.0f, 20.0f, 1, 1, MY_SCALE_2, colorWhite, 3);
}
void Debug::CG_DrawDebugPlayerHealth(const int localClientNum)
{
float healtha;
constexpr float color1[] = {0.0f, 0.0f, 0.0f, 1.0f};
constexpr float color2[] = {0.0f, 1.0f, 0.0f, 1.0f};
assert((*PlayerDebugHealth)->current.enabled);
const auto* cgameGlob = Game::cgArray;
if (cgameGlob->predictedPlayerState.stats[0] && cgameGlob->predictedPlayerState.stats[2])
{
const auto health = static_cast<float>(cgameGlob->predictedPlayerState.stats[0]) / static_cast<float>(cgameGlob->predictedPlayerState.stats[2]);
const auto stats = ((health - 1.0f) < 0.0f)
? static_cast<float>(cgameGlob->predictedPlayerState.stats[0]) / static_cast<float>(cgameGlob->predictedPlayerState.stats[2])
: 1.0f;
healtha = ((0.0f - health) < 0.0f)
? stats
: 0.0f;
}
else
{
healtha = 0.0f;
}
auto* const scrPlace = Game::ScrPlace_GetActivePlacement(localClientNum);
Game::CL_DrawStretchPic(scrPlace, 10.0f, 10.0f, 100.0f, 10.0f, 1, 1, 0.0f, 0.0f, 1.0f, 1.0f, color1, *Game::whiteMaterial);
Game::CL_DrawStretchPic(scrPlace, 10.0f, 10.0f, 100.0f * healtha, 10.0f, 1, 1, 0.0f, 0.0f, healtha, 1.0f, color2, *Game::whiteMaterial);
}
void Debug::CG_DrawDebugOverlays_Hk(const int localClientNum)
{
switch (DebugOverlay.get<int>())
{
case 2:
CG_Debug_DrawPSFlags(localClientNum);
break;
default:
break;
}
if ((*PlayerDebugHealth)->current.enabled)
{
CG_DrawDebugPlayerHealth(localClientNum);
}
}
void Debug::CL_InitDebugDvars()
{
static const char* debugOverlayNames_0[] =
{
"Off",
"ViewmodelInfo",
"Playerstate Flags",
"Entity Counts",
"Controllers",
"FontTest",
nullptr,
};
DebugOverlay = Game::Dvar_RegisterEnum("debugOverlay", debugOverlayNames_0, 0,
Game::dvar_flag::DVAR_NONE, "Toggles the display of various debug info.");
}
Debug::Debug()
{
Scheduler::Once(CL_InitDebugDvars, Scheduler::Pipeline::MAIN);
// Hook end of CG_DrawDebugOverlays (This is to ensure some checks are done before our hook is executed).
Utils::Hook(0x49CB0A, CG_DrawDebugOverlays_Hk, HOOK_JUMP).install()->quick();
}
}

View File

@ -0,0 +1,36 @@
#pragma once
namespace Components
{
class Debug : public Component
{
public:
Debug();
private:
static Dvar::Var DebugOverlay;
// Game dvars
static Game::dvar_t** PlayerDebugHealth;
static const char* PMFlagsValues[];
static const char* POFlagsValues[];
static const char* PLFlagsValues[];
static const char* PEFlagsValues[];
static constexpr auto MY_SCALE2 = 0.5f;
static constexpr auto MY_SCALE_2 = 0.201f;
static std::string BuildPMFlagsString(const Game::playerState_s* ps);
static std::string BuildPOFlagsString(const Game::playerState_s* ps);
static std::string BuildPLFlagsString(const Game::playerState_s* ps);
static std::string BuildPEFlagsString(const Game::playerState_s* ps);
static void CG_Debug_DrawPSFlags(int localClientNum);
static void CG_DrawDebugPlayerHealth(int localClientNum);
static void CG_DrawDebugOverlays_Hk(int localClientNum);
static void CL_InitDebugDvars();
};
}

View File

@ -4,8 +4,8 @@ namespace Components
{ {
SteamID Dedicated::PlayerGuids[18][2]; SteamID Dedicated::PlayerGuids[18][2];
Dvar::Var Dedicated::SVRandomMapRotation;
Dvar::Var Dedicated::SVLanOnly; Dvar::Var Dedicated::SVLanOnly;
Dvar::Var Dedicated::COMLogFilter;
bool Dedicated::IsEnabled() bool Dedicated::IsEnabled()
{ {
@ -35,7 +35,7 @@ namespace Components
std::memcpy(reinterpret_cast<void*>(0x66E1CB0), &fastfiles, sizeof(fastfiles)); std::memcpy(reinterpret_cast<void*>(0x66E1CB0), &fastfiles, sizeof(fastfiles));
Game::R_LoadGraphicsAssets(); Game::R_LoadGraphicsAssets();
if (Dvar::Var("com_logFilter").get<bool>()) if (COMLogFilter.get<bool>())
{ {
Utils::Hook::Nop(0x647466, 5); // 'dvar set' lines Utils::Hook::Nop(0x647466, 5); // 'dvar set' lines
Utils::Hook::Nop(0x5DF4F2, 5); // 'sending splash open' lines Utils::Hook::Nop(0x5DF4F2, 5); // 'sending splash open' lines
@ -96,161 +96,26 @@ namespace Components
} }
} }
Game::SV_GameSendServerCommand(-1, 0, list.data()); Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, list.data());
} }
void Dedicated::TimeWrapStub(Game::errorParm_t code, const char* message) void Dedicated::TimeWrapStub(Game::errorParm_t code, const char* message)
{ {
static bool partyEnable; Scheduler::Once([]
static std::string mapname;
partyEnable = Dvar::Var("party_enable").get<bool>();
mapname = Dvar::Var("mapname").get<std::string>();
Scheduler::Once([]()
{ {
Dvar::Var("party_enable").set(partyEnable); const auto partyEnable = Dvar::Var("party_enable").get<bool>();
auto mapname = Dvar::Var("mapname").get<std::string>();
if (!partyEnable) // Time wrapping should not occur in party servers, but yeah... if (!partyEnable) // Time wrapping should not occur in party servers, but yeah...
{ {
if (mapname.empty()) mapname = "mp_rust"; if (mapname.empty()) mapname = "mp_rust";
Command::Execute(Utils::String::VA("map %s", mapname.data()), false); Command::Execute(Utils::String::VA("map %s", mapname.data()), false);
mapname.clear();
} }
}); }, Scheduler::Pipeline::SERVER);
Game::Com_Error(code, message); Game::Com_Error(code, message);
} }
void Dedicated::RandomizeMapRotation()
{
auto rotation = Dvar::Var("sv_mapRotation").get<std::string>();
const auto tokens = Utils::String::Split(rotation, ' ');
std::vector<std::pair<std::string, std::string>> mapRotationPair;
for (auto i = 0u; i < (tokens.size() - 1); i += 2)
{
if (i + 1 >= tokens.size()) break;
const auto& key = tokens[i];
const auto& value = tokens[i + 1];
mapRotationPair.push_back(std::make_pair(key, value));
}
const auto seed = Utils::Cryptography::Rand::GenerateInt();
std::shuffle(std::begin(mapRotationPair), std::end(mapRotationPair), std::default_random_engine(seed));
// Rebuild map rotation using the randomized key/values
rotation.clear();
for (auto j = 0u; j < mapRotationPair.size(); j++)
{
const auto& pair = mapRotationPair[j];
rotation.append(pair.first);
rotation.append(" ");
rotation.append(pair.second);
if (j != mapRotationPair.size() - 1)
rotation.append(" ");
}
Dvar::Var("sv_mapRotationCurrent").set(rotation);
}
void Dedicated::MapRotate()
{
if (!Dedicated::IsEnabled() && Dvar::Var("sv_dontrotate").get<bool>())
{
Dvar::Var("sv_dontrotate").set(false);
return;
}
if (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>())
{
Logger::Print("Not performing map rotation as we are hosting a party!\n");
return;
}
Logger::Print("Rotating map...\n");
const auto mapRotation = Dvar::Var("sv_mapRotation").get<std::string>();
// if nothing, just restart
if (mapRotation.empty())
{
Logger::Print("No rotation defined, restarting map.\n");
if (!Dvar::Var("sv_cheats").get<bool>())
{
Command::Execute(Utils::String::VA("map %s", Dvar::Var("mapname").get<const char*>()), true);
}
else
{
Command::Execute(Utils::String::VA("devmap %s", Dvar::Var("mapname").get<const char*>()), true);
}
return;
}
// First, check if the string contains nothing
if (Dvar::Var("sv_mapRotationCurrent").get<std::string>().empty())
{
Logger::Print("Current map rotation has finished, reloading...\n");
if (Dedicated::SVRandomMapRotation.get<bool>())
{
Logger::Print("Randomizing map rotation\n");
Dedicated::RandomizeMapRotation();
}
else
{
Dvar::Var("sv_mapRotationCurrent").set(mapRotation);
}
}
auto rotation = Dvar::Var("sv_mapRotationCurrent").get<std::string>();
auto tokens = Utils::String::Split(rotation, ' ');
for (unsigned int i = 0; i < (tokens.size() - 1); i += 2)
{
if (i + 1 >= tokens.size())
{
Dvar::Var("sv_mapRotationCurrent").set("");
Command::Execute("map_rotate", true);
return;
}
std::string key = tokens[i];
std::string value = tokens[i + 1];
if (key == "map")
{
// Rebuild map rotation string
rotation.clear();
for (unsigned int j = (i + 2); j < tokens.size(); ++j)
{
if (j != (i + 2)) rotation += " ";
rotation += tokens[j];
}
Dvar::Var("sv_mapRotationCurrent").set(rotation);
Logger::Print("Loading new map: %s\n", value.data());
Command::Execute(Utils::String::VA("map %s", value.data()), true);
break;
}
else if (key == "gametype")
{
Logger::Print("Applying new gametype: %s\n", value.data());
Dvar::Var("g_gametype").set(value);
}
else
{
Logger::Print("Unsupported maprotation key '%s', motherfucker!\n", key.data());
}
}
}
void Dedicated::Heartbeat() void Dedicated::Heartbeat()
{ {
// Do not send a heartbeat if sv_lanOnly is set to true // Do not send a heartbeat if sv_lanOnly is set to true
@ -264,45 +129,92 @@ namespace Components
Network::Address master(Utils::String::VA("%s:%u", masterServerName, masterPort)); Network::Address master(Utils::String::VA("%s:%u", masterServerName, masterPort));
Logger::Print("Sending heartbeat to master: %s:%u\n", masterServerName, masterPort); Logger::Print(Game::CON_CHANNEL_SERVER, "Sending heartbeat to master: {}:{}\n", masterServerName, masterPort);
Network::SendCommand(master, "heartbeat", "IW4"); Network::SendCommand(master, "heartbeat", "IW4");
} }
__declspec(naked) void Dedicated::FrameStub()
{
__asm
{
pushad
call Scheduler::FrameHandler
popad
push 5A8E80h
retn
}
}
Game::dvar_t* Dedicated::Dvar_RegisterSVNetworkFps(const char* dvarName, int, int min, int, int, const char* description) Game::dvar_t* Dedicated::Dvar_RegisterSVNetworkFps(const char* dvarName, int, int min, int, int, const char* description)
{ {
return Game::Dvar_RegisterInt(dvarName, 1000, min, 1000, Game::dvar_flag::DVAR_NONE, description); return Game::Dvar_RegisterInt(dvarName, 1000, min, 1000, Game::dvar_flag::DVAR_NONE, description);
} }
void Dedicated::AddDedicatedCommands()
{
// Say command
Command::AddSV("say", [](Command::Params* params)
{
if (params->size() < 2) return;
auto message = params->join(1);
auto name = Dvar::Var("sv_sayName").get<std::string>();
if (!name.empty())
{
Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
Logger::Print(Game::CON_CHANNEL_SERVER, "{}: {}\n", name, message);
}
else
{
Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"Console: %s\"", 104, message.data()));
Logger::Print(Game::CON_CHANNEL_SERVER, "Console: {}\n", message);
}
});
// Tell command
Command::AddSV("tell", [](Command::Params* params)
{
if (params->size() < 3) return;
const auto client = atoi(params->get(1));
auto message = params->join(2);
auto name = Dvar::Var("sv_sayName").get<std::string>();
if (!name.empty())
{
Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
Logger::Print(Game::CON_CHANNEL_SERVER, "{} -> {}: {}\n", name, client, message);
}
else
{
Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"Console: %s\"", 104, message.data()));
Logger::Print(Game::CON_CHANNEL_SERVER, "Console -> {}: {}\n", client, message);
}
});
// Sayraw command
Command::AddSV("sayraw", [](Command::Params* params)
{
if (params->size() < 2) return;
auto message = params->join(1);
Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 104, message.data()));
Logger::Print(Game::CON_CHANNEL_SERVER, "Raw: {}\n", message);
});
// Tellraw command
Command::AddSV("tellraw", [](Command::Params* params)
{
if (params->size() < 3) return;
const auto client = atoi(params->get(1));
std::string message = params->join(2);
Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 104, message.data()));
Logger::Print(Game::CON_CHANNEL_SERVER, "Raw -> {}: {}\n", client, message);
});
}
Dedicated::Dedicated() Dedicated::Dedicated()
{ {
// Map rotation Dedicated::COMLogFilter = Dvar::Register<bool>("com_logFilter", true,
Utils::Hook::Set(0x4152E8, Dedicated::MapRotate); Game::dvar_flag::DVAR_LATCH, "Removes ~95% of unneeded lines from the log");
Dvar::Register<bool>("sv_dontrotate", false, Game::dvar_flag::DVAR_CHEAT, "");
Dvar::Register<bool>("com_logFilter", true, Game::dvar_flag::DVAR_LATCH, "Removes ~95% of unneeded lines from the log");
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
{ {
// Make sure all callbacks are handled // Make sure all callbacks are handled
Scheduler::OnFrame(Steam::SteamAPI_RunCallbacks); Scheduler::Loop(Steam::SteamAPI_RunCallbacks, Scheduler::Pipeline::SERVER);
Dvar::OnInit([] Dedicated::SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false,
{ Game::dvar_flag::DVAR_NONE, "Don't act as node");
Dedicated::SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false,
Game::dvar_flag::DVAR_NONE, "Don't act as node");
});
Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).install()->quick(); Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).install()->quick();
@ -361,112 +273,33 @@ namespace Components
// don't load the config // don't load the config
Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB); Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB);
// Dedicated frame handler
Utils::Hook(0x4B0F81, Dedicated::FrameStub, HOOK_CALL).install()->quick();
// Intercept time wrapping // Intercept time wrapping
Utils::Hook(0x62737D, Dedicated::TimeWrapStub, HOOK_CALL).install()->quick(); Utils::Hook(0x62737D, Dedicated::TimeWrapStub, HOOK_CALL).install()->quick();
//Utils::Hook::Set<DWORD>(0x62735C, 50'000); // Time wrap after 50 seconds (for testing - i don't want to wait 3 weeks) //Utils::Hook::Set<DWORD>(0x62735C, 50'000); // Time wrap after 50 seconds (for testing - i don't want to wait 3 weeks)
if (!ZoneBuilder::IsEnabled()) if (!ZoneBuilder::IsEnabled())
{ {
Scheduler::Once([]
{
Dvar::Register<const char*>("sv_sayName", "^7Console", Game::dvar_flag::DVAR_NONE, "The name to pose as for 'say' commands");
Dvar::Register<const char*>("sv_motd", "", Game::dvar_flag::DVAR_NONE, "A custom message of the day for servers");
}, Scheduler::Pipeline::MAIN);
Scheduler::OnGameInitialized(Dedicated::AddDedicatedCommands, Scheduler::Pipeline::SERVER);
// Post initialization point // Post initialization point
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick();
// Transmit custom data // Transmit custom data
Scheduler::OnFrame([]() Scheduler::Loop([]
{ {
static Utils::Time::Interval interval; CardTitles::SendCustomTitlesToClients();
if (interval.elapsed(10s)) //Clantags::SendClantagsToClients();
{ }, Scheduler::Pipeline::SERVER, 10s);
interval.update();
CardTitles::SendCustomTitlesToClients();
//Clantags::SendClantagsToClients();
}
});
// Heartbeats // Heartbeats
Scheduler::Once(Dedicated::Heartbeat); Scheduler::Once(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER);
Scheduler::OnFrame([]() Scheduler::Loop(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER, 2min);
{
static Utils::Time::Interval interval;
if (Dvar::Var("sv_maxclients").get<int>() > 0 && interval.elapsed(2min))
{
interval.update();
Dedicated::Heartbeat();
}
});
Dvar::OnInit([]()
{
Dedicated::SVRandomMapRotation = Dvar::Register<bool>("sv_randomMapRotation", false, Game::dvar_flag::DVAR_ARCHIVE, "Randomize map rotation when true");
Dvar::Register<const char*>("sv_sayName", "^7Console", Game::dvar_flag::DVAR_NONE, "The name to pose as for 'say' commands");
Dvar::Register<const char*>("sv_motd", "", Game::dvar_flag::DVAR_NONE, "A custom message of the day for servers");
// Say command
Command::AddSV("say", [](Command::Params* params)
{
if (params->size() < 2) return;
std::string message = params->join(1);
std::string name = Dvar::Var("sv_sayName").get<std::string>();
if (!name.empty())
{
Game::SV_GameSendServerCommand(-1, 0, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
Game::Com_Printf(15, "%s: %s\n", name.data(), message.data());
}
else
{
Game::SV_GameSendServerCommand(-1, 0, Utils::String::VA("%c \"Console: %s\"", 104, message.data()));
Game::Com_Printf(15, "Console: %s\n", message.data());
}
});
// Tell command
Command::AddSV("tell", [](Command::Params* params)
{
if (params->size() < 3) return;
int client = atoi(params->get(1));
std::string message = params->join(2);
std::string name = Dvar::Var("sv_sayName").get<std::string>();
if (!name.empty())
{
Game::SV_GameSendServerCommand(client, 0, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
Game::Com_Printf(15, "%s -> %i: %s\n", name.data(), client, message.data());
}
else
{
Game::SV_GameSendServerCommand(client, 0, Utils::String::VA("%c \"Console: %s\"", 104, message.data()));
Game::Com_Printf(15, "Console -> %i: %s\n", client, message.data());
}
});
// Sayraw command
Command::AddSV("sayraw", [](Command::Params* params)
{
if (params->size() < 2) return;
std::string message = params->join(1);
Game::SV_GameSendServerCommand(-1, 0, Utils::String::VA("%c \"%s\"", 104, message.data()));
Game::Com_Printf(15, "Raw: %s\n", message.data());
});
// Tellraw command
Command::AddSV("tellraw", [](Command::Params* params)
{
if (params->size() < 3) return;
int client = atoi(params->get(1));
std::string message = params->join(2);
Game::SV_GameSendServerCommand(client, 0, Utils::String::VA("%c \"%s\"", 104, message.data()));
Game::Com_Printf(15, "Raw -> %i: %s\n", client, message.data());
});
});
} }
} }
else else
@ -495,18 +328,12 @@ namespace Components
}); });
} }
Scheduler::OnFrame([]() Scheduler::Loop([]
{ {
if (Dvar::Var("sv_running").get<bool>()) if (Dvar::Var("sv_running").get<bool>())
{ {
static Utils::Time::Interval interval; Dedicated::TransmitGuids();
if (interval.elapsed(15s))
{
interval.update();
Dedicated::TransmitGuids();
}
} }
}); }, Scheduler::Pipeline::SERVER, 15s);
} }
} }

View File

@ -9,27 +9,24 @@ namespace Components
static SteamID PlayerGuids[18][2]; static SteamID PlayerGuids[18][2];
static Dvar::Var SVLanOnly; static Dvar::Var SVLanOnly;
static Dvar::Var COMLogFilter;
static bool IsEnabled(); static bool IsEnabled();
static void Heartbeat(); static void Heartbeat();
private: private:
static Dvar::Var SVRandomMapRotation;
static void RandomizeMapRotation();
static void MapRotate();
static void InitDedicatedServer(); static void InitDedicatedServer();
static void PostInitialization(); static void PostInitialization();
static void PostInitializationStub(); static void PostInitializationStub();
static void FrameStub();
static void TransmitGuids(); static void TransmitGuids();
static void TimeWrapStub(Game::errorParm_t code, const char* message); static void TimeWrapStub(Game::errorParm_t code, const char* message);
static Game::dvar_t* Dvar_RegisterSVNetworkFps(const char* dvarName, int value, int min, int max, int flags, const char* description); static Game::dvar_t* Dvar_RegisterSVNetworkFps(const char* dvarName, int value, int min, int max, int flags, const char* description);
static void AddDedicatedCommands();
}; };
} }

Some files were not shown because too many files have changed in this diff Show More