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"]
path = deps/protobuf
url = https://github.com/google/protobuf.git
branch = 3.17.x
branch = 3.20.x
[submodule "deps/udis86"]
path = deps/udis86
url = https://github.com/vmt/udis86.git
[submodule "deps/dxsdk"]
path = deps/dxsdk
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/).
## [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
### 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)
- 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

View File

@ -21,7 +21,7 @@
| `--copy-pdb` | Copy debug information for binaries as well to the path given via --copy-to. |
| `--force-unit-tests` | Always compile unit tests. |
| `--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. |
## 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()
project "json11"
language "C++"
cppdialect "C++11"
files
{
@ -29,4 +30,4 @@ function json11.project()
kind "StaticLib"
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 {
trigger = "force-minidump-upload",
description = "Upload minidumps even for Debug builds."
trigger = "disable-binary-check",
description = "Do not perform integrity checks on the exe."
}
newoption {
@ -206,7 +206,7 @@ workspace "iw4x"
configurations {"Debug", "Release"}
language "C++"
cppdialect "C++17"
cppdialect "C++20"
architecture "x86"
platforms "Win32"
@ -262,12 +262,12 @@ workspace "iw4x"
if _OPTIONS["force-unit-tests"] then
defines {"FORCE_UNIT_TESTS"}
end
if _OPTIONS["force-minidump-upload"] then
defines {"FORCE_MINIDUMP_UPLOAD"}
end
if _OPTIONS["force-exception-handler"] then
defines {"FORCE_EXCEPTION_HANDLER"}
end
if _OPTIONS["disable-binary-check"] then
defines {"DISABLE_BINARY_CHECK"}
end
if _OPTIONS["iw4x-zones"] then
defines {"GENERATE_IW4X_SPECIFIC_ZONES"}
end

View File

@ -106,10 +106,18 @@ namespace Components
Loader::Register(new ClientCommand());
Loader::Register(new ScriptExtension());
Loader::Register(new Branding());
Loader::Register(new Debug());
Loader::Register(new RawMouse());
Loader::Register(new Bullet());
Loader::Register(new MapRotation());
Loader::Register(new Ceg());
Loader::Register(new UserInfo());
Loader::Register(new Events());
Loader::Pregame = false;
// Make sure preDestroy is called when the game shuts down
Scheduler::OnGameShutdown(Loader::PreDestroy);
}
void Loader::Uninitialize()
@ -123,7 +131,7 @@ namespace Components
#ifdef DEBUG
if (!Loader::IsPerformingUnitTests())
{
Logger::Print("Unregistering component: %s\n", component->getName().data());
Logger::Print("Unregister component: {}\n", component->getName());
}
#endif
delete component;
@ -172,15 +180,15 @@ namespace Components
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)
Logger::Print("Testing '%s'...\n", component->getName().data());
#if defined(FORCE_UNIT_TESTS)
Logger::Debug("Testing '{}'...\n", component->getName());
#endif
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();
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;
}
@ -203,7 +211,7 @@ namespace Components
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
if (!Loader::IsPerformingUnitTests())
{
Logger::Print("Component registered: %s\n", component->getName().data());
Logger::Print("Component registered: {}\n", component->getName());
}
#endif
Loader::Components.push_back(component);

View File

@ -5,8 +5,8 @@ namespace Components
class Component
{
public:
Component() {};
virtual ~Component() {};
Component() = default;
virtual ~Component() = default;
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
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.
// 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.
virtual void preDestroy() {};
virtual bool unitTest() { return true; }; // Unit testing entry
virtual void preDestroy() {}
virtual bool unitTest() { return true; } // Unit testing entry
};
class Loader
@ -137,5 +137,10 @@ namespace Components
#include "Modules/Gamepad.hpp"
#include "Modules/ScriptExtension.hpp"
#include "Modules/Branding.hpp"
#include "Modules/Debug.hpp"
#include "Modules/RawMouse.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 "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
{
thread_local int AssetHandler::BypassState = 0;
@ -23,14 +56,14 @@ namespace Components
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()];
}
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;
@ -58,7 +91,7 @@ namespace Components
// Allow call DB_FindXAssetHeader within the hook
AssetHandler::SetBypassState(true);
if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end())
if (AssetHandler::TypeCallbacks.contains(type))
{
header = AssetHandler::TypeCallbacks[type](type, filename);
}
@ -96,7 +129,7 @@ namespace Components
if (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();
if (AssetHandler::Relocations.find(pointer) != AssetHandler::Relocations.end())
if (AssetHandler::Relocations.contains(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)
{
if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end())
if (AssetHandler::AssetInterfaces.contains(asset.type))
{
AssetHandler::AssetInterfaces[asset.type]->save(asset.header, builder);
}
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)
{
if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end())
if (AssetHandler::AssetInterfaces.contains(asset.type))
{
AssetHandler::AssetInterfaces[asset.type]->mark(asset.header, builder);
}
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 };
}
if (AssetHandler::AssetInterfaces.find(type) != AssetHandler::AssetInterfaces.end())
if (AssetHandler::AssetInterfaces.contains(type))
{
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();
// Log missing empty assets
Scheduler::OnFrame([]()
Scheduler::Loop([]
{
if (FastFiles::Ready() && !AssetHandler::EmptyAssets.empty())
{
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();
}
});
}, Scheduler::Pipeline::MAIN);
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*)
{

View File

@ -78,37 +78,3 @@ namespace Components
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 "IComWorld.hpp"
#define IW4X_COMMAP_VERSION 0
@ -19,13 +20,13 @@ namespace Assets
__int64 magic = reader.read<__int64>();
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>();
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>();

View File

@ -5,10 +5,10 @@ namespace Assets
class IComWorld : public Components::AssetHandler::IAsset
{
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;
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;
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;
};
}

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp>
#include "IFont_s.hpp"
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.h>
@ -104,13 +105,13 @@ namespace Assets
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;
}
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;
}
@ -135,7 +136,10 @@ namespace Assets
auto* material = builder->getAllocator()->allocate<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->info.name = fontName;
@ -159,7 +163,7 @@ namespace Assets
{
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)
{
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)
{
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)
{
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;

View File

@ -5,10 +5,10 @@ namespace Assets
class IFont_s : public Components::AssetHandler::IAsset
{
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;
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;
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;
};
}

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp>
#include "IFxEffectDef.hpp"
#define IW4X_FX_VERSION 1
@ -72,13 +73,13 @@ namespace Assets
__int64 magic = buffer.read<__int64>();
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>();
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>();
@ -188,7 +189,7 @@ namespace Assets
}
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)
{
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));
if (version > 2)
{
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;
@ -231,12 +232,12 @@ namespace Assets
if (!value) break;
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))
{
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];
@ -253,13 +254,13 @@ namespace Assets
{
// TODO: Allow loading assets from raw!
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))
{
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
{
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;
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;
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;
private:
void markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp>
#include "IFxWorld.hpp"
namespace Assets
{
@ -184,11 +185,12 @@ namespace Assets
}
}
}
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;
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
{
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;
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;
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;
};
}

View File

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

View File

@ -5,8 +5,8 @@ namespace Assets
class IGameWorldMp : public Components::AssetHandler::IAsset
{
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 "IGameWorldSp.hpp"
namespace Assets
{

View File

@ -5,10 +5,10 @@ namespace Assets
class IGameWorldSp : public Components::AssetHandler::IAsset
{
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;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private:
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 "IGfxImage.hpp"
#define IW4X_IMG_VERSION "0"
@ -12,7 +13,7 @@ namespace Assets
image = builder->getAllocator()->allocate<Game::GfxImage>();
if (!image)
{
Components::Logger::Error("Failed to allocate GfxImage structure!");
Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate GfxImage structure!");
return;
}
@ -30,7 +31,7 @@ namespace Assets
__int64 magic = reader.read<__int64>();
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>();
@ -53,7 +54,7 @@ namespace Assets
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];
@ -72,7 +73,7 @@ namespace Assets
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;
}
@ -82,7 +83,7 @@ namespace Assets
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;
}
@ -93,7 +94,7 @@ namespace Assets
image->texture.loadDef = builder->getAllocator()->allocate<Game::GfxImageLoadDef>();
if (!image->texture.loadDef)
{
Components::Logger::Error("Failed to allocate GfxImageLoadDef structure!");
Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate GfxImageLoadDef structure!");
return;
}

View File

@ -5,9 +5,9 @@ namespace Assets
class IGfxImage : public Components::AssetHandler::IAsset
{
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;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, 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 "IGfxLightDef.hpp"
#define IW4X_LIGHT_VERSION "0"
@ -15,14 +16,14 @@ namespace Assets
char* magic = reader.readArray<char>(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;
version.push_back(reader.read<char>());
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>();

View File

@ -5,10 +5,10 @@ namespace Assets
class IGfxLightDef : public Components::AssetHandler::IAsset
{
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;
virtual 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 mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, 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 "IGfxWorld.hpp"
#define IW4X_GFXMAP_VERSION 1
@ -137,13 +138,13 @@ namespace Assets
__int64 magic = reader.read<__int64>();
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>();
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>();
@ -950,7 +951,7 @@ namespace Assets
}
buffer->popBlock();
SaveLogExit();
SaveLogExit();
}
void IGfxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)

View File

@ -5,11 +5,12 @@ namespace Assets
class IGfxWorld : public Components::AssetHandler::IAsset
{
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:
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);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp>
#include "ILoadedSound.hpp"
namespace Assets
{
@ -29,7 +30,7 @@ namespace Assets
unsigned int chunkIDBuffer = reader.read<unsigned int>();
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;
}
@ -38,7 +39,7 @@ namespace Assets
unsigned int format = reader.read<unsigned int>();
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;
}
@ -55,7 +56,7 @@ namespace Assets
sound->sound.info.format = reader.read<short>();
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;
}
@ -89,11 +90,11 @@ namespace Assets
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;
}
sound->name = builder->getAllocator()->duplicateString(name.c_str());
sound->name = builder->getAllocator()->duplicateString(name.data());
header->loadSnd = sound;
}

View File

@ -5,9 +5,9 @@ namespace Assets
class ILoadedSound : public Components::AssetHandler::IAsset
{
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;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, 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 "ILocalizeEntry.hpp"
namespace Assets
{

View File

@ -5,8 +5,8 @@ namespace Assets
class ILocalizeEntry : public Components::AssetHandler::IAsset
{
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 "IMapEnts.hpp"
namespace Assets
{

View File

@ -5,10 +5,10 @@ namespace Assets
class IMapEnts : public Components::AssetHandler::IAsset
{
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;
virtual 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 mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, 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 "IMaterial.hpp"
#define IW4X_MAT_VERSION "1"
@ -64,14 +65,14 @@ namespace Assets
char* magic = reader.readArray<char>(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;
version.push_back(reader.read<char>());
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>();
@ -106,18 +107,18 @@ namespace Assets
asset->techniqueSet = techsetPtr;
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;
}
}
}
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)
{
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);
asset->constantCount = header.material->constantCount;
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;
}
}
@ -231,7 +232,7 @@ namespace Assets
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;
replacementFound = true;
}
@ -241,9 +242,10 @@ namespace Assets
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;
if (techSetCorrespondance.find(techName) != techSetCorrespondance.end()) {
if (techSetCorrespondance.contains(techName))
{
auto iw4TechSetName = techSetCorrespondance[techName];
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)
{
Components::Logger::Print("Material %s with techset %s has been mapped to %s (last chance!), taking the sort key of material %s\n",
asset->info.name, asset->techniqueSet->name,
header.material->techniqueSet->name, header.material->info.name);
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, header.material->techniqueSet->name, header.material->info.name);
asset->info.sortKey = header.material->info.sortKey;
asset->techniqueSet = iw4TechSet->asset.header.techniqueSet;
@ -278,23 +279,23 @@ namespace Assets
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
{
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
{
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())
{
Components::Logger::Error("Material data left!");
Components::Logger::Error(Game::ERR_FATAL, "Material data left!");
}
/*char baseIndex = 0;
@ -339,7 +340,7 @@ namespace Assets
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;
}
@ -347,7 +348,7 @@ namespace Assets
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;
}
@ -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!?
{
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;
}
@ -363,7 +364,7 @@ namespace Assets
if (!material)
{
Components::Logger::Error("Failed to allocate material structure!");
Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate material structure!");
return;
}
@ -451,7 +452,8 @@ namespace Assets
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
@ -468,7 +470,7 @@ namespace Assets
if (!textureTable)
{
Components::Logger::Error("Failed to allocate texture table!");
Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate texture table!");
return;
}

View File

@ -5,11 +5,11 @@ namespace Assets
class IMaterial : public Components::AssetHandler::IAsset
{
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;
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;
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;
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 loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);

View File

@ -1,55 +1,57 @@
#include <STDInclude.hpp>
#include "IMaterialPixelShader.hpp"
#define IW4X_TECHSET_VERSION "0"
namespace Assets
{
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->loadBinary(header, name, builder); // Check if we need to import a new one into the game
}
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->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*/)
{
header->pixelShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).pixelShader;
}
void IMaterialPixelShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->pixelShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).pixelShader;
}
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()));
if (!psFile.exists()) return;
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()));
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);
if (std::memcmp(magic, "IW4xPIXL", 8))
{
Components::Logger::Error(0, "Reading pixel shader '%s' failed, header is invalid!", name.data());
}
char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xPIXL", 8))
{
Components::Logger::Error(Game::ERR_FATAL, "Reading pixel shader '{}' failed, header is invalid!", name);
}
std::string version;
version.push_back(reader.read<char>());
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()));
}
std::string version;
version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION)
{
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)
{
asset->name = reader.readCString();
}
if (asset->name)
{
asset->name = reader.readCString();
}
if (asset->prog.loadDef.program)
{
asset->prog.loadDef.program = reader.readArray<unsigned int>(asset->prog.loadDef.programSize);
}
if (asset->prog.loadDef.program)
{
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)
{

View File

@ -5,12 +5,12 @@ namespace Assets
class IMaterialPixelShader : public Components::AssetHandler::IAsset
{
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;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, 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 loadBinary(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);
};
}

View File

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

View File

@ -5,15 +5,15 @@ namespace Assets
class IMaterialTechniqueSet : public Components::AssetHandler::IAsset
{
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;
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;
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;
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 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 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 "IMaterialVertexDeclaration.hpp"
#define IW4X_TECHSET_VERSION "0"
namespace Assets
{
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->loadBinary(header, name, builder); // Check if we need to import a new one into the game
}
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->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*/)
{
header->vertexDecl = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexDecl;
}
void IMaterialVertexDeclaration::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->vertexDecl = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexDecl;
}
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()));
if (!declFile.exists()) return;
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()));
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);
if (std::memcmp(magic, "IW4xDECL", 8))
{
Components::Logger::Error(0, "Reading vertex declaration '%s' failed, header is invalid!", name.data());
}
char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xDECL", 8))
{
Components::Logger::Error(Game::ERR_FATAL, "Reading vertex declaration '{}' failed, header is invalid!", name);
}
std::string version;
version.push_back(reader.read<char>());
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()));
}
std::string version;
version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION)
{
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)
{
asset->name = reader.readCString();
}
if (asset->name)
{
asset->name = reader.readCString();
}
header->vertexDecl = asset;
}
header->vertexDecl = asset;
}
void IMaterialVertexDeclaration::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{

View File

@ -5,12 +5,12 @@ namespace Assets
class IMaterialVertexDeclaration : public Components::AssetHandler::IAsset
{
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;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, 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 loadBinary(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);
};
}

View File

@ -1,54 +1,56 @@
#include <StdInclude.hpp>
#include <STDInclude.hpp>
#include "IMaterialVertexShader.hpp"
#define IW4X_TECHSET_VERSION "0"
namespace Assets
{
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->loadBinary(header, name, builder); // Check if we need to import a new one into the game
}
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->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*/)
{
header->vertexShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexShader;
}
void IMaterialVertexShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->vertexShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexShader;
}
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()));
if (!vsFile.exists()) return;
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()));
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);
if (std::memcmp(magic, "IW4xVERT", 8))
{
Components::Logger::Error(0, "Reading vertex shader '%s' failed, header is invalid!", name.data());
}
char* magic = reader.readArray<char>(8);
if (std::memcmp(magic, "IW4xVERT", 8))
{
Components::Logger::Error(Game::ERR_FATAL, "Reading vertex shader '{}' failed, header is invalid!", name);
}
std::string version;
version.push_back(reader.read<char>());
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()));
}
std::string version;
version.push_back(reader.read<char>());
if (version != IW4X_TECHSET_VERSION)
{
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)
{
asset->name = reader.readCString();
}
if (asset->name)
{
asset->name = reader.readCString();
}
if (asset->prog.loadDef.program)
{
asset->prog.loadDef.program = reader.readArray<unsigned int>(asset->prog.loadDef.programSize);
}
if (asset->prog.loadDef.program)
{
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)
{

View File

@ -5,12 +5,12 @@ namespace Assets
class IMaterialVertexShader : public Components::AssetHandler::IAsset
{
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;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, 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 loadBinary(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);
};
}

View File

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

View File

@ -5,10 +5,10 @@ namespace Assets
class IMenuList : public Components::AssetHandler::IAsset
{
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;
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;
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;
};
}

View File

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

View File

@ -5,9 +5,9 @@ namespace Assets
class IPhysCollmap : public Components::AssetHandler::IAsset
{
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:
void savePhysGeomInfoArray(Components::ZoneBuilder::Zone* builder, Game::PhysGeomInfo* geoms, unsigned int count);

View File

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

View File

@ -5,8 +5,8 @@ namespace Assets
class IPhysPreset : public Components::AssetHandler::IAsset
{
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 "IRawFile.hpp"
namespace Assets
{

View File

@ -5,9 +5,9 @@ namespace Assets
class IRawFile : public Components::AssetHandler::IAsset
{
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;
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, 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 "ISndCurve.hpp"
namespace Assets
{

View File

@ -5,8 +5,8 @@ namespace Assets
class ISndCurve : public Components::AssetHandler::IAsset
{
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 "IStringTable.hpp"
namespace Assets
{

View File

@ -5,9 +5,9 @@ namespace Assets
class IStringTable : public Components::AssetHandler::IAsset
{
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:
void saveStringTableCellArray(Components::ZoneBuilder::Zone* builder, Game::StringTableCell* values, int count);

View File

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

View File

@ -5,9 +5,9 @@ namespace Assets
class IStructuredDataDefSet : public Components::AssetHandler::IAsset
{
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 saveStructuredDataStructArray(Game::StructuredDataStruct* structs, int numStructs, Components::ZoneBuilder::Zone* builder);

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -5,11 +5,11 @@ namespace Assets
class IWeapon : public Components::AssetHandler::IAsset
{
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;
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;
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;
private:
void writeWeaponDef(Game::WeaponDef* def, Components::ZoneBuilder::Zone* builder, Utils::Stream* buffer);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp>
#include "IXAnimParts.hpp"
#define IW4X_ANIM_VERSION 1
@ -15,13 +16,13 @@ namespace Assets
__int64 magic = reader.read<__int64>();
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>();
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>();
@ -96,7 +97,7 @@ namespace Assets
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;

View File

@ -5,11 +5,11 @@ namespace Assets
class IXAnimParts : public Components::AssetHandler::IAsset
{
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;
virtual 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 mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private:
void saveXAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp>
#include "IXModel.hpp"
#define IW4X_MODEL_VERSION 5
@ -48,20 +49,20 @@ namespace Assets
}
// Access index block
if (surf->triIndices)
{
void* oldPtr = surf->triIndices;
surf->triIndices = reader->readArray<unsigned short>(surf->triCount * 3);
if (surf->triIndices)
{
void* oldPtr = surf->triIndices;
surf->triIndices = reader->readArray<unsigned short>(surf->triCount * 3);
if (builder->getAllocator()->isPointerMapped(oldPtr))
{
surf->triIndices = builder->getAllocator()->getPointer<unsigned short>(oldPtr);
}
else
{
builder->getAllocator()->mapPointer(oldPtr, surf->triIndices);
}
}
if (builder->getAllocator()->isPointerMapped(oldPtr))
{
surf->triIndices = builder->getAllocator()->getPointer<unsigned short>(oldPtr);
}
else
{
builder->getAllocator()->mapPointer(oldPtr, surf->triIndices);
}
}
}
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>();
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>();
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)
{
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>();
@ -310,7 +311,7 @@ namespace Assets
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;

View File

@ -5,14 +5,14 @@ namespace Assets
class IXModel : public Components::AssetHandler::IAsset
{
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;
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;
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;
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 loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder);
void loadXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Utils::Stream::Reader* reader);

View File

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

View File

@ -5,9 +5,9 @@ namespace Assets
class IXModelSurfs : public Components::AssetHandler::IAsset
{
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:
void saveXSurface(Game::XSurface* surf, Game::XSurface* destSurf, Components::ZoneBuilder::Zone* builder);

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp>
#include "IclipMap_t.hpp"
#define IW4X_CLIPMAP_VERSION 2
@ -601,13 +602,13 @@ namespace Assets
__int64 magic = reader.read<__int64>();
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>();
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();
@ -682,7 +683,7 @@ namespace Assets
int planeIndex = reader.read<int>();
if (planeIndex < 0 || planeIndex >= clipMap->planeCount)
{
Components::Logger::Error("invalid plane index");
Components::Logger::Error(Game::ERR_FATAL, "invalid plane index");
return;
}
clipMap->brushsides[i].plane = &clipMap->planes[planeIndex];
@ -705,7 +706,7 @@ namespace Assets
int planeIndex = reader.read<int>();
if (planeIndex < 0 || planeIndex >= clipMap->planeCount)
{
Components::Logger::Error("invalid plane index\n");
Components::Logger::Error(Game::ERR_FATAL, "invalid plane index\n");
return;
}
clipMap->nodes[i].plane = &clipMap->planes[planeIndex];
@ -773,7 +774,7 @@ namespace Assets
int index = reader.read<int>();
if (index < 0 || index > clipMap->borderCount)
{
Components::Logger::Error("invalid border index\n");
Components::Logger::Error(Game::ERR_FATAL, "invalid border index\n");
return;
}
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
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)
{
Components::Logger::Error("invalid side index\n");
Components::Logger::Error(Game::ERR_FATAL, "invalid side index\n");
return;
}
clipMap->brushes[i].sides = &clipMap->brushsides[index];
@ -813,10 +814,10 @@ namespace Assets
clipMap->brushes[i].sides = nullptr;
}
unsigned int index = reader.read<unsigned int>();
auto index = reader.read<unsigned int>();
if (index > clipMap->numBrushEdges)
{
Components::Logger::Error("invalid edge index\n");
Components::Logger::Error(Game::ERR_FATAL, "invalid edge index\n");
return;
}
clipMap->brushes[i].baseAdjacentSide = &clipMap->brushEdges[index];
@ -935,7 +936,7 @@ namespace Assets
if (!reader.end())
{
Components::Logger::Error("Clipmap data left!");
Components::Logger::Error(Game::ERR_FATAL, "Clipmap data left!");
}
header->clipMap = clipMap;

View File

@ -5,11 +5,11 @@ namespace Assets
class IclipMap_t : public Components::AssetHandler::IAsset
{
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;
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;
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;
private:
class SModelQuadtree

View File

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

View File

@ -5,13 +5,13 @@ namespace Assets
class ImenuDef_t : public Components::AssetHandler::IAsset
{
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;
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;
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;
static std::unordered_map<std::string, Game::menuDef_t*> LoadedMenus;
static std::unordered_map<std::string, Game::menuDef_t*> LoadedMenus;
private:
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 "Isnd_alias_list_t.hpp"
namespace Assets
{
@ -42,7 +43,7 @@ namespace Assets
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;
}
@ -86,14 +87,14 @@ namespace Assets
{
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())
{
Components::Logger::Print("Type is %s\n", type.dump().c_str());
Components::Logger::Print("SoundFile is %s\n", soundFile.dump().c_str());
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::Print("Type is {}\n", type.dump());
Components::Logger::Print("SoundFile is {}\n", soundFile.dump());
Components::Logger::Error(Game::ERR_FATAL, "Failed to parse sound {}! Each alias must have at least a type and a soundFile\n", name);
return;
}
@ -102,102 +103,102 @@ namespace Assets
// TODO: actually support all of those properties
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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))
{
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>();
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;
}
@ -328,7 +329,7 @@ namespace Assets
}
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;
}
@ -336,7 +337,7 @@ namespace Assets
}
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;
}
}

View File

@ -5,10 +5,10 @@ namespace Assets
class Isnd_alias_list_t : public Components::AssetHandler::IAsset
{
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;
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(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::StoreKey();
Logger::Print("Security level is %d\n", Auth::GetSecurityLevel());
Logger::Debug("Security level is {}", Auth::GetSecurityLevel());
Command::Execute("closemenu security_increase_popmenu", false);
if (!Auth::TokenContainer.cancel)
@ -67,14 +67,14 @@ namespace Components
Steam::SteamUser()->GetSteamID();
if (!Auth::GuidKey.isValid())
{
Logger::SoftError("Connecting failed: Guid key is invalid!");
Logger::Error(Game::ERR_SERVERDISCONNECT, "Connecting failed: Guid key is invalid!");
return;
}
if (std::find(Auth::BannedUids.begin(), Auth::BannedUids.end(), Steam::SteamUser()->GetSteamID().bits) != Auth::BannedUids.end())
{
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;
}
@ -86,7 +86,7 @@ namespace Components
if (params.size() < 3)
{
Game::SV_Cmd_EndTokenizedString();
Logger::SoftError("Connecting failed: Command parsing error!");
Logger::Error(Game::ERR_SERVERDISCONNECT, "Connecting failed: Command parsing error!");
return;
}
@ -96,7 +96,7 @@ namespace Components
if (challenge.empty())
{
Game::SV_Cmd_EndTokenizedString();
Logger::SoftError("Connecting failed: Challenge parsing error!");
Logger::Error(Game::ERR_SERVERDISCONNECT, "Connecting failed: Challenge parsing error!");
return;
}
@ -233,7 +233,7 @@ namespace Components
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());
}
#endif
@ -429,7 +429,7 @@ namespace Components
Auth::LoadKey(true);
Steam::SteamUser()->GetSteamID();
Scheduler::OnFrame(Auth::Frame);
Scheduler::Loop(Auth::Frame, Scheduler::Pipeline::MAIN);
// Register dvar
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
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())
@ -457,16 +457,16 @@ namespace Components
{
if (params->size() < 2)
{
uint32_t level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.getPublicKey());
Logger::Print("Your current security level is %d\n", level);
Logger::Print("Your security token is: %s\n", Utils::String::DumpHex(Auth::GuidToken.toString(), "").data());
Logger::Print("Your computation token is: %s\n", Utils::String::DumpHex(Auth::ComputeToken.toString(), "").data());
const auto level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.getPublicKey());
Logger::Print("Your current security level is {}\n", level);
Logger::Print("Your security token is: {}\n", Utils::String::DumpHex(Auth::GuidToken.toString(), ""));
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);
}
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);
}
});

View File

@ -13,7 +13,7 @@ namespace Components
if (entry.first.bits)
{
for (auto& idEntry : list.idList)
for (const auto& idEntry : list.idList)
{
if (idEntry.bits == entry.first.bits)
{
@ -89,21 +89,21 @@ namespace Components
std::vector<std::string> idVector;
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[1] & 0xFF,
ipEntry.bytes[2] & 0xFF,
ipEntry.bytes[3] & 0xFF));
}
json11::Json bans = json11::Json::object
const json11::Json bans = json11::Json::object
{
{ "ip", ipVector },
{ "id", idVector },
@ -126,7 +126,7 @@ namespace Components
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;
@ -176,7 +176,7 @@ namespace Components
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;
}
@ -253,7 +253,7 @@ namespace Components
Network::Address address(params->get(2));
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)
@ -263,15 +263,15 @@ namespace Components
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
Scheduler::Once([]()
Scheduler::OnGameInitialized([]
{
Bans::BanList list;
Bans::LoadBans(&list);
});
}, Scheduler::Pipeline::SERVER);
}
}

View File

@ -83,28 +83,30 @@ namespace Components
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();
if (ent == nullptr)
return;
Scheduler::OnDelay([ent]()
Scheduler::Once([ent]
{
Game::Scr_AddString("autoassign");
Game::Scr_AddString("team_marinesopfor");
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("changeclass");
Game::Scr_Notify(ent, Game::SL_GetString("menuresponse", 0), 2);
}, 1s);
}, 1s);
}, 500ms * (i + 1));
}, Scheduler::Pipeline::SERVER, 1s);
}, 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()
{
AssertOffset(Game::client_s, bIsTestClient, 0x41AF0);
@ -335,7 +325,10 @@ namespace Components
Utils::Hook(0x441B80, Bots::G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick();
// 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
for (auto i = 0u; i < std::extent_v<decltype(g_botai)>; i++)
@ -362,8 +355,7 @@ namespace Components
if (input == end)
{
Logger::Print("Warning: %s is not a valid input\n"
"Usage: %s optional <number of bots> or optional <\"all\">\n",
Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "{} is not a valid input\nUsage: {} optional <number of bots> or optional <\"all\">\n",
input, params->get(0));
return;
}
@ -381,7 +373,7 @@ namespace Components
}
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);
});
@ -389,9 +381,9 @@ namespace Components
Bots::AddMethods();
// 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;
}

View File

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

View File

@ -7,6 +7,12 @@ namespace Components
Dvar::Var Branding::CGDrawVersionY;
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()
{
// Default values
@ -45,15 +51,9 @@ namespace Components
const char* Branding::GetVersionString()
{
#ifdef _DEBUG
const auto* buildType = "IW4x_DEV MP";
#else
const auto* buildType = "IW4x MP";
#endif
// IW4x is technically a beta
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;
}
@ -75,7 +75,7 @@ namespace Components
[[maybe_unused]] float y, float min, float max, [[maybe_unused]] int flags, const char* description)
{
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()
@ -95,7 +95,7 @@ namespace Components
Branding::Branding()
{
Dvar::OnInit(Branding::RegisterBrandingDvars);
Branding::RegisterBrandingDvars();
// UI version string
Utils::Hook::Set<const char*>(0x43F73B, "IW4x: " VERSION);
@ -103,6 +103,14 @@ namespace Components
// Short version dvar
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();
// Version string color

View File

@ -44,15 +44,12 @@ namespace Components
Bullet::Bullet()
{
Dvar::OnInit([]
{
BGSurfacePenetration = Dvar::Register<float>("bg_surfacePenetration", 0.0f,
0.0f, std::numeric_limits<float>::max(), Game::dvar_flag::DVAR_CODINFO,
"Set to a value greater than 0 to override the surface penetration depth");
BGBulletRange = Game::Dvar_RegisterFloat("bg_bulletRange", 8192.0f,
0.0f, std::numeric_limits<float>::max(), Game::dvar_flag::DVAR_CODINFO,
"Max range used when calculating the bullet end position");
});
BGSurfacePenetration = Dvar::Register<float>("bg_surfacePenetration", 0.0f,
0.0f, std::numeric_limits<float>::max(), Game::dvar_flag::DVAR_CODINFO,
"Set to a value greater than 0 to override the surface penetration depth");
BGBulletRange = Game::Dvar_RegisterFloat("bg_bulletRange", 8192.0f,
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(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));
}
std::string command = Utils::String::VA("%c customTitles \"%s\"", 21, list.data());
Game::SV_GameSendServerCommand(-1, 0, command.data());
const auto* command = Utils::String::VA("%c customTitles \"%s\"", 21, list.data());
Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, command);
}
void CardTitles::ParseCustomTitles(const char* msg)
@ -190,10 +190,10 @@ namespace Components
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");
});
}, Scheduler::Pipeline::MAIN);
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
{
Game::dvar_t** Chat::cg_chatHeight = reinterpret_cast<Game::dvar_t**>(0x7ED398);
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);
bool Chat::SendChat;
@ -11,23 +13,34 @@ namespace Components
std::mutex Chat::AccessMutex;
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] == '/')
{
Chat::SendChat = false;
SendChat = false;
text[1] = text[0];
++text;
}
std::unique_lock<std::mutex> lock(Chat::AccessMutex);
if (Chat::MuteList.find(Game::svs_clients[player->s.number].steamID) != Chat::MuteList.end())
std::unique_lock lock(AccessMutex);
if (MuteList.contains(Game::svs_clients[player->s.number].steamID))
{
lock.unlock();
Chat::SendChat = false;
Game::SV_GameSendServerCommand(player->s.number, 0,
SendChat = false;
Game::SV_GameSendServerCommand(player->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"You are muted\"", 0x65));
}
@ -37,6 +50,21 @@ namespace Components
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);
Game::Scr_AddEntity(player);
@ -50,21 +78,22 @@ namespace Components
{
__asm
{
mov eax, [esp + 100h + 10h]
mov eax, [esp + 0x100 + 0x10]
push eax
pushad
push [esp + 100h + 28h]
push eax
call Chat::EvaluateSay
add esp, 8h
push [esp + 0x100 + 0x30] // mode
push [esp + 0x100 + 0x2C] // player
push eax // text
call EvaluateSay
add esp, 0xC
mov [esp + 20h], eax
mov [esp + 0x20], eax
popad
pop eax
mov [esp + 100h + 10h], eax
mov [esp + 0x100 + 0x10], eax
jmp PlayerName::CleanStrStub
}
@ -78,7 +107,7 @@ namespace Components
push eax
xor eax, eax
mov al, Chat::SendChat
mov al, SendChat
test al, al
jnz return
@ -215,42 +244,42 @@ namespace Components
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();
Logger::Print("%s was muted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, 0,
Logger::Print("{} was muted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"You were muted\"", 0x65));
return;
}
lock.unlock();
Logger::Print("%s is already muted\n", client->name);
Game::SV_GameSendServerCommand(-1, 0,
Logger::Print("{} is already muted\n", client->name);
Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"%s is already muted\"", 0x65, client->name));
}
void Chat::UnmuteClient(const Game::client_t* client)
{
Chat::UnmuteInternal(client->steamID);
UnmuteInternal(client->steamID);
Logger::Print("%s was unmuted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, 0,
Logger::Print("{} was unmuted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, Game::SV_CMD_CAN_IGNORE,
Utils::String::VA("%c \"You were unmuted\"", 0x65));
}
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)
Chat::MuteList.clear();
MuteList.clear();
else
Chat::MuteList.erase(id);
MuteList.erase(id);
}
void Chat::AddChatCommands()
@ -266,14 +295,14 @@ namespace Components
const auto* cmd = params->get(0);
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;
}
const auto* client = Game::SV_GetPlayerByNum();
if (client != nullptr)
{
Chat::MuteClient(client);
MuteClient(client);
}
});
@ -288,7 +317,7 @@ namespace Components
const auto* cmd = params->get(0);
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;
}
@ -296,30 +325,92 @@ namespace Components
if (client != nullptr)
{
Chat::UnmuteClient(client);
UnmuteClient(client);
return;
}
if (std::strcmp(params->get(1), "all") == 0)
{
Logger::Print("All players were unmuted\n");
Chat::UnmuteInternal(0, true);
UnmuteInternal(0, true);
}
else
{
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()
{
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");
Chat::AddChatCommands();
});
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");
Scheduler::OnGameInitialized(AddChatCommands, Scheduler::Pipeline::SERVER);
// Intercept chat sending
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
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();
private:
static Game::dvar_t** cg_chatHeight;
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 bool SendChat;
@ -18,7 +21,10 @@ namespace Components
static std::mutex AccessMutex;
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 PostSayStub();
@ -31,5 +37,9 @@ namespace Components
static void UnmuteClient(const Game::client_t* client);
static void UnmuteInternal(const std::uint64_t id, bool everyone = false);
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());
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)
@ -73,10 +73,11 @@ namespace Components
ClanTags::ClanTags()
{
// 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
ServerCommands::OnCommand(22, [](Command::Params* params)

View File

@ -10,15 +10,15 @@ namespace Components
if (!Dvar::Var("sv_cheats").get<bool>())
{
Logger::Print("CheatsOk: cheats are disabled!\n");
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"GAME_CHEATSNOTENABLED\"", 0x65));
Logger::Debug("Cheats are disabled!");
Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"GAME_CHEATSNOTENABLED\"", 0x65));
return false;
}
if (ent->health < 1)
{
Logger::Print("CheatsOk: entity %i must be alive to use this command!\n", entNum);
Game::SV_GameSendServerCommand(entNum, 0, Utils::String::VA("%c \"GAME_MUSTBEALIVECOMMAND\"", 0x65));
Logger::Debug("Entity {} must be alive to use this command!", entNum);
Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"GAME_MUSTBEALIVECOMMAND\"", 0x65));
return false;
}
@ -38,7 +38,7 @@ namespace Components
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;
}
@ -64,9 +64,9 @@ namespace Components
ent->client->flags ^= Game::PLAYER_FLAG_NOCLIP;
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"));
});
@ -78,9 +78,9 @@ namespace Components
ent->client->flags ^= Game::PLAYER_FLAG_UFO;
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"));
});
@ -92,9 +92,9 @@ namespace Components
ent->flags ^= Game::FL_GODMODE;
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"));
});
@ -106,9 +106,9 @@ namespace Components
ent->flags ^= Game::FL_DEMI_GODMODE;
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"));
});
@ -120,9 +120,9 @@ namespace Components
ent->flags ^= Game::FL_NOTARGET;
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"));
});
@ -137,7 +137,7 @@ namespace Components
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));
return;
}
@ -157,8 +157,90 @@ namespace Components
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);
});
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()
@ -180,7 +262,7 @@ namespace Components
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"
@ -208,7 +290,7 @@ namespace Components
strncpy_s(ent->client->visionName[visMode],
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));
});
@ -236,14 +318,33 @@ namespace Components
strncpy_s(ent->client->visionName[visMode],
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));
});
ClientCommand::Add("g_testCmd", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
assert(ent != nullptr);
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];
}
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);
if (Command::FunctionMap.find(command) == Command::FunctionMap.end())
if (!Command::FunctionMap.contains(command))
{
Command::AddRaw(name, Command::MainCallback);
}
@ -72,11 +80,11 @@ namespace Components
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())
{
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
__debugbreak();
@ -87,7 +95,7 @@ namespace Components
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);
@ -95,7 +103,7 @@ namespace Components
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)
@ -168,17 +176,4 @@ namespace Components
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
{
public:
static_assert(sizeof(Game::cmd_function_t) == 0x18);
class Params
{
public:
@ -45,14 +47,14 @@ namespace Components
int nesting_;
};
Command();
Command() = default;
static Game::cmd_function_t* Allocate();
static void Add(const char* name, std::function<void(Command::Params*)> callback);
static void AddSV(const char* name, std::function<void(Command::Params*)> callback);
static void Add(const char* name, const std::function<void()>& 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 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 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*)>> FunctionMapSV;
static void AddRawSV(const char* name, void(*callback)());
static void MainCallback();
static void MainCallbackSV();
};

View File

@ -213,7 +213,7 @@ namespace Components
});
// Invocation handler
Scheduler::OnReady(ConnectProtocol::Invocation);
Scheduler::OnGameInitialized(ConnectProtocol::Invocation, Scheduler::Pipeline::MAIN);
ConnectProtocol::InstallProtocol();
ConnectProtocol::EvaluateProtocol();
@ -232,10 +232,10 @@ namespace Components
// Only skip intro here, invocation will be done later.
Utils::Hook::Set<BYTE>(0x60BECF, 0xEB);
Scheduler::OnDelay([]()
Scheduler::Once([]
{
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::Width = 80;
char Console::LineBuffer[1024] = { 0 };
char Console::LineBuffer2[1024] = { 0 };
char Console::LineBuffer[1024] = {0};
char Console::LineBuffer2[1024] = {0};
int Console::LineBufferIndex = 0;
bool Console::HasConsole = false;
@ -24,7 +24,7 @@ namespace Components
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;
return Game::FS_GetFileList(path, extension, behavior, numfiles, allocTrackType);
@ -44,8 +44,8 @@ namespace Components
void Console::RefreshStatus()
{
std::string mapname = Dvar::Var("mapname").get<const char*>();
std::string hostname = TextRenderer::StripColors(Dvar::Var("sv_hostname").get<const char*>());
const auto mapname = Dvar::Var("mapname").get<std::string>();
const auto hostname = TextRenderer::StripColors(Dvar::Var("sv_hostname").get<std::string>());
if (Console::HasConsole)
{
@ -72,7 +72,7 @@ namespace Components
}
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);
}
else if (IsWindow(Console::GetWindow()) != FALSE)
@ -318,17 +318,16 @@ namespace Components
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_start(va, format);
_vsnprintf_s(buffer, sizeof(buffer), format, va);
va_start(va, fmt);
_vsnprintf_s(buf, _TRUNCATE, fmt, va);
va_end(va);
Game::Com_Printf(0, "ERROR:\n");
Game::Com_Printf(0, buffer);
Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}", buf);
Console::RefreshOutput();
@ -426,13 +425,13 @@ namespace Components
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_start(ap, format);
_vsnprintf_s(buffer, sizeof(buffer), format, ap);
va_start(ap, fmt);
_vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
va_end(ap);
perror(buffer);
@ -520,7 +519,7 @@ namespace Components
{ "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)
{
@ -544,7 +543,10 @@ namespace Components
static float consoleColor[] = { 0.70f, 1.00f, 0.00f, 1.00f };
Utils::Hook::Set<float*>(0x5A451A, 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
Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).install()->quick();
Utils::Hook(0x4F65A5, Console::ToggleConsole, HOOK_JUMP).install()->quick();
@ -577,7 +579,7 @@ namespace Components
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!
@ -619,10 +621,10 @@ namespace Components
}
}, HOOK_CALL).install()->quick();
Scheduler::OnFrame([]()
Scheduler::Loop([]
{
Console::LastRefresh = Game::Sys_Milliseconds();
});
}, Scheduler::Pipeline::MAIN);
}
else if (Dedicated::IsEnabled()/* || ZoneBuilder::IsEnabled()*/)
{

View File

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

View File

@ -573,7 +573,7 @@ namespace Components
// TODO: Fix the actual error!
if (IsBadReadPtr(pConstantData, Vector4fCount * 16))
{
//Logger::Print("Invalid shader constant array!\n");
Logger::Debug("Invalid shader constant array!");
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];
Dvar::Var Dedicated::SVRandomMapRotation;
Dvar::Var Dedicated::SVLanOnly;
Dvar::Var Dedicated::COMLogFilter;
bool Dedicated::IsEnabled()
{
@ -35,7 +35,7 @@ namespace Components
std::memcpy(reinterpret_cast<void*>(0x66E1CB0), &fastfiles, sizeof(fastfiles));
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(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)
{
static bool partyEnable;
static std::string mapname;
partyEnable = Dvar::Var("party_enable").get<bool>();
mapname = Dvar::Var("mapname").get<std::string>();
Scheduler::Once([]()
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 (mapname.empty()) mapname = "mp_rust";
Command::Execute(Utils::String::VA("map %s", mapname.data()), false);
mapname.clear();
}
});
}, Scheduler::Pipeline::SERVER);
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()
{
// 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));
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");
}
__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)
{
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()
{
// Map rotation
Utils::Hook::Set(0x4152E8, Dedicated::MapRotate);
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");
Dedicated::COMLogFilter = Dvar::Register<bool>("com_logFilter", true,
Game::dvar_flag::DVAR_LATCH, "Removes ~95% of unneeded lines from the log");
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
{
// 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();
@ -361,112 +273,33 @@ namespace Components
// don't load the config
Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB);
// Dedicated frame handler
Utils::Hook(0x4B0F81, Dedicated::FrameStub, HOOK_CALL).install()->quick();
// Intercept time wrapping
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)
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
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick();
// Transmit custom data
Scheduler::OnFrame([]()
Scheduler::Loop([]
{
static Utils::Time::Interval interval;
if (interval.elapsed(10s))
{
interval.update();
CardTitles::SendCustomTitlesToClients();
//Clantags::SendClantagsToClients();
}
});
CardTitles::SendCustomTitlesToClients();
//Clantags::SendClantagsToClients();
}, Scheduler::Pipeline::SERVER, 10s);
// Heartbeats
Scheduler::Once(Dedicated::Heartbeat);
Scheduler::OnFrame([]()
{
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());
});
});
Scheduler::Once(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER);
Scheduler::Loop(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER, 2min);
}
}
else
@ -495,18 +328,12 @@ namespace Components
});
}
Scheduler::OnFrame([]()
Scheduler::Loop([]
{
if (Dvar::Var("sv_running").get<bool>())
{
static Utils::Time::Interval interval;
if (interval.elapsed(15s))
{
interval.update();
Dedicated::TransmitGuids();
}
Dedicated::TransmitGuids();
}
});
}, Scheduler::Pipeline::SERVER, 15s);
}
}

View File

@ -9,27 +9,24 @@ namespace Components
static SteamID PlayerGuids[18][2];
static Dvar::Var SVLanOnly;
static Dvar::Var COMLogFilter;
static bool IsEnabled();
static void Heartbeat();
private:
static Dvar::Var SVRandomMapRotation;
static void RandomizeMapRotation();
static void MapRotate();
static void InitDedicatedServer();
static void PostInitialization();
static void PostInitializationStub();
static void FrameStub();
static void TransmitGuids();
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 void AddDedicatedCommands();
};
}

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