commit
7473844a4c
3
.github/CODEOWNERS
vendored
Normal file
3
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
* @XLabsProject/Developers
|
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -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
|
||||
|
31
CHANGELOG.md
31
CHANGELOG.md
@ -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
|
||||
|
||||
|
@ -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
1
deps/GSL
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d9fc52e20e32fcc804502480a781120b210afd41
|
19
deps/premake/gsl.lua
vendored
Normal file
19
deps/premake/gsl.lua
vendored
Normal 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)
|
3
deps/premake/json11.lua
vendored
3
deps/premake/json11.lua
vendored
@ -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
2
deps/protobuf
vendored
@ -1 +1 @@
|
||||
Subproject commit 5500c72c5b616da9f0125bcfab513987a1226e2b
|
||||
Subproject commit 6e9e60367d8744e86856590d8ea0e793c61deeec
|
12
premake5.lua
12
premake5.lua
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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*)
|
||||
{
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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>();
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IGameWorldMp.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IGameWorldSp.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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>();
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "ILocalizeEntry.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IMapEnts.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IPhysCollmap.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IPhysPreset.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IRawFile.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "ISndCurve.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IStringTable.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "IStructuredDataDefSet.hpp"
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
51
src/Components/Modules/Ceg.cpp
Normal file
51
src/Components/Modules/Ceg.cpp
Normal 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);
|
||||
}
|
||||
}
|
10
src/Components/Modules/Ceg.hpp
Normal file
10
src/Components/Modules/Ceg.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class Ceg : public Component
|
||||
{
|
||||
public:
|
||||
Ceg();
|
||||
};
|
||||
}
|
@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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(¶ms);
|
||||
}
|
||||
}
|
||||
|
||||
Command::Command()
|
||||
{
|
||||
AssertSize(Game::cmd_function_t, 24);
|
||||
|
||||
Command::Add("openLink", [](Command::Params* params)
|
||||
{
|
||||
if (params->size() > 1)
|
||||
{
|
||||
Utils::OpenUrl(params->get(1));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()*/)
|
||||
{
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
240
src/Components/Modules/Debug.cpp
Normal file
240
src/Components/Modules/Debug.cpp
Normal 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();
|
||||
}
|
||||
}
|
36
src/Components/Modules/Debug.hpp
Normal file
36
src/Components/Modules/Debug.hpp
Normal 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();
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user