Merge branch 'develop' into branding
This commit is contained in:
commit
144978e758
64
CHANGELOG.md
64
CHANGELOG.md
@ -4,6 +4,70 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/).
|
The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [0.7.0] - 2022-01-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added controller support (#75)
|
||||||
|
- Added aim assist for controllers (#75)
|
||||||
|
- Unlock camera_thirdPersonCrosshairOffset Dvar (#68)
|
||||||
|
- Added support for building custom Fonts with Zonebuilder (#88)
|
||||||
|
- Added colorblind friendly team colors (#101)
|
||||||
|
- Added emojis based on titlecards and emblems to use in the chat and server names Example: `:nuke:` (#130)
|
||||||
|
- Upon leaving a server 'archive' dvars (saved in the config file) will be reset to the value they had prior to joining the server (#134)
|
||||||
|
- Implement muteClient command for the game chat (#159)
|
||||||
|
- Implement unmute command for the game chat (#159)
|
||||||
|
- Add sv_allowAimAssist Dvar (#75)
|
||||||
|
- Add sv_allowColoredNames (#130)
|
||||||
|
- Add sv_randomMapRotation Dvar (#146)
|
||||||
|
- Add rcon_log_requests Dvar (#195)
|
||||||
|
- Add player_duckedSpeedScale Dvar (#141)
|
||||||
|
- Add player_proneSpeedScale Dvar (#141)
|
||||||
|
- Add cg_ufo_scaler Dvar (#158)
|
||||||
|
- Add cg_noclip_scaler Dvar (#158)
|
||||||
|
- Add bg_bouncesAllAngles Dvar (#158)
|
||||||
|
- Add bg_rocketJump Dvar (#158)
|
||||||
|
- Add bg_elevators Dvar (#156)
|
||||||
|
- Implement noclip client command (#152)
|
||||||
|
- Implement ufo client command (#152)
|
||||||
|
- Implement God client command (#152)
|
||||||
|
- Implement demigod client command (#152)
|
||||||
|
- Implement notarget client command (#152)
|
||||||
|
- Add noclip GSC Function (#152)
|
||||||
|
- Add ufo GSC Function (#152)
|
||||||
|
- Add God GSC Function (#152)
|
||||||
|
- Add demigod GSC Function (#152)
|
||||||
|
- Add notarget GSC Function (#152)
|
||||||
|
- Add replaceFunc GSC Function (#144)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Renamed sv_enableBounces to bg_bounces (#158)
|
||||||
|
- Renamed g_playerCollision to bg_playerEjection (#158)
|
||||||
|
- Renamed g_playerEjection to bg_playerCollision (#158)
|
||||||
|
- Setviewpos client command works outside private matches (#163)
|
||||||
|
- Ufo client command works outside of private matches (#152)
|
||||||
|
- Noclip client command works outside of private matches (#152)
|
||||||
|
- If a player name is less than 3 characters server will change it to `Unknown Soldier` (#130)
|
||||||
|
- scr_player_forceautoassign Dvar is false by default
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed issue where CoD:O DLC Maps caused DirectX crash following `vid_restart` (#37)
|
||||||
|
- Fixes and improvements to Zonebuilder
|
||||||
|
- Fixed issue where the game froze following base game script throwing an error (#74)
|
||||||
|
- Fixed RCon on party servers (#91 - #95)
|
||||||
|
- Fixed slow motion during final killcams (#111 - #107)
|
||||||
|
- Fixed sound issue that causes the game to freeze (#106)
|
||||||
|
- Fixed issue where materials strings found in hostnames, player names, chat etc. caused the game to crash (#113)
|
||||||
|
- Fixed issue with servers displaying an invalid player count (#144)
|
||||||
|
|
||||||
|
### Known issues
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
## [0.6.1] - 2020-12-23
|
## [0.6.1] - 2020-12-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
| `--force-unit-tests` | Always compile unit tests. |
|
| `--force-unit-tests` | Always compile unit tests. |
|
||||||
| `--force-exception-handler` | Install custom unhandled exception handler even for Debug builds. |
|
| `--force-exception-handler` | Install custom unhandled exception handler even for Debug builds. |
|
||||||
| `--force-minidump-upload` | Upload minidumps even for Debug builds. |
|
| `--force-minidump-upload` | Upload minidumps even for Debug builds. |
|
||||||
| `--disable-bitmessage` | Disable use of BitMessage completely. |
|
|
||||||
| `--disable-base128` | Disable base128 encoding for minidumps. |
|
|
||||||
| `--no-new-structure` | Do not use new virtual path structure (separating headers and source files). |
|
|
||||||
| `--iw4x-zones` | Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches. |
|
| `--iw4x-zones` | Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches. |
|
||||||
|
|
||||||
## Command line arguments
|
## Command line arguments
|
||||||
|
2
deps/libtommath
vendored
2
deps/libtommath
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 5108f12350b6daa4aa5dbc846517ad1db2f8388a
|
Subproject commit 4b47368501321c795d5b54d87a5bab35a21a7940
|
@ -83,6 +83,7 @@ namespace Components
|
|||||||
Loader::Register(new ModelSurfs());
|
Loader::Register(new ModelSurfs());
|
||||||
Loader::Register(new PlayerName());
|
Loader::Register(new PlayerName());
|
||||||
Loader::Register(new QuickPatch());
|
Loader::Register(new QuickPatch());
|
||||||
|
Loader::Register(new Security());
|
||||||
Loader::Register(new ServerInfo());
|
Loader::Register(new ServerInfo());
|
||||||
Loader::Register(new ServerList());
|
Loader::Register(new ServerList());
|
||||||
Loader::Register(new SlowMotion());
|
Loader::Register(new SlowMotion());
|
||||||
@ -105,6 +106,7 @@ namespace Components
|
|||||||
Loader::Register(new ClientCommand());
|
Loader::Register(new ClientCommand());
|
||||||
Loader::Register(new ScriptExtension());
|
Loader::Register(new ScriptExtension());
|
||||||
Loader::Register(new Branding());
|
Loader::Register(new Branding());
|
||||||
|
Loader::Register(new RawMouse());
|
||||||
|
|
||||||
Loader::Pregame = false;
|
Loader::Pregame = false;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@ namespace Components
|
|||||||
#include "Modules/Network.hpp"
|
#include "Modules/Network.hpp"
|
||||||
#include "Modules/Theatre.hpp"
|
#include "Modules/Theatre.hpp"
|
||||||
#include "Modules/QuickPatch.hpp"
|
#include "Modules/QuickPatch.hpp"
|
||||||
|
#include "Modules/Security.hpp"
|
||||||
#include "Modules/Node.hpp"
|
#include "Modules/Node.hpp"
|
||||||
#include "Modules/RCon.hpp"
|
#include "Modules/RCon.hpp"
|
||||||
#include "Modules/Party.hpp" // Destroys the order, but requires network classes :D
|
#include "Modules/Party.hpp" // Destroys the order, but requires network classes :D
|
||||||
@ -136,3 +137,4 @@ namespace Components
|
|||||||
#include "Modules/Gamepad.hpp"
|
#include "Modules/Gamepad.hpp"
|
||||||
#include "Modules/ScriptExtension.hpp"
|
#include "Modules/ScriptExtension.hpp"
|
||||||
#include "Modules/Branding.hpp"
|
#include "Modules/Branding.hpp"
|
||||||
|
#include "Modules/RawMouse.hpp"
|
||||||
|
@ -28,7 +28,7 @@ namespace Components
|
|||||||
if (!rawfile || Game::DB_IsXAssetDefault(Game::XAssetType::ASSET_TYPE_RAWFILE, this->filePath.data())) return;
|
if (!rawfile || Game::DB_IsXAssetDefault(Game::XAssetType::ASSET_TYPE_RAWFILE, this->filePath.data())) return;
|
||||||
|
|
||||||
this->buffer.resize(Game::DB_GetRawFileLen(rawfile));
|
this->buffer.resize(Game::DB_GetRawFileLen(rawfile));
|
||||||
Game::DB_GetRawBuffer(rawfile, const_cast<char*>(this->buffer.data()), this->buffer.size());
|
Game::DB_GetRawBuffer(rawfile, this->buffer.data(), static_cast<int>(this->buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystem::FileReader::FileReader(const std::string& file) : handle(0), name(file)
|
FileSystem::FileReader::FileReader(const std::string& file) : handle(0), name(file)
|
||||||
|
@ -77,16 +77,14 @@ namespace Components
|
|||||||
|
|
||||||
std::string Logger::Format(const char** message)
|
std::string Logger::Format(const char** message)
|
||||||
{
|
{
|
||||||
const size_t bufferSize = 0x10000;
|
char buffer[4096] = {0};
|
||||||
Utils::Memory::Allocator allocator;
|
|
||||||
char* buffer = allocator.allocateArray<char>(bufferSize);
|
|
||||||
|
|
||||||
va_list ap = reinterpret_cast<char*>(const_cast<char**>(&message[1]));
|
va_list ap = reinterpret_cast<char*>(const_cast<char**>(&message[1]));
|
||||||
//va_start(ap, *message);
|
|
||||||
_vsnprintf_s(buffer, bufferSize, bufferSize, *message, ap);
|
_vsnprintf_s(buffer, _TRUNCATE, *message, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return buffer;
|
return {buffer};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::Flush()
|
void Logger::Flush()
|
||||||
@ -138,8 +136,8 @@ namespace Components
|
|||||||
{
|
{
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
std::string buffer(data);
|
const std::string buffer(data);
|
||||||
for (auto& addr : Logger::LoggingAddresses[gLog & 1])
|
for (const auto& addr : Logger::LoggingAddresses[gLog & 1])
|
||||||
{
|
{
|
||||||
Network::SendCommand(addr, "print", buffer);
|
Network::SendCommand(addr, "print", buffer);
|
||||||
}
|
}
|
||||||
@ -373,9 +371,9 @@ namespace Components
|
|||||||
Logger::MessageMutex.unlock();
|
Logger::MessageMutex.unlock();
|
||||||
|
|
||||||
// Flush the console log
|
// Flush the console log
|
||||||
if (int fh = *reinterpret_cast<int*>(0x1AD8F28))
|
if (const auto logfile = *reinterpret_cast<int*>(0x1AD8F28))
|
||||||
{
|
{
|
||||||
Game::FS_FCloseFile(fh);
|
Game::FS_FCloseFile(logfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Dvar::Var Movement::PlayerDuckedSpeedScale;
|
|
||||||
Dvar::Var Movement::PlayerLastStandCrawlSpeedScale;
|
|
||||||
Dvar::Var Movement::PlayerProneSpeedScale;
|
|
||||||
Dvar::Var Movement::PlayerSpectateSpeedScale;
|
Dvar::Var Movement::PlayerSpectateSpeedScale;
|
||||||
Dvar::Var Movement::CGUfoScaler;
|
Dvar::Var Movement::CGUfoScaler;
|
||||||
Dvar::Var Movement::CGNoclipScaler;
|
Dvar::Var Movement::CGNoclipScaler;
|
||||||
@ -13,99 +10,50 @@ namespace Components
|
|||||||
Dvar::Var Movement::BGPlayerEjection;
|
Dvar::Var Movement::BGPlayerEjection;
|
||||||
Dvar::Var Movement::BGPlayerCollision;
|
Dvar::Var Movement::BGPlayerCollision;
|
||||||
Game::dvar_t* Movement::BGBounces;
|
Game::dvar_t* Movement::BGBounces;
|
||||||
|
Game::dvar_t* Movement::PlayerDuckedSpeedScale;
|
||||||
|
Game::dvar_t* Movement::PlayerProneSpeedScale;
|
||||||
|
|
||||||
float Movement::PM_CmdScaleForStance(const Game::pmove_s* pm)
|
__declspec(naked) void Movement::PM_PlayerDuckedSpeedScaleStub()
|
||||||
{
|
|
||||||
assert(pm->ps != nullptr);
|
|
||||||
|
|
||||||
const auto* playerState = pm->ps;
|
|
||||||
float scale;
|
|
||||||
|
|
||||||
if (playerState->viewHeightLerpTime != 0 && playerState->viewHeightLerpTarget == 0xB)
|
|
||||||
{
|
|
||||||
scale = pm->cmd.serverTime - playerState->viewHeightLerpTime / 400.0f;
|
|
||||||
|
|
||||||
if (0.0f <= scale)
|
|
||||||
{
|
|
||||||
if (scale > 1.0f)
|
|
||||||
{
|
|
||||||
scale = 1.0f;
|
|
||||||
return scale * 0.15f + (1.0f - scale) * 0.65f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale != 0.0f)
|
|
||||||
{
|
|
||||||
return scale * 0.15f + (1.0f - scale) * 0.65f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((playerState->viewHeightLerpTime != 0 && playerState->viewHeightLerpTarget == 0x28) &&
|
|
||||||
playerState->viewHeightLerpDown == 0)
|
|
||||||
{
|
|
||||||
scale = 400.0f / pm->cmd.serverTime - playerState->viewHeightLerpTime;
|
|
||||||
|
|
||||||
if (0.0f <= scale)
|
|
||||||
{
|
|
||||||
if (scale > 1.0f)
|
|
||||||
{
|
|
||||||
scale = 1.0f;
|
|
||||||
}
|
|
||||||
else if (scale != 0.0f)
|
|
||||||
{
|
|
||||||
return scale * 0.65f + (1.0f - scale) * 0.15f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scale = 1.0f;
|
|
||||||
const auto stance = Game::PM_GetEffectiveStance(playerState);
|
|
||||||
|
|
||||||
if (stance == Game::PM_EFF_STANCE_PRONE)
|
|
||||||
{
|
|
||||||
scale = Movement::PlayerProneSpeedScale.get<float>();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (stance == Game::PM_EFF_STANCE_DUCKED)
|
|
||||||
{
|
|
||||||
scale = Movement::PlayerDuckedSpeedScale.get<float>();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (stance == Game::PM_EFF_STANCE_LASTSTANDCRAWL)
|
|
||||||
{
|
|
||||||
scale = Movement::PlayerLastStandCrawlSpeedScale.get<float>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) void Movement::PM_CmdScaleForStanceStub()
|
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
pushad
|
push eax
|
||||||
|
mov eax, Movement::PlayerDuckedSpeedScale
|
||||||
|
fld dword ptr [eax + 0x10] // dvar_t.current.value
|
||||||
|
pop eax
|
||||||
|
|
||||||
push edx
|
// Game's code
|
||||||
call Movement::PM_CmdScaleForStance // pm
|
pop ecx
|
||||||
add esp, 4
|
|
||||||
|
|
||||||
popad
|
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float Movement::PM_MoveScale(Game::playerState_s* ps, float forwardmove,
|
__declspec(naked) void Movement::PM_PlayerProneSpeedScaleStub()
|
||||||
float rightmove, float upmove)
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
push eax
|
||||||
|
mov eax, Movement::PlayerProneSpeedScale
|
||||||
|
fld dword ptr [eax + 0x10] // dvar_t.current.value
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
// Game's code
|
||||||
|
pop ecx
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float Movement::PM_MoveScale(Game::playerState_s* ps, float fmove,
|
||||||
|
float rmove, float umove)
|
||||||
{
|
{
|
||||||
assert(ps != nullptr);
|
assert(ps != nullptr);
|
||||||
|
|
||||||
auto max = (std::fabsf(forwardmove) < std::fabsf(rightmove))
|
auto max = std::fabsf(fmove) < std::fabsf(rmove)
|
||||||
? std::fabsf(rightmove)
|
? std::fabsf(rmove) : std::fabsf(fmove);
|
||||||
: std::fabsf(forwardmove);
|
|
||||||
|
|
||||||
if (std::fabsf(upmove) > max)
|
if (std::fabsf(umove) > max)
|
||||||
{
|
{
|
||||||
max = std::fabsf(upmove);
|
max = std::fabsf(umove);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max == 0.0f)
|
if (max == 0.0f)
|
||||||
@ -113,28 +61,28 @@ namespace Components
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto total = std::sqrtf(forwardmove * forwardmove
|
auto total = std::sqrtf(fmove * fmove
|
||||||
+ rightmove * rightmove + upmove * upmove);
|
+ rmove * rmove + umove * umove);
|
||||||
auto scale = (ps->speed * max) / (127.0f * total);
|
auto scale = (static_cast<float>(ps->speed) * max) / (127.0f * total);
|
||||||
|
|
||||||
if (ps->pm_flags & Game::PMF_WALKING || ps->leanf != 0.0f)
|
if (ps->pm_flags & Game::PMF_WALKING || ps->leanf != 0.0f)
|
||||||
{
|
{
|
||||||
scale *= 0.4f;
|
scale *= 0.4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->pm_type == Game::PM_NOCLIP)
|
switch (ps->pm_type)
|
||||||
{
|
{
|
||||||
return scale * Movement::CGNoclipScaler.get<float>();
|
case Game::pmtype_t::PM_NOCLIP:
|
||||||
}
|
scale *= Movement::CGNoclipScaler.get<float>();
|
||||||
|
break;
|
||||||
if (ps->pm_type == Game::PM_UFO)
|
case Game::pmtype_t::PM_UFO:
|
||||||
{
|
scale *= Movement::CGUfoScaler.get<float>();
|
||||||
return scale * Movement::CGUfoScaler.get<float>();
|
break;
|
||||||
}
|
case Game::pmtype_t::PM_SPECTATOR:
|
||||||
|
scale *= Movement::PlayerSpectateSpeedScale.get<float>();
|
||||||
if (ps->pm_type == Game::PM_SPECTATOR)
|
break;
|
||||||
{
|
default:
|
||||||
return scale * Movement::PlayerSpectateSpeedScale.get<float>();
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return scale;
|
return scale;
|
||||||
@ -146,9 +94,9 @@ namespace Components
|
|||||||
{
|
{
|
||||||
pushad
|
pushad
|
||||||
|
|
||||||
push [esp + 0xC + 0x20] // upmove
|
push [esp + 0xC + 0x20] // umove
|
||||||
push [esp + 0xC + 0x20] // rightmove
|
push [esp + 0xC + 0x20] // rmove
|
||||||
push [esp + 0xC + 0x20] // forwardmove
|
push [esp + 0xC + 0x20] // fmove
|
||||||
push esi // ps
|
push esi // ps
|
||||||
call Movement::PM_MoveScale
|
call Movement::PM_MoveScale
|
||||||
add esp, 0x10
|
add esp, 0x10
|
||||||
@ -230,9 +178,9 @@ namespace Components
|
|||||||
|
|
||||||
if (ent->client != nullptr && BGRocketJump.get<bool>())
|
if (ent->client != nullptr && BGRocketJump.get<bool>())
|
||||||
{
|
{
|
||||||
ent->client->ps.velocity[0] += (0 - wp->forward[0]) * 64.0f;
|
ent->client->ps.velocity[0] += (0.0f - wp->forward[0]) * 64.0f;
|
||||||
ent->client->ps.velocity[1] += (0 - wp->forward[1]) * 64.0f;
|
ent->client->ps.velocity[1] += (0.0f - wp->forward[1]) * 64.0f;
|
||||||
ent->client->ps.velocity[2] += (0 - wp->forward[2]) * 64.0f;
|
ent->client->ps.velocity[2] += (0.0f - wp->forward[2]) * 64.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -260,15 +208,6 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::dvar_t* Movement::Dvar_RegisterLastStandSpeedScale(const char* dvarName, float value,
|
|
||||||
float min, float max, unsigned __int16 /*flags*/, const char* description)
|
|
||||||
{
|
|
||||||
Movement::PlayerLastStandCrawlSpeedScale = Dvar::Register<float>(dvarName, value,
|
|
||||||
min, max, Game::DVAR_CHEAT | Game::DVAR_CODINFO, description);
|
|
||||||
|
|
||||||
return Movement::PlayerLastStandCrawlSpeedScale.get<Game::dvar_t*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::dvar_t* Movement::Dvar_RegisterSpectateSpeedScale(const char* dvarName, float value,
|
Game::dvar_t* Movement::Dvar_RegisterSpectateSpeedScale(const char* dvarName, float value,
|
||||||
float min, float max, unsigned __int16 /*flags*/, const char* description)
|
float min, float max, unsigned __int16 /*flags*/, const char* description)
|
||||||
{
|
{
|
||||||
@ -290,11 +229,11 @@ namespace Components
|
|||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
Movement::PlayerDuckedSpeedScale = Dvar::Register<float>("player_duckedSpeedScale",
|
Movement::PlayerDuckedSpeedScale = Game::Dvar_RegisterFloat("player_duckedSpeedScale",
|
||||||
0.65f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
|
0.65f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
|
||||||
"The scale applied to the player speed when ducking");
|
"The scale applied to the player speed when ducking");
|
||||||
|
|
||||||
Movement::PlayerProneSpeedScale = Dvar::Register<float>("player_proneSpeedScale",
|
Movement::PlayerProneSpeedScale = Game::Dvar_RegisterFloat("player_proneSpeedScale",
|
||||||
0.15f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
|
0.15f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
|
||||||
"The scale applied to the player speed when crawling");
|
"The scale applied to the player speed when crawling");
|
||||||
|
|
||||||
@ -323,18 +262,13 @@ namespace Components
|
|||||||
true, Game::DVAR_CODINFO, "Push intersecting players away from each other");
|
true, Game::DVAR_CODINFO, "Push intersecting players away from each other");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hook PM_CmdScaleForStance in PM_CmdScale_Walk
|
|
||||||
Utils::Hook(0x572F34, Movement::PM_CmdScaleForStanceStub, HOOK_CALL).install()->quick();
|
|
||||||
|
|
||||||
//Hook PM_CmdScaleForStance in PM_GetMaxSpeed
|
|
||||||
Utils::Hook(0x57395F, Movement::PM_CmdScaleForStanceStub, HOOK_CALL).install()->quick();
|
|
||||||
|
|
||||||
// Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used.
|
|
||||||
Utils::Hook(0x448B66, Movement::Dvar_RegisterLastStandSpeedScale, HOOK_CALL).install()->quick();
|
|
||||||
|
|
||||||
// Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used.
|
// Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used.
|
||||||
Utils::Hook(0x448990, Movement::Dvar_RegisterSpectateSpeedScale, HOOK_CALL).install()->quick();
|
Utils::Hook(0x448990, Movement::Dvar_RegisterSpectateSpeedScale, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
|
// PM_CmdScaleForStance
|
||||||
|
Utils::Hook(0x572D9B, Movement::PM_PlayerDuckedSpeedScaleStub, HOOK_JUMP).install()->quick();
|
||||||
|
Utils::Hook(0x572DA5, Movement::PM_PlayerProneSpeedScaleStub, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
// Hook PM_MoveScale so we can add custom speed scale for Ufo and Noclip
|
// Hook PM_MoveScale so we can add custom speed scale for Ufo and Noclip
|
||||||
Utils::Hook(0x56F845, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick();
|
Utils::Hook(0x56F845, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick();
|
||||||
Utils::Hook(0x56FABD, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick();
|
Utils::Hook(0x56FABD, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick();
|
||||||
|
@ -10,9 +10,6 @@ namespace Components
|
|||||||
private:
|
private:
|
||||||
enum BouncesSettings { DISABLED, ENABLED, DOUBLE };
|
enum BouncesSettings { DISABLED, ENABLED, DOUBLE };
|
||||||
|
|
||||||
static Dvar::Var PlayerDuckedSpeedScale;
|
|
||||||
static Dvar::Var PlayerLastStandCrawlSpeedScale;
|
|
||||||
static Dvar::Var PlayerProneSpeedScale;
|
|
||||||
static Dvar::Var PlayerSpectateSpeedScale;
|
static Dvar::Var PlayerSpectateSpeedScale;
|
||||||
static Dvar::Var CGUfoScaler;
|
static Dvar::Var CGUfoScaler;
|
||||||
static Dvar::Var CGNoclipScaler;
|
static Dvar::Var CGNoclipScaler;
|
||||||
@ -22,11 +19,13 @@ namespace Components
|
|||||||
static Dvar::Var BGPlayerCollision;
|
static Dvar::Var BGPlayerCollision;
|
||||||
// Can't use Var class inside assembly stubs
|
// Can't use Var class inside assembly stubs
|
||||||
static Game::dvar_t* BGBounces;
|
static Game::dvar_t* BGBounces;
|
||||||
|
static Game::dvar_t* PlayerDuckedSpeedScale;
|
||||||
|
static Game::dvar_t* PlayerProneSpeedScale;
|
||||||
|
|
||||||
static float PM_CmdScaleForStance(const Game::pmove_s* move);
|
static void PM_PlayerDuckedSpeedScaleStub();
|
||||||
static void PM_CmdScaleForStanceStub();
|
static void PM_PlayerProneSpeedScaleStub();
|
||||||
|
|
||||||
static float PM_MoveScale(Game::playerState_s* ps, float forwardmove, float rightmove, float upmove);
|
static float PM_MoveScale(Game::playerState_s* ps, float fmove, float rmove, float umove);
|
||||||
static void PM_MoveScaleStub();
|
static void PM_MoveScaleStub();
|
||||||
|
|
||||||
// Bounce logic
|
// Bounce logic
|
||||||
@ -40,7 +39,6 @@ namespace Components
|
|||||||
static int StuckInClient_Hk(Game::gentity_s* self);
|
static int StuckInClient_Hk(Game::gentity_s* self);
|
||||||
static void CM_TransformedCapsuleTrace_Hk(Game::trace_t* results, const float* start, const float* end, const Game::Bounds* bounds, const Game::Bounds* capsule, int contents, const float* origin, const float* angles);
|
static void CM_TransformedCapsuleTrace_Hk(Game::trace_t* results, const float* start, const float* end, const Game::Bounds* bounds, const Game::Bounds* capsule, int contents, const float* origin, const float* angles);
|
||||||
|
|
||||||
static Game::dvar_t* Dvar_RegisterLastStandSpeedScale(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description);
|
|
||||||
static Game::dvar_t* Dvar_RegisterSpectateSpeedScale(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description);
|
static Game::dvar_t* Dvar_RegisterSpectateSpeedScale(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ namespace Components
|
|||||||
{
|
{
|
||||||
if (!sv_allowColoredNames.get<bool>())
|
if (!sv_allowColoredNames.get<bool>())
|
||||||
{
|
{
|
||||||
char nameBuffer[64] = { 0 };
|
char nameBuffer[64] = {0};
|
||||||
TextRenderer::StripColors(name, nameBuffer, sizeof(nameBuffer));
|
TextRenderer::StripColors(name, nameBuffer, sizeof(nameBuffer));
|
||||||
TextRenderer::StripAllTextIcons(nameBuffer, buffer, size);
|
TextRenderer::StripAllTextIcons(nameBuffer, buffer, size);
|
||||||
}
|
}
|
||||||
@ -26,12 +26,12 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(naked) void PlayerName::ClientUserinfoChanged()
|
__declspec(naked) void PlayerName::ClientCleanName()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, [esp + 4h] // length
|
mov eax, [esp + 4h] // length
|
||||||
//sub eax, 1
|
|
||||||
push eax
|
push eax
|
||||||
|
|
||||||
push ecx // name
|
push ecx // name
|
||||||
@ -53,12 +53,57 @@ namespace Components
|
|||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* PlayerName::CleanStrStub(char* string)
|
char* PlayerName::CleanStrStub(char* string)
|
||||||
{
|
{
|
||||||
TextRenderer::StripColors(string, string, strlen(string) + 1);
|
TextRenderer::StripColors(string, string, strlen(string) + 1);
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlayerName::CopyClientNameCheck(char* dest, const char* source, int size)
|
||||||
|
{
|
||||||
|
Utils::Hook::Call<void(char*, const char*, int)>(0x4D6F80)(dest, source, size); // I_strncpyz
|
||||||
|
|
||||||
|
auto i = 0;
|
||||||
|
while (i < size - 1 && dest[i] != '\0')
|
||||||
|
{
|
||||||
|
if (dest[i] > 125 || dest[i] < 32 || dest[i] == '%')
|
||||||
|
{
|
||||||
|
return false; // Illegal string
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void PlayerName::SV_UserinfoChangedStub()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
call CopyClientNameCheck
|
||||||
|
test al, al
|
||||||
|
|
||||||
|
jnz returnSafe
|
||||||
|
|
||||||
|
pushad
|
||||||
|
|
||||||
|
push 1 // tellThem
|
||||||
|
push INVALID_NAME_MSG // reason
|
||||||
|
push edi // drop
|
||||||
|
mov eax, 0x4D1600 // SV_DropClient
|
||||||
|
call eax
|
||||||
|
add esp, 0xC
|
||||||
|
|
||||||
|
popad
|
||||||
|
|
||||||
|
returnSafe:
|
||||||
|
push 0x401988
|
||||||
|
retn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PlayerName::PlayerName()
|
PlayerName::PlayerName()
|
||||||
{
|
{
|
||||||
sv_allowColoredNames = Dvar::Register<bool>("sv_allowColoredNames", true, Game::dvar_flag::DVAR_NONE, "Allow colored names on the server");
|
sv_allowColoredNames = Dvar::Register<bool>("sv_allowColoredNames", true, Game::dvar_flag::DVAR_NONE, "Allow colored names on the server");
|
||||||
@ -66,13 +111,17 @@ namespace Components
|
|||||||
// Disable SV_UpdateUserinfo_f, to block changing the name ingame
|
// Disable SV_UpdateUserinfo_f, to block changing the name ingame
|
||||||
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
|
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
|
||||||
|
|
||||||
// Allow colored names ingame
|
// Allow colored names ingame. Hook placed in ClientUserinfoChanged
|
||||||
Utils::Hook(0x5D8B40, ClientUserinfoChanged, HOOK_JUMP).install()->quick();
|
Utils::Hook(0x5D8B40, ClientCleanName, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
// Though, don't apply that to overhead names.
|
// Though, don't apply that to overhead names.
|
||||||
Utils::Hook(0x581932, GetClientName, HOOK_CALL).install()->quick();
|
Utils::Hook(0x581932, GetClientName, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
// Patch I_CleanStr
|
// Patch I_CleanStr
|
||||||
Utils::Hook(0x4AD470, CleanStrStub, HOOK_JUMP).install()->quick();
|
Utils::Hook(0x4AD470, CleanStrStub, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
|
// Detect invalid characters including '%' to prevent format string vulnerabilities.
|
||||||
|
// Kicks the player as soon as possible
|
||||||
|
Utils::Hook(0x401983, SV_UserinfoChangedStub, HOOK_JUMP).install()->quick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,14 @@ namespace Components
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static Dvar::Var sv_allowColoredNames;
|
static Dvar::Var sv_allowColoredNames;
|
||||||
|
// Message used when kicking players
|
||||||
|
static constexpr auto INVALID_NAME_MSG = "Invalid name detected";
|
||||||
|
|
||||||
static char* CleanStrStub(char* string);
|
static char* CleanStrStub(char* string);
|
||||||
static void ClientUserinfoChanged();
|
static void ClientCleanName();
|
||||||
static char* GetClientName(int localClientNum, int index, char* buf, size_t size);
|
static char* GetClientName(int localClientNum, int index, char* buf, size_t size);
|
||||||
|
|
||||||
|
static bool CopyClientNameCheck(char* dest, const char* source, int size);
|
||||||
|
static void SV_UserinfoChangedStub();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -47,62 +47,6 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int QuickPatch::MsgReadBitsCompressCheckSV(const char *from, char *to, int size)
|
|
||||||
{
|
|
||||||
static char buffer[0x8000];
|
|
||||||
|
|
||||||
if (size > 0x800) return 0;
|
|
||||||
size = Game::MSG_ReadBitsCompress(from, buffer, size);
|
|
||||||
|
|
||||||
if (size > 0x800) return 0;
|
|
||||||
std::memcpy(to, buffer, size);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QuickPatch::MsgReadBitsCompressCheckCL(const char *from, char *to, int size)
|
|
||||||
{
|
|
||||||
static char buffer[0x100000];
|
|
||||||
|
|
||||||
if (size > 0x20000) return 0;
|
|
||||||
size = Game::MSG_ReadBitsCompress(from, buffer, size);
|
|
||||||
|
|
||||||
if (size > 0x20000) return 0;
|
|
||||||
std::memcpy(to, buffer, size);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QuickPatch::SVCanReplaceServerCommand(Game::client_t* /*client*/, const char* /*cmd*/)
|
|
||||||
{
|
|
||||||
// This is a fix copied from V2. As I don't have time to investigate, let's simply trust them
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
long QuickPatch::AtolAdjustPlayerLimit(const char* string)
|
|
||||||
{
|
|
||||||
return std::min(atol(string), 18l);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QuickPatch::SelectStringTableEntryInDvarStub()
|
|
||||||
{
|
|
||||||
Command::ClientParams params;
|
|
||||||
|
|
||||||
if (params.size() >= 4)
|
|
||||||
{
|
|
||||||
const auto* dvarName = params[3];
|
|
||||||
const auto* dvar = Game::Dvar_FindVar(dvarName);
|
|
||||||
|
|
||||||
if (Command::Find(dvarName) ||
|
|
||||||
(dvar != nullptr && dvar->flags & (Game::DVAR_WRITEPROTECTED | Game::DVAR_CHEAT | Game::DVAR_READONLY)))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::CL_SelectStringTableEntryInDvar_f();
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) void QuickPatch::JavelinResetHookStub()
|
__declspec(naked) void QuickPatch::JavelinResetHookStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
@ -117,69 +61,6 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(naked) int QuickPatch::G_GetClientScore()
|
|
||||||
{
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
mov eax, [esp + 4] // index
|
|
||||||
mov ecx, ds : 1A831A8h // level: &g_clients
|
|
||||||
|
|
||||||
test ecx, ecx;
|
|
||||||
jz invalid_ptr;
|
|
||||||
|
|
||||||
imul eax, 366Ch
|
|
||||||
mov eax, [eax + ecx + 3134h]
|
|
||||||
ret
|
|
||||||
|
|
||||||
invalid_ptr:
|
|
||||||
xor eax, eax
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QuickPatch::InvalidNameCheck(char* dest, const char* source, int size)
|
|
||||||
{
|
|
||||||
Utils::Hook::Call<void(char*, const char*, int)>(0x4D6F80)(dest, source, size); // I_strncpyz
|
|
||||||
|
|
||||||
for (int i = 0; i < size - 1; i++)
|
|
||||||
{
|
|
||||||
if (!dest[i]) break;
|
|
||||||
|
|
||||||
if (dest[i] > 125 || dest[i] < 32 || dest[i] == '%')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) void QuickPatch::InvalidNameStub()
|
|
||||||
{
|
|
||||||
static const char* kick_reason = "Invalid name detected.";
|
|
||||||
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
call InvalidNameCheck;
|
|
||||||
test al, al
|
|
||||||
|
|
||||||
jnz returnSafe;
|
|
||||||
|
|
||||||
pushad;
|
|
||||||
push 1;
|
|
||||||
push kick_reason;
|
|
||||||
push edi;
|
|
||||||
mov eax, 0x004D1600; // SV_DropClientInternal
|
|
||||||
call eax;
|
|
||||||
add esp, 12;
|
|
||||||
popad;
|
|
||||||
|
|
||||||
returnSafe:
|
|
||||||
push 0x00401988;
|
|
||||||
retn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::dvar_t* QuickPatch::g_antilag;
|
Game::dvar_t* QuickPatch::g_antilag;
|
||||||
__declspec(naked) void QuickPatch::ClientEventsFireWeaponStub()
|
__declspec(naked) void QuickPatch::ClientEventsFireWeaponStub()
|
||||||
{
|
{
|
||||||
@ -372,9 +253,6 @@ namespace Components
|
|||||||
Utils::Hook(0x5D6D56, QuickPatch::ClientEventsFireWeaponStub, HOOK_JUMP).install()->quick();
|
Utils::Hook(0x5D6D56, QuickPatch::ClientEventsFireWeaponStub, HOOK_JUMP).install()->quick();
|
||||||
Utils::Hook(0x5D6D6A, QuickPatch::ClientEventsFireWeaponMeleeStub, HOOK_JUMP).install()->quick();
|
Utils::Hook(0x5D6D6A, QuickPatch::ClientEventsFireWeaponMeleeStub, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
// Disallow invalid player names
|
|
||||||
Utils::Hook(0x401983, QuickPatch::InvalidNameStub, HOOK_JUMP).install()->quick();
|
|
||||||
|
|
||||||
// Javelin fix
|
// Javelin fix
|
||||||
Utils::Hook(0x578F52, QuickPatch::JavelinResetHookStub, HOOK_JUMP).install()->quick();
|
Utils::Hook(0x578F52, QuickPatch::JavelinResetHookStub, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
@ -619,21 +497,6 @@ namespace Components
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Exploit fixes
|
|
||||||
Utils::Hook::Set<BYTE>(0x412370, 0xC3); // SV_SteamAuthClient
|
|
||||||
Utils::Hook::Set<BYTE>(0x5A8C70, 0xC3); // CL_HandleRelayPacket
|
|
||||||
Utils::Hook(0x414D92, QuickPatch::MsgReadBitsCompressCheckSV, HOOK_CALL).install()->quick(); // SV_ExecuteClientCommands
|
|
||||||
Utils::Hook(0x4A9F56, QuickPatch::MsgReadBitsCompressCheckCL, HOOK_CALL).install()->quick(); // CL_ParseServerMessage
|
|
||||||
Utils::Hook(0x407376, QuickPatch::SVCanReplaceServerCommand , HOOK_CALL).install()->quick(); // SV_CanReplaceServerCommand
|
|
||||||
Utils::Hook(0x5B67ED, QuickPatch::AtolAdjustPlayerLimit , HOOK_CALL).install()->quick(); // PartyHost_HandleJoinPartyRequest
|
|
||||||
Utils::Hook::Nop(0x41698E, 5); // Disable Svcmd_EntityList_f
|
|
||||||
|
|
||||||
// Patch selectStringTableEntryInDvar
|
|
||||||
Utils::Hook::Set(0x405959, QuickPatch::SelectStringTableEntryInDvarStub);
|
|
||||||
|
|
||||||
// Patch G_GetClientScore for uninitialised game
|
|
||||||
Utils::Hook(0x469AC0, QuickPatch::G_GetClientScore, HOOK_JUMP).install()->quick();
|
|
||||||
|
|
||||||
// Ignore call to print 'Offhand class mismatch when giving weapon...'
|
// Ignore call to print 'Offhand class mismatch when giving weapon...'
|
||||||
Utils::Hook(0x5D9047, 0x4BB9B0, HOOK_CALL).install()->quick();
|
Utils::Hook(0x5D9047, 0x4BB9B0, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
|
@ -12,21 +12,8 @@ namespace Components
|
|||||||
static void UnlockStats();
|
static void UnlockStats();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void SelectStringTableEntryInDvarStub();
|
|
||||||
|
|
||||||
static int SVCanReplaceServerCommand(Game::client_t *client, const char *cmd);
|
|
||||||
static int G_GetClientScore();
|
|
||||||
|
|
||||||
static int MsgReadBitsCompressCheckSV(const char *from, char *to, int size);
|
|
||||||
static int MsgReadBitsCompressCheckCL(const char *from, char *to, int size);
|
|
||||||
|
|
||||||
static long AtolAdjustPlayerLimit(const char* string);
|
|
||||||
|
|
||||||
static void JavelinResetHookStub();
|
static void JavelinResetHookStub();
|
||||||
|
|
||||||
static bool InvalidNameCheck(char* dest, const char* source, int size);
|
|
||||||
static void InvalidNameStub();
|
|
||||||
|
|
||||||
static Dvar::Var r_customAspectRatio;
|
static Dvar::Var r_customAspectRatio;
|
||||||
static Game::dvar_t* Dvar_RegisterAspectRatioDvar(const char* dvarName, const char** valueList, int defaultIndex, unsigned __int16 flags, const char* description);
|
static Game::dvar_t* Dvar_RegisterAspectRatioDvar(const char* dvarName, const char** valueList, int defaultIndex, unsigned __int16 flags, const char* description);
|
||||||
static void SetAspectRatioStub();
|
static void SetAspectRatioStub();
|
||||||
|
162
src/Components/Modules/RawMouse.cpp
Normal file
162
src/Components/Modules/RawMouse.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#include <STDInclude.hpp>
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
Dvar::Var RawMouse::M_RawInput;
|
||||||
|
int RawMouse::MouseRawX = 0;
|
||||||
|
int RawMouse::MouseRawY = 0;
|
||||||
|
|
||||||
|
void RawMouse::IN_ClampMouseMove()
|
||||||
|
{
|
||||||
|
tagRECT rc;
|
||||||
|
tagPOINT curPos;
|
||||||
|
|
||||||
|
GetCursorPos(&curPos);
|
||||||
|
GetWindowRect(Window::GetWindow(), &rc);
|
||||||
|
auto isClamped = false;
|
||||||
|
if (curPos.x >= rc.left)
|
||||||
|
{
|
||||||
|
if (curPos.x >= rc.right)
|
||||||
|
{
|
||||||
|
curPos.x = rc.right - 1;
|
||||||
|
isClamped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curPos.x = rc.left;
|
||||||
|
isClamped = true;
|
||||||
|
}
|
||||||
|
if (curPos.y >= rc.top)
|
||||||
|
{
|
||||||
|
if (curPos.y >= rc.bottom)
|
||||||
|
{
|
||||||
|
curPos.y = rc.bottom - 1;
|
||||||
|
isClamped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curPos.y = rc.top;
|
||||||
|
isClamped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isClamped)
|
||||||
|
{
|
||||||
|
SetCursorPos(curPos.x, curPos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RawMouse::OnRawInput(LPARAM lParam, WPARAM)
|
||||||
|
{
|
||||||
|
auto dwSize = sizeof(RAWINPUT);
|
||||||
|
static BYTE lpb[sizeof(RAWINPUT)];
|
||||||
|
|
||||||
|
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
|
||||||
|
|
||||||
|
auto* raw = reinterpret_cast<RAWINPUT*>(lpb);
|
||||||
|
if (raw->header.dwType == RIM_TYPEMOUSE)
|
||||||
|
{
|
||||||
|
// Is there's really absolute mouse on earth?
|
||||||
|
if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
|
||||||
|
{
|
||||||
|
MouseRawX = raw->data.mouse.lLastX;
|
||||||
|
MouseRawY = raw->data.mouse.lLastY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MouseRawX += raw->data.mouse.lLastX;
|
||||||
|
MouseRawY += raw->data.mouse.lLastY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawMouse::IN_RawMouseMove()
|
||||||
|
{
|
||||||
|
static auto r_fullscreen = Dvar::Var("r_fullscreen");
|
||||||
|
|
||||||
|
if (GetForegroundWindow() == Window::GetWindow())
|
||||||
|
{
|
||||||
|
if (r_fullscreen.get<bool>())
|
||||||
|
IN_ClampMouseMove();
|
||||||
|
|
||||||
|
static auto oldX = 0, oldY = 0;
|
||||||
|
|
||||||
|
auto dx = MouseRawX - oldX;
|
||||||
|
auto dy = MouseRawY - oldY;
|
||||||
|
|
||||||
|
oldX = MouseRawX;
|
||||||
|
oldY = MouseRawY;
|
||||||
|
|
||||||
|
// Don't use raw input for menu?
|
||||||
|
// Because it needs to call the ScreenToClient
|
||||||
|
tagPOINT curPos;
|
||||||
|
GetCursorPos(&curPos);
|
||||||
|
Game::s_wmv->oldPos = curPos;
|
||||||
|
ScreenToClient(Window::GetWindow(), &curPos);
|
||||||
|
|
||||||
|
auto recenterMouse = Game::CL_MouseEvent(curPos.x, curPos.y, dx, dy);
|
||||||
|
|
||||||
|
if (recenterMouse)
|
||||||
|
{
|
||||||
|
Game::IN_RecenterMouse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawMouse::IN_RawMouse_Init()
|
||||||
|
{
|
||||||
|
if (Window::GetWindow() && RawMouse::M_RawInput.get<bool>())
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
Logger::Print("Raw Mouse Init.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAWINPUTDEVICE Rid[1];
|
||||||
|
Rid[0].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
|
||||||
|
Rid[0].usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
|
||||||
|
Rid[0].dwFlags = RIDEV_INPUTSINK;
|
||||||
|
Rid[0].hwndTarget = Window::GetWindow();
|
||||||
|
|
||||||
|
RegisterRawInputDevices(Rid, ARRAYSIZE(Rid), sizeof(Rid[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawMouse::IN_Init()
|
||||||
|
{
|
||||||
|
Game::IN_Init();
|
||||||
|
IN_RawMouse_Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawMouse::IN_MouseMove()
|
||||||
|
{
|
||||||
|
if (RawMouse::M_RawInput.get<bool>())
|
||||||
|
{
|
||||||
|
IN_RawMouseMove();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game::IN_MouseMove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RawMouse::RawMouse()
|
||||||
|
{
|
||||||
|
Utils::Hook(0x475E65, RawMouse::IN_MouseMove, HOOK_JUMP).install()->quick();
|
||||||
|
Utils::Hook(0x475E8D, RawMouse::IN_MouseMove, HOOK_JUMP).install()->quick();
|
||||||
|
Utils::Hook(0x475E9E, RawMouse::IN_MouseMove, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
|
Utils::Hook(0x467C03, RawMouse::IN_Init, HOOK_CALL).install()->quick();
|
||||||
|
Utils::Hook(0x64D095, RawMouse::IN_Init, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
|
Dvar::OnInit([]()
|
||||||
|
{
|
||||||
|
RawMouse::M_RawInput = Dvar::Register<bool>("m_rawinput", true, Game::dvar_flag::DVAR_ARCHIVE, "Use raw mouse input, Improves accuracy & has better support for higher polling rates. Use in_restart to take effect if not enabled.");
|
||||||
|
});
|
||||||
|
|
||||||
|
Window::OnWndMessage(WM_INPUT, RawMouse::OnRawInput);
|
||||||
|
Window::OnCreate(RawMouse::IN_RawMouse_Init);
|
||||||
|
}
|
||||||
|
}
|
20
src/Components/Modules/RawMouse.hpp
Normal file
20
src/Components/Modules/RawMouse.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class RawMouse : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RawMouse();
|
||||||
|
private:
|
||||||
|
static Dvar::Var M_RawInput;
|
||||||
|
static int MouseRawX, MouseRawY;
|
||||||
|
|
||||||
|
static void IN_ClampMouseMove();
|
||||||
|
static BOOL OnRawInput(LPARAM lParam, WPARAM);
|
||||||
|
static void IN_RawMouseMove();
|
||||||
|
static void IN_RawMouse_Init();
|
||||||
|
static void IN_Init();
|
||||||
|
static void IN_MouseMove();
|
||||||
|
};
|
||||||
|
}
|
@ -4,6 +4,115 @@ namespace Components
|
|||||||
{
|
{
|
||||||
const char* ScriptExtension::QueryStrings[] = { R"(..)", R"(../)", R"(..\)" };
|
const char* ScriptExtension::QueryStrings[] = { R"(..)", R"(../)", R"(..\)" };
|
||||||
|
|
||||||
|
std::unordered_map<std::uint16_t, Game::ent_field_t> ScriptExtension::CustomEntityFields;
|
||||||
|
std::unordered_map<std::uint16_t, Game::client_fields_s> ScriptExtension::CustomClientFields;
|
||||||
|
|
||||||
|
void ScriptExtension::AddEntityField(const char* name, Game::fieldtype_t type,
|
||||||
|
const Game::ScriptCallbackEnt& setter, const Game::ScriptCallbackEnt& getter)
|
||||||
|
{
|
||||||
|
static std::uint16_t fieldOffsetStart = 15; // fields count
|
||||||
|
assert((fieldOffsetStart & Game::ENTFIELD_MASK) == Game::ENTFIELD_ENTITY);
|
||||||
|
|
||||||
|
ScriptExtension::CustomEntityFields[fieldOffsetStart] = {name, fieldOffsetStart, type, setter, getter};
|
||||||
|
++fieldOffsetStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptExtension::AddClientField(const char* name, Game::fieldtype_t type,
|
||||||
|
const Game::ScriptCallbackClient& setter, const Game::ScriptCallbackClient& getter)
|
||||||
|
{
|
||||||
|
static std::uint16_t fieldOffsetStart = 21; // fields count
|
||||||
|
assert((fieldOffsetStart & Game::ENTFIELD_MASK) == Game::ENTFIELD_ENTITY);
|
||||||
|
|
||||||
|
const auto offset = fieldOffsetStart | Game::ENTFIELD_CLIENT; // This is how client field's offset is calculated
|
||||||
|
|
||||||
|
// Use 'index' in 'array' as map key. It will be used later in Scr_SetObjectFieldStub
|
||||||
|
ScriptExtension::CustomClientFields[fieldOffsetStart] = {name, offset, type, setter, getter};
|
||||||
|
++fieldOffsetStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptExtension::GScr_AddFieldsForEntityStub()
|
||||||
|
{
|
||||||
|
for (const auto& [offset, field] : ScriptExtension::CustomEntityFields)
|
||||||
|
{
|
||||||
|
Game::Scr_AddClassField(Game::ClassNum::CLASS_NUM_ENTITY, field.name, field.ofs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::Hook::Call<void()>(0x4A7CF0)(); // GScr_AddFieldsForClient
|
||||||
|
|
||||||
|
for (const auto& [offset, field] : ScriptExtension::CustomClientFields)
|
||||||
|
{
|
||||||
|
Game::Scr_AddClassField(Game::ClassNum::CLASS_NUM_ENTITY, field.name, field.ofs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because some functions are inlined we have to hook this function instead of Scr_SetEntityField
|
||||||
|
int ScriptExtension::Scr_SetObjectFieldStub(unsigned int classnum, int entnum, int offset)
|
||||||
|
{
|
||||||
|
if (classnum == Game::ClassNum::CLASS_NUM_ENTITY)
|
||||||
|
{
|
||||||
|
const auto entity_offset = static_cast<std::uint16_t>(offset);
|
||||||
|
|
||||||
|
const auto got = ScriptExtension::CustomEntityFields.find(entity_offset);
|
||||||
|
if (got != ScriptExtension::CustomEntityFields.end())
|
||||||
|
{
|
||||||
|
got->second.setter(&Game::g_entities[entnum], offset);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No custom generic field was found, let the game handle it
|
||||||
|
return Game::Scr_SetObjectField(classnum, entnum, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset was already converted to array 'index' following binop offset & ~Game::ENTFIELD_MASK
|
||||||
|
void ScriptExtension::Scr_SetClientFieldStub(Game::gclient_s* client, int offset)
|
||||||
|
{
|
||||||
|
const auto client_offset = static_cast<std::uint16_t>(offset);
|
||||||
|
|
||||||
|
const auto got = ScriptExtension::CustomClientFields.find(client_offset);
|
||||||
|
if (got != ScriptExtension::CustomClientFields.end())
|
||||||
|
{
|
||||||
|
got->second.setter(client, &got->second);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No custom field client was found, let the game handle it
|
||||||
|
Game::Scr_SetClientField(client, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptExtension::Scr_GetEntityFieldStub(int entnum, int offset)
|
||||||
|
{
|
||||||
|
if ((offset & Game::ENTFIELD_MASK) == Game::ENTFIELD_CLIENT)
|
||||||
|
{
|
||||||
|
// If we have a ENTFIELD_CLIENT offset we need to check g_entity is actually a fully connected client
|
||||||
|
if (Game::g_entities[entnum].client != nullptr)
|
||||||
|
{
|
||||||
|
const auto client_offset = static_cast<std::uint16_t>(offset & ~Game::ENTFIELD_MASK);
|
||||||
|
|
||||||
|
const auto got = ScriptExtension::CustomClientFields.find(client_offset);
|
||||||
|
if (got != ScriptExtension::CustomClientFields.end())
|
||||||
|
{
|
||||||
|
// Game functions probably don't ever need to use the reference to client_fields_s...
|
||||||
|
got->second.getter(Game::g_entities[entnum].client, &got->second);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular entity offsets can be searched directly in our custom handler
|
||||||
|
const auto entity_offset = static_cast<std::uint16_t>(offset);
|
||||||
|
|
||||||
|
const auto got = ScriptExtension::CustomEntityFields.find(entity_offset);
|
||||||
|
if (got != ScriptExtension::CustomEntityFields.end())
|
||||||
|
{
|
||||||
|
got->second.getter(&Game::g_entities[entnum], offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No custom generic field was found, let the game handle it
|
||||||
|
Game::Scr_GetEntityField(entnum, offset);
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptExtension::AddFunctions()
|
void ScriptExtension::AddFunctions()
|
||||||
{
|
{
|
||||||
// File functions
|
// File functions
|
||||||
@ -247,11 +356,46 @@ namespace Components
|
|||||||
Game::Scr_AddIString(value);
|
Game::Scr_AddIString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptExtension::AddEntityFields()
|
||||||
|
{
|
||||||
|
ScriptExtension::AddEntityField("entityflags", Game::fieldtype_t::F_INT,
|
||||||
|
[](Game::gentity_s* ent, [[maybe_unused]] int offset)
|
||||||
|
{
|
||||||
|
ent->flags = Game::Scr_GetInt(0);
|
||||||
|
},
|
||||||
|
[](Game::gentity_s* ent, [[maybe_unused]] int offset)
|
||||||
|
{
|
||||||
|
Game::Scr_AddInt(ent->flags);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptExtension::AddClientFields()
|
||||||
|
{
|
||||||
|
ScriptExtension::AddClientField("clientflags", Game::fieldtype_t::F_INT,
|
||||||
|
[](Game::gclient_s* pSelf, [[maybe_unused]] const Game::client_fields_s* pField)
|
||||||
|
{
|
||||||
|
pSelf->flags = Game::Scr_GetInt(0);
|
||||||
|
},
|
||||||
|
[](Game::gclient_s* pSelf, [[maybe_unused]] const Game::client_fields_s* pField)
|
||||||
|
{
|
||||||
|
Game::Scr_AddInt(pSelf->flags);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ScriptExtension::ScriptExtension()
|
ScriptExtension::ScriptExtension()
|
||||||
{
|
{
|
||||||
ScriptExtension::AddFunctions();
|
ScriptExtension::AddFunctions();
|
||||||
ScriptExtension::AddMethods();
|
ScriptExtension::AddMethods();
|
||||||
|
ScriptExtension::AddEntityFields();
|
||||||
|
ScriptExtension::AddClientFields();
|
||||||
|
|
||||||
// Correct builtin function pointer
|
// Correct builtin function pointer
|
||||||
Utils::Hook::Set<void(*)()>(0x79A90C, ScriptExtension::Scr_TableLookupIStringByRow);
|
Utils::Hook::Set<void(*)()>(0x79A90C, ScriptExtension::Scr_TableLookupIStringByRow);
|
||||||
|
|
||||||
|
Utils::Hook(0x4EC721, ScriptExtension::GScr_AddFieldsForEntityStub, HOOK_CALL).install()->quick(); // GScr_AddFieldsForEntity
|
||||||
|
|
||||||
|
Utils::Hook(0x41BED2, ScriptExtension::Scr_SetObjectFieldStub, HOOK_CALL).install()->quick(); // SetEntityFieldValue
|
||||||
|
Utils::Hook(0x5FBF01, ScriptExtension::Scr_SetClientFieldStub, HOOK_CALL).install()->quick(); // Scr_SetObjectField
|
||||||
|
Utils::Hook(0x4FF413, ScriptExtension::Scr_GetEntityFieldStub, HOOK_CALL).install()->quick(); // Scr_GetObjectField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,28 @@ namespace Components
|
|||||||
public:
|
public:
|
||||||
ScriptExtension();
|
ScriptExtension();
|
||||||
|
|
||||||
|
static void AddEntityField(const char* name, Game::fieldtype_t type, const Game::ScriptCallbackEnt& setter, const Game::ScriptCallbackEnt& getter);
|
||||||
|
static void AddClientField(const char* name, Game::fieldtype_t type, const Game::ScriptCallbackClient& setter, const Game::ScriptCallbackClient& getter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const char* QueryStrings[];
|
static const char* QueryStrings[];
|
||||||
|
|
||||||
|
static std::unordered_map<std::uint16_t, Game::ent_field_t> CustomEntityFields;
|
||||||
|
static std::unordered_map<std::uint16_t, Game::client_fields_s> CustomClientFields;
|
||||||
|
|
||||||
|
static void GScr_AddFieldsForEntityStub();
|
||||||
|
|
||||||
|
// Two hooks because it makes our code cleaner (luckily functions were not inlined)
|
||||||
|
static int Scr_SetObjectFieldStub(unsigned int classnum, int entnum, int offset);
|
||||||
|
static void Scr_SetClientFieldStub(Game::gclient_s* client, int offset);
|
||||||
|
|
||||||
|
// One hook because functions were inlined
|
||||||
|
static void Scr_GetEntityFieldStub(int entnum, int offset);
|
||||||
|
|
||||||
static void AddFunctions();
|
static void AddFunctions();
|
||||||
static void AddMethods();
|
static void AddMethods();
|
||||||
|
static void AddEntityFields();
|
||||||
|
static void AddClientFields();
|
||||||
static void Scr_TableLookupIStringByRow();
|
static void Scr_TableLookupIStringByRow();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
112
src/Components/Modules/Security.cpp
Normal file
112
src/Components/Modules/Security.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include <STDInclude.hpp>
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
int Security::MsgReadBitsCompressCheckSV(const char* from, char* to, int size)
|
||||||
|
{
|
||||||
|
static char buffer[0x8000];
|
||||||
|
|
||||||
|
if (size > 0x800) return 0;
|
||||||
|
size = Game::MSG_ReadBitsCompress(from, buffer, size);
|
||||||
|
|
||||||
|
if (size > 0x800) return 0;
|
||||||
|
std::memcpy(to, buffer, size);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Security::MsgReadBitsCompressCheckCL(const char* from, char* to, int size)
|
||||||
|
{
|
||||||
|
static char buffer[0x100000];
|
||||||
|
|
||||||
|
if (size > 0x20000) return 0;
|
||||||
|
size = Game::MSG_ReadBitsCompress(from, buffer, size);
|
||||||
|
|
||||||
|
if (size > 0x20000) return 0;
|
||||||
|
std::memcpy(to, buffer, size);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Security::SVCanReplaceServerCommand(Game::client_t* /*client*/, const char* /*cmd*/)
|
||||||
|
{
|
||||||
|
// This is a fix copied from V2. As I don't have time to investigate, let's simply trust them
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long Security::AtolAdjustPlayerLimit(const char* string)
|
||||||
|
{
|
||||||
|
return std::min<long>(std::atol(string), 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Security::SelectStringTableEntryInDvarStub()
|
||||||
|
{
|
||||||
|
Command::ClientParams params;
|
||||||
|
|
||||||
|
if (params.size() >= 4)
|
||||||
|
{
|
||||||
|
const auto* dvarName = params[3];
|
||||||
|
const auto* dvar = Game::Dvar_FindVar(dvarName);
|
||||||
|
|
||||||
|
if (Command::Find(dvarName) ||
|
||||||
|
(dvar != nullptr && dvar->flags & (Game::DVAR_WRITEPROTECTED | Game::DVAR_CHEAT | Game::DVAR_READONLY)))
|
||||||
|
{
|
||||||
|
Logger::Print(0, "CL_SelectStringTableEntryInDvar_f: illegal parameter\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::CL_SelectStringTableEntryInDvar_f();
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) int Security::G_GetClientScore()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
mov eax, [esp + 4] // index
|
||||||
|
mov ecx, ds:1A831A8h // level: &g_clients
|
||||||
|
|
||||||
|
test ecx, ecx
|
||||||
|
jz invalid_ptr
|
||||||
|
|
||||||
|
imul eax, 366Ch
|
||||||
|
mov eax, [eax + ecx + 3134h]
|
||||||
|
ret
|
||||||
|
|
||||||
|
invalid_ptr:
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Security::G_LogPrintfStub(const char* fmt)
|
||||||
|
{
|
||||||
|
Game::G_LogPrintf("%s", fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Security::Security()
|
||||||
|
{
|
||||||
|
// Exploit fixes
|
||||||
|
Utils::Hook(0x414D92, MsgReadBitsCompressCheckSV, HOOK_CALL).install()->quick(); // SV_ExecuteClientCommands
|
||||||
|
Utils::Hook(0x4A9F56, MsgReadBitsCompressCheckCL, HOOK_CALL).install()->quick(); // CL_ParseServerMessage
|
||||||
|
Utils::Hook(0x407376, SVCanReplaceServerCommand, HOOK_CALL).install()->quick(); // SV_CanReplaceServerCommand
|
||||||
|
|
||||||
|
Utils::Hook::Set<BYTE>(0x412370, 0xC3); // SV_SteamAuthClient
|
||||||
|
Utils::Hook::Set<BYTE>(0x5A8C70, 0xC3); // CL_HandleRelayPacket
|
||||||
|
|
||||||
|
Utils::Hook::Nop(0x41698E, 5); // Disable Svcmd_EntityList_f
|
||||||
|
|
||||||
|
// Patch selectStringTableEntryInDvar
|
||||||
|
Utils::Hook::Set<void(*)()>(0x405959, Security::SelectStringTableEntryInDvarStub);
|
||||||
|
|
||||||
|
// Patch G_GetClientScore for uninitialized game
|
||||||
|
Utils::Hook(0x469AC0, G_GetClientScore, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
|
// Requests can be malicious
|
||||||
|
Utils::Hook(0x5B67ED, AtolAdjustPlayerLimit, HOOK_CALL).install()->quick(); // PartyHost_HandleJoinPartyRequest
|
||||||
|
|
||||||
|
// Patch unsecure call to G_LogPrint inside GScr_LogPrint
|
||||||
|
// This function is unsafe because IW devs forgot to G_LogPrintf("%s", fmt)
|
||||||
|
Utils::Hook(0x5F70B5, G_LogPrintfStub, HOOK_CALL).install()->quick();
|
||||||
|
}
|
||||||
|
}
|
24
src/Components/Modules/Security.hpp
Normal file
24
src/Components/Modules/Security.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class Security : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Security();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int MsgReadBitsCompressCheckSV(const char* from, char* to, int size);
|
||||||
|
static int MsgReadBitsCompressCheckCL(const char* from, char* to, int size);
|
||||||
|
|
||||||
|
static int SVCanReplaceServerCommand(Game::client_t* client, const char* cmd);
|
||||||
|
|
||||||
|
static long AtolAdjustPlayerLimit(const char* string);
|
||||||
|
|
||||||
|
static void SelectStringTableEntryInDvarStub();
|
||||||
|
|
||||||
|
static int G_GetClientScore();
|
||||||
|
|
||||||
|
static void G_LogPrintfStub(const char* fmt);
|
||||||
|
};
|
||||||
|
}
|
@ -1356,11 +1356,11 @@ namespace Components
|
|||||||
if (*in) // height
|
if (*in) // height
|
||||||
in++;
|
in++;
|
||||||
|
|
||||||
if(*in) // material name length + material name characters
|
if (*in) // material name length + material name characters
|
||||||
{
|
{
|
||||||
const auto materialNameLength = *in;
|
const auto materialNameLength = *in;
|
||||||
in++;
|
in++;
|
||||||
for(auto i = 0; i < materialNameLength; i++)
|
for (auto i = 0; i < materialNameLength; i++)
|
||||||
{
|
{
|
||||||
if (*in)
|
if (*in)
|
||||||
in++;
|
in++;
|
||||||
@ -1370,7 +1370,7 @@ namespace Components
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(*in == FONT_ICON_SEPARATOR_CHARACTER)
|
if (*in == FONT_ICON_SEPARATOR_CHARACTER)
|
||||||
{
|
{
|
||||||
const auto* fontIconEndPos = &in[1];
|
const auto* fontIconEndPos = &in[1];
|
||||||
FontIconInfo fontIcon{};
|
FontIconInfo fontIcon{};
|
||||||
@ -1386,6 +1386,7 @@ namespace Components
|
|||||||
++current;
|
++current;
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = '\0';
|
*out = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ namespace Components
|
|||||||
|
|
||||||
HWND Window::MainWindow = nullptr;
|
HWND Window::MainWindow = nullptr;
|
||||||
BOOL Window::CursorVisible = TRUE;
|
BOOL Window::CursorVisible = TRUE;
|
||||||
|
std::unordered_map<UINT, Utils::Slot<Window::WndProcCallback>> Window::WndMessageCallbacks;
|
||||||
|
Utils::Signal<Window::CreateCallback> Window::CreateSignals;
|
||||||
|
|
||||||
int Window::Width()
|
int Window::Width()
|
||||||
{
|
{
|
||||||
@ -66,6 +68,16 @@ namespace Components
|
|||||||
return Window::MainWindow;
|
return Window::MainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::OnWndMessage(UINT Msg, Utils::Slot<Window::WndProcCallback> callback)
|
||||||
|
{
|
||||||
|
WndMessageCallbacks.emplace(Msg, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::OnCreate(Utils::Slot<CreateCallback> callback)
|
||||||
|
{
|
||||||
|
CreateSignals.connect(callback);
|
||||||
|
}
|
||||||
|
|
||||||
int Window::IsNoBorder()
|
int Window::IsNoBorder()
|
||||||
{
|
{
|
||||||
return Window::NoBorder.get<bool>();
|
return Window::NoBorder.get<bool>();
|
||||||
@ -121,6 +133,9 @@ namespace Components
|
|||||||
HWND WINAPI Window::CreateMainWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
|
HWND WINAPI Window::CreateMainWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
|
||||||
{
|
{
|
||||||
Window::MainWindow = CreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
Window::MainWindow = CreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
||||||
|
|
||||||
|
CreateSignals();
|
||||||
|
|
||||||
return Window::MainWindow;
|
return Window::MainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,15 +147,21 @@ namespace Components
|
|||||||
|
|
||||||
BOOL WINAPI Window::MessageHandler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
BOOL WINAPI Window::MessageHandler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
if (Msg == WM_SETCURSOR)
|
if (const auto cb = WndMessageCallbacks.find(Msg); cb != WndMessageCallbacks.end())
|
||||||
{
|
{
|
||||||
Window::ApplyCursor();
|
return cb->second(lParam, wParam);
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils::Hook::Call<BOOL(__stdcall)(HWND, UINT, WPARAM, LPARAM)>(0x4731F0)(hWnd, Msg, wParam, lParam);
|
return Utils::Hook::Call<BOOL(__stdcall)(HWND, UINT, WPARAM, LPARAM)>(0x4731F0)(hWnd, Msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::EnableDpiAwareness()
|
||||||
|
{
|
||||||
|
const Utils::Library user32{"user32.dll"};
|
||||||
|
|
||||||
|
user32.invokePascal<void>("SetProcessDpiAwarenessContext", DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||||
|
}
|
||||||
|
|
||||||
Window::Window()
|
Window::Window()
|
||||||
{
|
{
|
||||||
// Borderless window
|
// Borderless window
|
||||||
@ -184,5 +205,13 @@ namespace Components
|
|||||||
|
|
||||||
// Use custom message handler
|
// Use custom message handler
|
||||||
Utils::Hook::Set(0x64D298, Window::MessageHandler);
|
Utils::Hook::Set(0x64D298, Window::MessageHandler);
|
||||||
|
|
||||||
|
Window::OnWndMessage(WM_SETCURSOR, [](WPARAM, LPARAM)
|
||||||
|
{
|
||||||
|
Window::ApplyCursor();
|
||||||
|
return TRUE;
|
||||||
|
});
|
||||||
|
|
||||||
|
Window::EnableDpiAwareness();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@ namespace Components
|
|||||||
class Window : public Component
|
class Window : public Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef BOOL(WndProcCallback)(WPARAM wParam, LPARAM lParam);
|
||||||
|
typedef void(CreateCallback)();
|
||||||
|
|
||||||
Window();
|
Window();
|
||||||
|
|
||||||
static int Width();
|
static int Width();
|
||||||
@ -18,10 +21,15 @@ namespace Components
|
|||||||
|
|
||||||
static HWND GetWindow();
|
static HWND GetWindow();
|
||||||
|
|
||||||
|
static void OnWndMessage(UINT Msg, Utils::Slot<WndProcCallback> callback);
|
||||||
|
|
||||||
|
static void OnCreate(Utils::Slot<CreateCallback> callback);
|
||||||
private:
|
private:
|
||||||
static BOOL CursorVisible;
|
static BOOL CursorVisible;
|
||||||
static Dvar::Var NoBorder;
|
static Dvar::Var NoBorder;
|
||||||
static Dvar::Var NativeCursor;
|
static Dvar::Var NativeCursor;
|
||||||
|
static std::unordered_map<UINT, Utils::Slot<WndProcCallback>> WndMessageCallbacks;
|
||||||
|
static Utils::Signal<CreateCallback> CreateSignals;
|
||||||
|
|
||||||
static HWND MainWindow;
|
static HWND MainWindow;
|
||||||
|
|
||||||
@ -36,5 +44,7 @@ namespace Components
|
|||||||
|
|
||||||
static void StyleHookStub();
|
static void StyleHookStub();
|
||||||
static HWND WINAPI CreateMainWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
|
static HWND WINAPI CreateMainWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
|
||||||
|
|
||||||
|
static void EnableDpiAwareness();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,7 @@ namespace Game
|
|||||||
FS_IsShippedIWD_t FS_IsShippedIWD = FS_IsShippedIWD_t(0x642440);
|
FS_IsShippedIWD_t FS_IsShippedIWD = FS_IsShippedIWD_t(0x642440);
|
||||||
FS_Delete_t FS_Delete = FS_Delete_t(0x48A5B0);
|
FS_Delete_t FS_Delete = FS_Delete_t(0x48A5B0);
|
||||||
|
|
||||||
|
G_LogPrintf_t G_LogPrintf = G_LogPrintf_t(0x4B0150);
|
||||||
G_GetWeaponIndexForName_t G_GetWeaponIndexForName = G_GetWeaponIndexForName_t(0x49E540);
|
G_GetWeaponIndexForName_t G_GetWeaponIndexForName = G_GetWeaponIndexForName_t(0x49E540);
|
||||||
G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = G_SpawnEntitiesFromString_t(0x4D8840);
|
G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = G_SpawnEntitiesFromString_t(0x4D8840);
|
||||||
G_PrintEntities_t G_PrintEntities = G_PrintEntities_t(0x4E6A50);
|
G_PrintEntities_t G_PrintEntities = G_PrintEntities_t(0x4E6A50);
|
||||||
@ -295,6 +296,12 @@ namespace Game
|
|||||||
|
|
||||||
Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0);
|
Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0);
|
||||||
|
|
||||||
|
Scr_GetObjectField_t Scr_GetObjectField = Scr_GetObjectField_t(0x4FF3D0);
|
||||||
|
Scr_SetObjectField_t Scr_SetObjectField = Scr_SetObjectField_t(0x4F20F0);
|
||||||
|
Scr_GetEntityField_t Scr_GetEntityField = Scr_GetEntityField_t(0x4E8390);
|
||||||
|
Scr_SetClientField_t Scr_SetClientField = Scr_SetClientField_t(0x4A6DF0);
|
||||||
|
Scr_AddClassField_t Scr_AddClassField = Scr_AddClassField_t(0x4C0E70);
|
||||||
|
|
||||||
GetEntity_t GetEntity = GetEntity_t(0x4BC270);
|
GetEntity_t GetEntity = GetEntity_t(0x4BC270);
|
||||||
GetPlayerEntity_t GetPlayerEntity = GetPlayerEntity_t(0x49C4A0);
|
GetPlayerEntity_t GetPlayerEntity = GetPlayerEntity_t(0x49C4A0);
|
||||||
|
|
||||||
@ -415,6 +422,13 @@ namespace Game
|
|||||||
PM_Trace_t PM_Trace = PM_Trace_t(0x441F60);
|
PM_Trace_t PM_Trace = PM_Trace_t(0x441F60);
|
||||||
PM_GetEffectiveStance_t PM_GetEffectiveStance = PM_GetEffectiveStance_t(0x412540);
|
PM_GetEffectiveStance_t PM_GetEffectiveStance = PM_GetEffectiveStance_t(0x412540);
|
||||||
|
|
||||||
|
CL_MouseEvent_t CL_MouseEvent = CL_MouseEvent_t(0x4D7C50);
|
||||||
|
IN_RecenterMouse_t IN_RecenterMouse = IN_RecenterMouse_t(0x463D80);
|
||||||
|
|
||||||
|
IN_MouseMove_t IN_MouseMove = IN_MouseMove_t(0x64C490);
|
||||||
|
IN_Init_t IN_Init = IN_Init_t(0x45D620);
|
||||||
|
IN_Shutdown_t IN_Shutdown = IN_Shutdown_t(0x426360);
|
||||||
|
|
||||||
XAssetHeader* DB_XAssetPool = reinterpret_cast<XAssetHeader*>(0x7998A8);
|
XAssetHeader* DB_XAssetPool = reinterpret_cast<XAssetHeader*>(0x7998A8);
|
||||||
unsigned int* g_poolSize = reinterpret_cast<unsigned int*>(0x7995E8);
|
unsigned int* g_poolSize = reinterpret_cast<unsigned int*>(0x7995E8);
|
||||||
|
|
||||||
@ -539,6 +553,11 @@ namespace Game
|
|||||||
|
|
||||||
level_locals_t* level = reinterpret_cast<level_locals_t*>(0x1A831A8);
|
level_locals_t* level = reinterpret_cast<level_locals_t*>(0x1A831A8);
|
||||||
|
|
||||||
|
WinMouseVars_t* s_wmv = reinterpret_cast<WinMouseVars_t*>(0x649D640);
|
||||||
|
|
||||||
|
int* window_center_x = reinterpret_cast<int*>(0x649D638);
|
||||||
|
int* window_center_y = reinterpret_cast<int*>(0x649D630);
|
||||||
|
|
||||||
void Sys_LockRead(FastCriticalSection* critSect)
|
void Sys_LockRead(FastCriticalSection* critSect)
|
||||||
{
|
{
|
||||||
InterlockedIncrement(&critSect->readCount);
|
InterlockedIncrement(&critSect->readCount);
|
||||||
|
@ -341,7 +341,7 @@ namespace Game
|
|||||||
typedef int(__cdecl * FS_FOpenFileReadForThread_t)(const char *filename, int *file, int thread);
|
typedef int(__cdecl * FS_FOpenFileReadForThread_t)(const char *filename, int *file, int thread);
|
||||||
extern FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread;
|
extern FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_FCloseFile_t)(int fh);
|
typedef int(__cdecl * FS_FCloseFile_t)(int stream);
|
||||||
extern FS_FCloseFile_t FS_FCloseFile;
|
extern FS_FCloseFile_t FS_FCloseFile;
|
||||||
|
|
||||||
typedef bool(__cdecl * FS_FileExists_t)(const char* file);
|
typedef bool(__cdecl * FS_FileExists_t)(const char* file);
|
||||||
@ -380,6 +380,9 @@ namespace Game
|
|||||||
typedef int(__cdecl* FS_Delete_t)(const char* fileName);
|
typedef int(__cdecl* FS_Delete_t)(const char* fileName);
|
||||||
extern FS_Delete_t FS_Delete;
|
extern FS_Delete_t FS_Delete;
|
||||||
|
|
||||||
|
typedef void(__cdecl * G_LogPrintf_t)(const char* fmt, ...);
|
||||||
|
extern G_LogPrintf_t G_LogPrintf;
|
||||||
|
|
||||||
typedef unsigned int(__cdecl * G_GetWeaponIndexForName_t)(const char*);
|
typedef unsigned int(__cdecl * G_GetWeaponIndexForName_t)(const char*);
|
||||||
extern G_GetWeaponIndexForName_t G_GetWeaponIndexForName;
|
extern G_GetWeaponIndexForName_t G_GetWeaponIndexForName;
|
||||||
|
|
||||||
@ -744,6 +747,21 @@ namespace Game
|
|||||||
typedef void(__cdecl * Scr_ParamError_t)(unsigned int paramIndex, const char*);
|
typedef void(__cdecl * Scr_ParamError_t)(unsigned int paramIndex, const char*);
|
||||||
extern Scr_ParamError_t Scr_ParamError;
|
extern Scr_ParamError_t Scr_ParamError;
|
||||||
|
|
||||||
|
typedef void(__cdecl * Scr_GetObjectField_t)(unsigned int classnum, int entnum, int offset);
|
||||||
|
extern Scr_GetObjectField_t Scr_GetObjectField;
|
||||||
|
|
||||||
|
typedef int(__cdecl * Scr_SetObjectField_t)(unsigned int classnum, int entnum, int offset);
|
||||||
|
extern Scr_SetObjectField_t Scr_SetObjectField;
|
||||||
|
|
||||||
|
typedef void(__cdecl * Scr_SetClientField_t)(gclient_s* client, int offset);
|
||||||
|
extern Scr_SetClientField_t Scr_SetClientField;
|
||||||
|
|
||||||
|
typedef void(__cdecl * Scr_GetEntityField_t)(int entnum, int offset);
|
||||||
|
extern Scr_GetEntityField_t Scr_GetEntityField;
|
||||||
|
|
||||||
|
typedef void(__cdecl * Scr_AddClassField_t)(unsigned int classnum, const char* name, unsigned int offset);
|
||||||
|
extern Scr_AddClassField_t Scr_AddClassField;
|
||||||
|
|
||||||
typedef gentity_s*(__cdecl * GetPlayerEntity_t)(scr_entref_t entref);
|
typedef gentity_s*(__cdecl * GetPlayerEntity_t)(scr_entref_t entref);
|
||||||
extern GetPlayerEntity_t GetPlayerEntity;
|
extern GetPlayerEntity_t GetPlayerEntity;
|
||||||
|
|
||||||
@ -990,6 +1008,21 @@ namespace Game
|
|||||||
typedef EffectiveStance(__cdecl * PM_GetEffectiveStance_t)(const playerState_s* ps);
|
typedef EffectiveStance(__cdecl * PM_GetEffectiveStance_t)(const playerState_s* ps);
|
||||||
extern PM_GetEffectiveStance_t PM_GetEffectiveStance;
|
extern PM_GetEffectiveStance_t PM_GetEffectiveStance;
|
||||||
|
|
||||||
|
typedef int(__cdecl * CL_MouseEvent_t)(int x, int y, int dx, int dy);
|
||||||
|
extern CL_MouseEvent_t CL_MouseEvent;
|
||||||
|
|
||||||
|
typedef void(__cdecl * IN_RecenterMouse_t)();
|
||||||
|
extern IN_RecenterMouse_t IN_RecenterMouse;
|
||||||
|
|
||||||
|
typedef void(__cdecl * IN_MouseMove_t)();
|
||||||
|
extern IN_MouseMove_t IN_MouseMove;
|
||||||
|
|
||||||
|
typedef void(__cdecl * IN_Init_t)();
|
||||||
|
extern IN_Init_t IN_Init;
|
||||||
|
|
||||||
|
typedef void(__cdecl * IN_Shutdown_t)();
|
||||||
|
extern IN_Shutdown_t IN_Shutdown;
|
||||||
|
|
||||||
extern XAssetHeader* DB_XAssetPool;
|
extern XAssetHeader* DB_XAssetPool;
|
||||||
extern unsigned int* g_poolSize;
|
extern unsigned int* g_poolSize;
|
||||||
|
|
||||||
@ -1120,6 +1153,11 @@ namespace Game
|
|||||||
|
|
||||||
extern level_locals_t* level;
|
extern level_locals_t* level;
|
||||||
|
|
||||||
|
extern WinMouseVars_t* s_wmv;
|
||||||
|
|
||||||
|
extern int* window_center_x;
|
||||||
|
extern int* window_center_y;
|
||||||
|
|
||||||
void Sys_LockRead(FastCriticalSection* critSect);
|
void Sys_LockRead(FastCriticalSection* critSect);
|
||||||
void Sys_UnlockRead(FastCriticalSection* critSect);
|
void Sys_UnlockRead(FastCriticalSection* critSect);
|
||||||
|
|
||||||
|
@ -231,6 +231,17 @@ namespace Game
|
|||||||
FL_MOVER_SLIDE = 0x8000000
|
FL_MOVER_SLIDE = 0x8000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ClassNum : unsigned int
|
||||||
|
{
|
||||||
|
CLASS_NUM_ENTITY = 0x0,
|
||||||
|
CLASS_NUM_HUDELEM = 0x1,
|
||||||
|
CLASS_NUM_PATHNODE = 0x2,
|
||||||
|
CLASS_NUM_VEHICLENODE = 0x3,
|
||||||
|
CLASS_NUM_VEHTRACK_SEGMENT = 0x4,
|
||||||
|
CLASS_NUM_FXENTITY = 0x5,
|
||||||
|
CLASS_NUM_COUNT = 0x6,
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
HITLOC_NONE,
|
HITLOC_NONE,
|
||||||
@ -5705,6 +5716,53 @@ namespace Game
|
|||||||
|
|
||||||
static_assert(sizeof(gentity_s) == 0x274);
|
static_assert(sizeof(gentity_s) == 0x274);
|
||||||
|
|
||||||
|
enum $1C4253065710F064DA9E4D59ED6EC544
|
||||||
|
{
|
||||||
|
ENTFIELD_ENTITY = 0x0,
|
||||||
|
ENTFIELD_SENTIENT = 0x2000,
|
||||||
|
ENTFIELD_ACTOR = 0x4000,
|
||||||
|
ENTFIELD_CLIENT = 0x6000,
|
||||||
|
ENTFIELD_VEHICLE = 0x8000,
|
||||||
|
ENTFIELD_MASK = 0xE000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fieldtype_t
|
||||||
|
{
|
||||||
|
F_INT = 0x0,
|
||||||
|
F_SHORT = 0x1,
|
||||||
|
F_BYTE = 0x2,
|
||||||
|
F_FLOAT = 0x3,
|
||||||
|
F_CSTRING = 0x4,
|
||||||
|
F_STRING = 0x5,
|
||||||
|
F_VECTOR = 0x6,
|
||||||
|
F_ENTITY = 0x7,
|
||||||
|
F_ENTHANDLE = 0x8,
|
||||||
|
F_ANGLES_YAW = 0x9,
|
||||||
|
F_OBJECT = 0xA,
|
||||||
|
F_MODEL = 0xB,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ent_field_t
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
int ofs;
|
||||||
|
fieldtype_t type;
|
||||||
|
void(__cdecl * setter)(gentity_s*, int);
|
||||||
|
void(__cdecl * getter)(gentity_s*, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct client_fields_s
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
int ofs;
|
||||||
|
fieldtype_t type;
|
||||||
|
void(__cdecl * setter)(gclient_s*, const client_fields_s*);
|
||||||
|
void(__cdecl * getter)(gclient_s*, const client_fields_s*);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void(__cdecl * ScriptCallbackEnt)(gentity_s*, int);
|
||||||
|
typedef void(__cdecl * ScriptCallbackClient)(gclient_s*, const client_fields_s*);
|
||||||
|
|
||||||
struct lockonFireParms
|
struct lockonFireParms
|
||||||
{
|
{
|
||||||
bool lockon;
|
bool lockon;
|
||||||
@ -7415,6 +7473,16 @@ namespace Game
|
|||||||
|
|
||||||
static_assert(sizeof(level_locals_t) == 0x2F78);
|
static_assert(sizeof(level_locals_t) == 0x2F78);
|
||||||
|
|
||||||
|
struct WinMouseVars_t
|
||||||
|
{
|
||||||
|
int oldButtonState;
|
||||||
|
tagPOINT oldPos;
|
||||||
|
bool mouseActive;
|
||||||
|
bool mouseInitialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(WinMouseVars_t) == 0x10);
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#ifndef IDA
|
#ifndef IDA
|
||||||
|
@ -11,7 +11,7 @@ namespace Utils
|
|||||||
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
||||||
|
|
||||||
VAProvider() : currentBuffer(0) {}
|
VAProvider() : currentBuffer(0) {}
|
||||||
~VAProvider() {}
|
~VAProvider() = default;
|
||||||
|
|
||||||
const char* get(const char* format, va_list ap)
|
const char* get(const char* format, va_list ap)
|
||||||
{
|
{
|
||||||
@ -25,7 +25,7 @@ namespace Utils
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
const auto res = _vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
||||||
if (res > 0) break; // Success
|
if (res > 0) break; // Success
|
||||||
if (res == 0) return ""; // Error
|
if (res == 0) return ""; // Error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user