Merge pull request #267 from XLabsProject/develop

Release v0.7.2
This commit is contained in:
Edo 2022-05-10 20:41:59 +01:00 committed by GitHub
commit 42a414c2f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 475 additions and 186 deletions

View File

@ -4,6 +4,29 @@ 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.2] - 2022-05-10
### Added
- Add IsArray GSC function (#248)
- Keybind fields in menus work with controller keys (#255)
### Changed
- GSC function `GetSystemTime` now returns the Unix time (#258)
### Fixed
- 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)
### 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.
## [0.7.1] - 2022-05-03
### Added
@ -20,7 +43,9 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.
### Changed
- Test clients' native functionality has been restored by default (#162)
- Renamed GSC method `isBot` to `IsTestClient` (#162)
- Custom GSC functions can be called correctly from a game script (#216)
- GSC functions `HttpCancel` and `HttpCancel` require the game to be launched with the command line argument `scriptablehttp` (#162)
- Master server list will be used instead of the node system (load server list faster) (#234)
### Fixed

View File

@ -161,7 +161,7 @@ newaction {
local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w"))
versionHeader:write("/*\n")
versionHeader:write(" * Automatically generated by premake5.\n")
versionHeader:write(" * Do not touch, you fucking moron!\n")
versionHeader:write(" * Do not touch!\n")
versionHeader:write(" */\n")
versionHeader:write("\n")
versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n")
@ -181,7 +181,7 @@ newaction {
local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w"))
versionHeader:write("/*\n")
versionHeader:write(" * Automatically generated by premake5.\n")
versionHeader:write(" * Do not touch, you fucking moron!\n")
versionHeader:write(" * Do not touch!\n")
versionHeader:write(" *\n")
versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n")
versionHeader:write(" *\n")

View File

@ -105,6 +105,7 @@ namespace Components
Loader::Register(new Elevators());
Loader::Register(new ClientCommand());
Loader::Register(new ScriptExtension());
Loader::Register(new Branding());
Loader::Register(new RawMouse());
Loader::Register(new Bullet());

View File

@ -136,5 +136,6 @@ namespace Components
#include "Modules/ClientCommand.hpp"
#include "Modules/Gamepad.hpp"
#include "Modules/ScriptExtension.hpp"
#include "Modules/Branding.hpp"
#include "Modules/RawMouse.hpp"
#include "Modules/Bullet.hpp"

View File

@ -108,8 +108,17 @@ namespace Components
}
}
void Bots::GScr_isTestClient(Game::scr_entref_t entref)
{
const auto* ent = Game::GetPlayerEntity(entref);
Game::Scr_AddBool(Game::SV_IsTestClient(ent->s.number) != 0);
}
void Bots::AddMethods()
{
Script::AddMethod("IsBot", Bots::GScr_isTestClient); // Usage: self IsBot();
Script::AddMethod("IsTestClient", Bots::GScr_isTestClient); // Usage: self IsTestClient();
Script::AddMethod("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing(<int>)
{
auto ping = Game::Scr_GetInt(0);
@ -119,7 +128,7 @@ namespace Components
const auto* ent = Game::GetPlayerEntity(entref);
auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1SetPing: Can only call on a bot!\n");
return;
@ -128,20 +137,11 @@ namespace Components
client->ping = static_cast<int16_t>(ping);
});
Script::AddMethod("IsTestClient", [](Game::scr_entref_t entref) // Usage: <bot> IsTestClient();
{
const auto* gentity = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(gentity);
Game::Scr_AddBool(client->bIsTestClient == 1);
});
Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: <bot> BotStop();
{
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotStop: Can only call on a bot!\n");
return;
@ -154,17 +154,16 @@ namespace Components
Script::AddMethod("BotWeapon", [](Game::scr_entref_t entref) // Usage: <bot> BotWeapon(<str>);
{
const auto* weapon = Game::Scr_GetString(0);
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotWeapon: Can only call on a bot!\n");
return;
}
const auto* weapon = Game::Scr_GetString(0);
if (weapon == nullptr || weapon[0] == '\0')
{
g_botai[entref.entnum].weapon = 1;
@ -178,6 +177,14 @@ namespace Components
Script::AddMethod("BotAction", [](Game::scr_entref_t entref) // Usage: <bot> BotAction(<str action>);
{
const auto* ent = Game::GetPlayerEntity(entref);
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotAction: Can only call on a bot!\n");
return;
}
const auto* action = Game::Scr_GetString(0);
if (action == nullptr)
@ -186,15 +193,6 @@ namespace Components
return;
}
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
{
Game::Scr_Error("^1BotAction: Can only call on a bot!\n");
return;
}
if (action[0] != '+' && action[0] != '-')
{
Game::Scr_ParamError(0, "^1BotAction: Sign for action must be '+' or '-'.\n");
@ -220,20 +218,16 @@ namespace Components
Script::AddMethod("BotMovement", [](Game::scr_entref_t entref) // Usage: <bot> BotMovement(<int>, <int>);
{
auto forwardInt = Game::Scr_GetInt(0);
auto rightInt = Game::Scr_GetInt(1);
const auto* ent = Game::GetPlayerEntity(entref);
const auto* client = Script::GetClient(ent);
if (!client->bIsTestClient)
if (Game::SV_IsTestClient(ent->s.number) == 0)
{
Game::Scr_Error("^1BotMovement: Can only call on a bot!\n");
return;
}
forwardInt = std::clamp<int>(forwardInt, std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
rightInt = std::clamp<int>(rightInt, std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
const auto forwardInt = std::clamp<int>(Game::Scr_GetInt(0), std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
const auto rightInt = std::clamp<int>(Game::Scr_GetInt(1), std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
g_botai[entref.entnum].forward = static_cast<int8_t>(forwardInt);
g_botai[entref.entnum].right = static_cast<int8_t>(rightInt);
@ -327,6 +321,8 @@ namespace Components
Bots::Bots()
{
AssertOffset(Game::client_s, bIsTestClient, 0x41AF0);
// Replace connect string
Utils::Hook::Set<const char*>(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\"");

View File

@ -14,6 +14,7 @@ namespace Components
static void Spawn(unsigned int count);
static void GScr_isTestClient(Game::scr_entref_t entref);
static void AddMethods();
static void BotAiAction(Game::client_t* cl);

View File

@ -0,0 +1,122 @@
#include <STDInclude.hpp>
namespace Components
{
Dvar::Var Branding::CGDrawVersion;
Dvar::Var Branding::CGDrawVersionX;
Dvar::Var Branding::CGDrawVersionY;
Game::dvar_t** Branding::Version = reinterpret_cast<Game::dvar_t**>(0x1AD7930);
void Branding::CG_DrawVersion()
{
// Default values
constexpr auto fontScale = 0.25f;
constexpr auto maxChars = std::numeric_limits<int>::max();
// Default colours
constexpr Game::vec4_t shadowColor = {0.0f, 0.0f, 0.0f, 0.69f};
constexpr Game::vec4_t color = {0.4f, 0.69f, 1.0f, 0.69f};
auto* const placement = Game::ScrPlace_GetUnsafeFullPlacement();
auto* const font = Game::UI_GetFontHandle(placement, 0, 0.583f);
const auto width = Game::UI_TextWidth((*Version)->current.string, 0, font, fontScale);
const auto height = Game::UI_TextHeight(font, fontScale);
Game::UI_DrawText(placement, (*Version)->current.string, maxChars, font, 1.0f - (CGDrawVersionX.get<float>() + static_cast<float>(width)),
1.0f - (CGDrawVersionY.get<float>() + static_cast<float>(height)), 3, 3, fontScale, shadowColor, 0);
Game::UI_DrawText(placement, (*Version)->current.string, maxChars, font, (0.0f - static_cast<float>(width)) - CGDrawVersionX.get<float>(),
(0.0f - static_cast<float>(height)) - CGDrawVersionY.get<float>(), 3, 3, fontScale, color, 0);
}
void Branding::CG_DrawVersion_Hk(int localClientNum)
{
Utils::Hook::Call<void(int)>(0x4EFF80)(localClientNum);
if (Branding::CGDrawVersion.get<bool>())
{
Branding::CG_DrawVersion();
}
}
const char* Branding::GetBuildNumber()
{
return SHORTVERSION " latest " __DATE__ " " __TIME__;
}
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));
return result;
}
void Branding::Dvar_SetVersionString(const Game::dvar_t* dvar, [[maybe_unused]] const char* value)
{
const auto* result = Branding::GetVersionString();
Utils::Hook::Call<void(const Game::dvar_t*, const char*)>(0x4A9580)(dvar, result);
}
// Branding this might be a good idea in case this LSP logging ever gets turned on for some reason
void Branding::MSG_WriteVersionStringHeader(Game::msg_t* msg, [[maybe_unused]] const char* string)
{
const auto* result = Branding::GetVersionString();
Utils::Hook::Call<void(Game::msg_t*, const char*)>(0x463820)(msg, result);
}
Game::dvar_t* Branding::Dvar_RegisterUIBuildLocation(const char* dvarName, [[maybe_unused]] float x,
[[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);
}
void Branding::RegisterBrandingDvars()
{
#ifdef _DEBUG
constexpr auto value = true;
#else
constexpr auto value = false;
#endif
Branding::CGDrawVersion = Dvar::Register<bool>("cg_drawVersion", value,
Game::dvar_flag::DVAR_NONE, "Draw the game version");
Branding::CGDrawVersionX = Dvar::Register<float>("cg_drawVersionX", 10.0f,
0.0f, 512.0f, Game::dvar_flag::DVAR_NONE, "X offset for the version string");
Branding::CGDrawVersionY = Dvar::Register<float>("cg_drawVersionY", 455.0f,
0.0f, 512.0f, Game::dvar_flag::DVAR_NONE, "Y offset for the version string");
}
Branding::Branding()
{
Dvar::OnInit(Branding::RegisterBrandingDvars);
// UI version string
Utils::Hook::Set<const char*>(0x43F73B, "IW4x: " VERSION);
// Short version dvar
Utils::Hook::Set<const char*>(0x60BD91, SHORTVERSION);
Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick();
// Version string color
static Game::vec4_t buildLocColor = {1.0f, 1.0f, 1.0f, 0.8f};
Utils::Hook::Set<float*>(0x43F710, buildLocColor);
// Place ui version string to bottom right corner (ui_buildlocation)
Utils::Hook(0x6310A0, Branding::Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); // Dvar_RegisterVec2
Utils::Hook(0x60BD81, Branding::Dvar_SetVersionString, HOOK_CALL).install()->quick();
Utils::Hook(0x4DA842, Branding::MSG_WriteVersionStringHeader, HOOK_CALL).install()->quick();
// Hook CG_DrawFullScreenDebugOverlays so we may render the version when it's appropriate
Utils::Hook(0x5AC975, Branding::CG_DrawVersion_Hk, HOOK_CALL).install()->quick();
}
}

View File

@ -0,0 +1,30 @@
#pragma once
namespace Components
{
class Branding : public Component
{
public:
Branding();
static const char* GetBuildNumber();
static const char* GetVersionString();
private:
static Dvar::Var CGDrawVersion;
static Dvar::Var CGDrawVersionX;
static Dvar::Var CGDrawVersionY;
static Game::dvar_t** Version;
static void CG_DrawVersion();
static void CG_DrawVersion_Hk(int localClientNum);
// Use IW4x Branding
static void Dvar_SetVersionString(const Game::dvar_t* dvar, const char* value);
static void MSG_WriteVersionStringHeader(Game::msg_t* msg, const char* string);
static Game::dvar_t* Dvar_RegisterUIBuildLocation(const char* dvarName, float x, float y, float min, float max, int flags, const char* description);
static void RegisterBrandingDvars();
};
}

View File

@ -354,7 +354,7 @@ namespace Components
}
});
Script::AddFunction("DropAllBots", []() // gsc: DropAllBots();
Script::AddFunction("DropAllBots", [] // gsc: DropAllBots();
{
Game::SV_DropAllBots();
});

View File

@ -3,7 +3,9 @@
namespace Components
{
SteamID Dedicated::PlayerGuids[18][2];
Dvar::Var Dedicated::SVRandomMapRotation;
Dvar::Var Dedicated::SVLanOnly;
bool Dedicated::IsEnabled()
{
@ -250,9 +252,15 @@ namespace Components
}
void Dedicated::Heartbeat()
{
int masterPort = Dvar::Var("masterPort").get<int>();
const char* masterServerName = Dvar::Var("masterServerName").get<const char*>();
{
// Do not send a heartbeat if sv_lanOnly is set to true
if (Dedicated::SVLanOnly.get<bool>())
{
return;
}
auto masterPort = Dvar::Var("masterPort").get<int>();
const auto* masterServerName = Dvar::Var("masterServerName").get<const char*>();
Network::Address master(Utils::String::VA("%s:%u", masterServerName, masterPort));
@ -290,7 +298,11 @@ namespace Components
// Make sure all callbacks are handled
Scheduler::OnFrame(Steam::SteamAPI_RunCallbacks);
Dvar::Register<bool>("sv_lanOnly", false, Game::dvar_flag::DVAR_NONE, "Don't act as node");
Dvar::OnInit([]
{
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();

View File

@ -8,6 +8,7 @@ namespace Components
Dedicated();
static SteamID PlayerGuids[18][2];
static Dvar::Var SVLanOnly;
static bool IsEnabled();

View File

@ -964,7 +964,7 @@ namespace Components
Download::ScriptDownloads.clear();
});
Script::AddFunction("HttpGet", []()
Script::AddFunction("HttpGet", []
{
if (!Flags::HasFlag("scriptablehttp"))
return;
@ -985,7 +985,7 @@ namespace Components
Game::RemoveRefToObject(object);
});
Script::AddFunction("HttpCancel", []()
Script::AddFunction("HttpCancel", []
{
if (!Flags::HasFlag("scriptablehttp"))
return;

View File

@ -16,9 +16,9 @@ namespace Components
const auto elevatorSetting = Elevators::BG_Elevators.get<int>();
while (true)
{
point[0] = ps->origin[0] + Game::CorrectSolidDeltas[i][0];
point[1] = ps->origin[1] + Game::CorrectSolidDeltas[i][1];
point[2] = ps->origin[2] + Game::CorrectSolidDeltas[i][2];
point[0] = ps->origin[0] + (*Game::CorrectSolidDeltas)[i][0];
point[1] = ps->origin[1] + (*Game::CorrectSolidDeltas)[i][1];
point[2] = ps->origin[2] + (*Game::CorrectSolidDeltas)[i][2];
Game::PM_playerTrace(pm, trace, point, point, &pm->bounds, ps->clientNum, pm->tracemask);
@ -40,8 +40,8 @@ namespace Components
}
}
i += 1;
if (i >= 26)
++i;
if (i >= 26) // CorrectSolidDeltas count
{
ps->groundEntityNum = Game::ENTITYNUM_NONE;
pml->groundPlane = 0;
@ -62,15 +62,15 @@ namespace Components
return 1;
}
void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* trace, const float* f3,
const float* f4, const Game::Bounds* bounds, int a6, int a7)
void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* results, const float* start,
const float* end, const Game::Bounds* bounds, int passEntityNum, int contentMask)
{
Game::PM_Trace(pm, trace, f3, f4, bounds, a6, a7);
Game::PM_Trace(pm, results, start, end, bounds, passEntityNum, contentMask);
// Allow the player to stand even when there is no headroom
if (Elevators::BG_Elevators.get<int>() == Elevators::EASY)
{
trace->allsolid = false;
results->allsolid = false;
}
}
@ -111,8 +111,7 @@ namespace Components
Elevators::ENABLED, Game::DVAR_CODINFO, "Elevators glitch settings");
});
//Replace PM_CorrectAllSolid
Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick();
Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); // PM_GroundTrace
// Place hooks in PM_CheckDuck. If the elevators dvar is set to easy the
// flags for duck/prone will always be removed from the player state

View File

@ -193,24 +193,6 @@ namespace Components
{
Exception::SetMiniDumpType(Flags::HasFlag("bigminidumps"), Flags::HasFlag("reallybigminidumps"));
#ifdef DEBUG
// Display DEBUG branding, so we know we're on a debug build
Scheduler::OnFrame([]()
{
auto* font = Game::R_RegisterFont("fonts/normalFont", 0);
Game::vec4_t color = { 1.0f, 1.0f, 1.0f, 1.0f };
// Change the color when attaching a debugger
if (IsDebuggerPresent())
{
color[0] = 0.6588f;
color[1] = 1.0000f;
color[2] = 0.0000f;
}
Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED);
}, true);
#endif
#if !defined(DEBUG) || defined(FORCE_EXCEPTION_HANDLER)
Exception::SetFilterHook.initialize(SetUnhandledExceptionFilter, Exception::SetUnhandledExceptionFilterStub, HOOK_JUMP);
Exception::SetFilterHook.install();

View File

@ -661,7 +661,8 @@ namespace Components
Game::AimAssist_UpdateAdsLerp(input);
AimAssist_ApplyTurnRates(input, output);
Game::AimAssist_ApplyAutoMelee(input, output);
// Automelee has already been done by keyboard so don't do it again
AimAssist_ApplyLockOn(input, output);
}
@ -886,8 +887,6 @@ namespace Components
AimAssist_UpdateGamePadInput(&aimInput, &aimOutput);
clientActive.clViewangles[0] = aimOutput.pitch;
clientActive.clViewangles[1] = aimOutput.yaw;
cmd->meleeChargeDist = aimOutput.meleeChargeDist;
cmd->meleeChargeYaw = aimOutput.meleeChargeYaw;
}
}
@ -1033,6 +1032,13 @@ namespace Components
void Gamepad::UI_GamepadKeyEvent(const int gamePadIndex, const int key, const bool down)
{
// If we are currently capturing a key for menu bind inputs then do not map keys and pass to game
if (*Game::g_waitingForKey)
{
Game::UI_KeyEvent(gamePadIndex, key, down);
return;
}
for (const auto& mapping : controllerMenuKeyMappings)
{
if (mapping.controllerKey == key)
@ -1711,8 +1717,8 @@ namespace Components
{
gpad_enabled = Dvar::Register<bool>("gpad_enabled", false, Game::DVAR_ARCHIVE, "Game pad enabled");
gpad_debug = Dvar::Register<bool>("gpad_debug", false, Game::DVAR_NONE, "Game pad debugging");
gpad_present = Dvar::Register<bool>("gpad_present", false, Game::DVAR_NONE, "Game pad present");
gpad_in_use = Dvar::Register<bool>("gpad_in_use", false, Game::DVAR_NONE, "A game pad is in use");
gpad_present = Dvar::Register<bool>("gpad_present", false, Game::DVAR_READONLY, "Game pad present");
gpad_in_use = Dvar::Register<bool>("gpad_in_use", false, Game::DVAR_READONLY, "A game pad is in use");
gpad_style = Dvar::Register<bool>("gpad_style", false, Game::DVAR_ARCHIVE, "Switch between Xbox and PS HUD");
gpad_sticksConfig = Dvar::Register<const char*>("gpad_sticksConfig", "", Game::DVAR_ARCHIVE, "Game pad stick configuration");
gpad_buttonConfig = Dvar::Register<const char*>("gpad_buttonConfig", "", Game::DVAR_ARCHIVE, "Game pad button configuration");
@ -1720,15 +1726,15 @@ namespace Components
gpad_menu_scroll_delay_rest = Dvar::Register<int>("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_ARCHIVE,
"Menu scroll key-repeat delay, for repeats after the first, in milliseconds");
gpad_rumble = Dvar::Register<bool>("gpad_rumble", true, Game::DVAR_ARCHIVE, "Enable game pad rumble");
gpad_stick_pressed_hysteresis = Dvar::Register<float>("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, Game::DVAR_NONE,
gpad_stick_pressed_hysteresis = Dvar::Register<float>("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, Game::DVAR_ARCHIVE,
"Game pad stick pressed no-change-zone around gpad_stick_pressed to prevent bouncing");
gpad_stick_pressed = Dvar::Register<float>("gpad_stick_pressed", 0.4f, 0.0, 1.0, Game::DVAR_NONE, "Game pad stick pressed threshhold");
gpad_stick_deadzone_max = Dvar::Register<float>("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum stick deadzone");
gpad_stick_deadzone_min = Dvar::Register<float>("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad minimum stick deadzone");
gpad_button_deadzone = Dvar::Register<float>("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad button deadzone threshhold");
gpad_button_lstick_deflect_max = Dvar::Register<float>("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum pad stick pressed value");
gpad_button_rstick_deflect_max = Dvar::Register<float>("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum pad stick pressed value");
gpad_use_hold_time = Dvar::Register<int>("gpad_use_hold_time", 250, 0, std::numeric_limits<int>::max(), Game::DVAR_NONE, "Time to hold the 'use' button on gamepads to activate use");
gpad_stick_pressed = Dvar::Register<float>("gpad_stick_pressed", 0.4f, 0.0, 1.0, Game::DVAR_ARCHIVE, "Game pad stick pressed threshhold");
gpad_stick_deadzone_max = Dvar::Register<float>("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum stick deadzone");
gpad_stick_deadzone_min = Dvar::Register<float>("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad minimum stick deadzone");
gpad_button_deadzone = Dvar::Register<float>("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad button deadzone threshhold");
gpad_button_lstick_deflect_max = Dvar::Register<float>("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum pad stick pressed value");
gpad_button_rstick_deflect_max = Dvar::Register<float>("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum pad stick pressed value");
gpad_use_hold_time = Dvar::Register<int>("gpad_use_hold_time", 250, 0, std::numeric_limits<int>::max(), Game::DVAR_ARCHIVE, "Time to hold the 'use' button on gamepads to activate use");
gpad_lockon_enabled = Dvar::Register<bool>("gpad_lockon_enabled", true, Game::DVAR_ARCHIVE, "Game pad lockon aim assist enabled");
gpad_slowdown_enabled = Dvar::Register<bool>("gpad_slowdown_enabled", true, Game::DVAR_ARCHIVE, "Game pad slowdown aim assist enabled");
@ -1777,19 +1783,19 @@ namespace Components
return command;
}
int Gamepad::Key_GetCommandAssignmentInternal_Hk(const char* cmd, int (*keys)[2])
int Gamepad::Key_GetCommandAssignmentInternal([[maybe_unused]] int localClientNum, const char* cmd, int (*keys)[2])
{
auto keyCount = 0;
if (gamePads[0].inUse)
{
cmd = GetGamePadCommand(cmd);
const auto gamePadCmd = GetGamePadCommand(cmd);
for (auto keyNum = 0; keyNum < Game::K_LAST_KEY; keyNum++)
{
if (!Key_IsValidGamePadChar(keyNum))
continue;
if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0)
if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, gamePadCmd) == 0)
{
(*keys)[keyCount++] = keyNum;
@ -1818,6 +1824,35 @@ namespace Components
return keyCount;
}
void __declspec(naked) Gamepad::Key_GetCommandAssignmentInternal_Stub()
{
__asm
{
push eax
pushad
push [esp + 0x20 + 0x4 + 0x8] // keyNums
push [esp + 0x20 + 0x4 + 0x8] // command
push eax // localClientNum
call Key_GetCommandAssignmentInternal
add esp, 0xC
mov[esp + 0x20], eax
popad
pop eax
ret
}
}
void Gamepad::Key_SetBinding_Hk(const int localClientNum, const int keyNum, const char* binding)
{
if(Key_IsValidGamePadChar(keyNum))
gpad_buttonConfig.set("custom");
Game::Key_SetBinding(localClientNum, keyNum, binding);
}
void Gamepad::CL_KeyEvent_Hk(const int localClientNum, const int key, const int down, const unsigned time)
{
// A keyboard key has been pressed. Mark controller as unused.
@ -1833,13 +1868,18 @@ namespace Components
return gamePads[0].inUse;
}
int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy)
void Gamepad::OnMouseMove([[maybe_unused]] const int x, [[maybe_unused]] const int y, const int dx, const int dy)
{
if (dx != 0 || dy != 0)
{
gamePads[0].inUse = false;
gpad_in_use.setRaw(false);
}
}
int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy)
{
OnMouseMove(x, y, dx, dy);
// Call original function
return Utils::Hook::Call<int(int, int, int, int)>(0x4D7C50)(x, y, dx, dy);
@ -1949,7 +1989,12 @@ namespace Components
Utils::Hook(0x48E527, UI_RefreshViewport_Hk, HOOK_CALL).install()->quick();
// Only return gamepad keys when gamepad enabled and only non gamepad keys when not
Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x5A7890, Key_GetCommandAssignmentInternal_Stub, HOOK_JUMP).install()->quick();
// Whenever a key binding for a gamepad key is replaced update the button config
Utils::Hook(0x47D473, Key_SetBinding_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x47D485, Key_SetBinding_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x47D49D, Key_SetBinding_Hk, HOOK_CALL).install()->quick();
// Add gamepad inputs to remote control (eg predator) handling
Utils::Hook(0x5A6D4E, CL_RemoteControlMove_Stub, HOOK_CALL).install()->quick();

View File

@ -41,6 +41,8 @@ namespace Components
public:
Gamepad();
static void OnMouseMove(int x, int y, int dx, int dy);
private:
static Game::ButtonToCodeMap_t buttonList[];
static Game::StickToCodeMap_t analogStickList[4];
@ -190,7 +192,9 @@ namespace Components
static void CG_RegisterDvars_Hk();
static const char* GetGamePadCommand(const char* command);
static int Key_GetCommandAssignmentInternal_Hk(const char* cmd, int(*keys)[2]);
static int Key_GetCommandAssignmentInternal(int localClientNum, const char* cmd, int (*keys)[2]);
static void Key_GetCommandAssignmentInternal_Stub();
static void Key_SetBinding_Hk(int localClientNum, int keyNum, const char* binding);
static bool IsGamePadInUse();
static void CL_KeyEvent_Hk(int localClientNum, int key, int down, unsigned int time);
static int CL_MouseEvent_Hk(int x, int y, int dx, int dy);

View File

@ -114,7 +114,7 @@ namespace Components
void Node::StoreNodes(bool force)
{
if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get<bool>()) return;
if (Dedicated::IsEnabled() && Dedicated::SVLanOnly.get<bool>()) return;
static Utils::Time::Interval interval;
if (!force && !interval.elapsed(1min)) return;
@ -167,13 +167,17 @@ namespace Components
void Node::RunFrame()
{
if (ServerList::useMasterServer) return;
if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get<bool>()) return;
if (Dedicated::IsEnabled() && Dedicated::SVLanOnly.get<bool>()) return;
if (!Dedicated::IsEnabled() && *Game::clcState > 0)
if (!Dedicated::IsEnabled())
{
wasIngame = true;
return; // don't run while ingame because it can still cause lag spikes on lower end PCs
if (ServerList::useMasterServer) return; // don't run node frame if master server is active
if (*Game::clcState > 0)
{
wasIngame = true;
return; // don't run while ingame because it can still cause lag spikes on lower end PCs
}
}
if (wasIngame) // our last frame we were ingame and now we aren't so touch all nodes

View File

@ -229,12 +229,6 @@ namespace Components
}
}
Game::dvar_t* QuickPatch::Dvar_RegisterUIBuildLocation(const char* dvarName,
float /*x*/, float /*y*/, float min, float max, int /*flags*/, const char* description)
{
return Game::Dvar_RegisterVec2(dvarName, -60.0f, 474.0f, min, max, Game::DVAR_READONLY, description);
}
QuickPatch::QuickPatch()
{
// quitHard
@ -304,22 +298,6 @@ namespace Components
// fs_basegame
Utils::Hook::Set<const char*>(0x6431D1, BASEGAME);
// UI version string
Utils::Hook::Set<const char*>(0x43F73B, "IW4x: " VERSION);
// console version string
Utils::Hook::Set<const char*>(0x4B12BB, "IW4x " VERSION " (built " __DATE__ " " __TIME__ ")");
// version string
Utils::Hook::Set<const char*>(0x60BD56, "IW4x (" VERSION ")");
// version string color
static Game::vec4_t buildLocColor = { 1.0f, 1.0f, 1.0f, 0.8f };
Utils::Hook::Set<float*>(0x43F710, buildLocColor);
// Shift ui version string to the left (ui_buildlocation)
Utils::Hook(0x6310A0, QuickPatch::Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick();
// console title
if (ZoneBuilder::IsEnabled())
{
@ -340,9 +318,6 @@ namespace Components
// sv_hostname
Utils::Hook::Set<const char*>(0x4D378B, "IW4Host");
// shortversion
Utils::Hook::Set<const char*>(0x60BD91, SHORTVERSION);
// console logo
Utils::Hook::Set<const char*>(0x428A66, BASEGAME "/images/logo.bmp");

View File

@ -27,7 +27,5 @@ namespace Components
static void CL_KeyEvent_OnEscape();
static void CL_KeyEvent_ConsoleEscape_Stub();
static Game::dvar_t* Dvar_RegisterUIBuildLocation(const char* dvarName, float x, float y, float min, float max, int flags, const char* description);
};
}

View File

@ -97,6 +97,7 @@ namespace Components
Game::s_wmv->oldPos = curPos;
ScreenToClient(Window::GetWindow(), &curPos);
Gamepad::OnMouseMove(curPos.x, curPos.y, dx, dy);
auto recenterMouse = Game::CL_MouseEvent(curPos.x, curPos.y, dx, dy);
if (recenterMouse)

View File

@ -431,7 +431,7 @@ namespace Components
{
std::memmove(&Game::scrVmPub->top[-4], &Game::scrVmPub->top[-5], sizeof(Game::VariableValue) * 6);
Game::scrVmPub->top += 1;
Game::scrVmPub->top[-6].type = Game::VAR_FLOAT;
Game::scrVmPub->top[-6].type = Game::scrParamType_t::VAR_FLOAT;
Game::scrVmPub->top[-6].u.floatValue = 0.0f;
++Game::scrVmPub->outparamcount;
@ -450,7 +450,7 @@ namespace Components
const auto value = &Game::scrVmPub->top[-index];
if (value->type != Game::VAR_FUNCTION)
if (value->type != Game::scrParamType_t::VAR_FUNCTION)
{
Game::Scr_ParamError(static_cast<unsigned int>(index), "^1GetCodePosForParam: Expects a function as parameter!\n");
return "";
@ -549,7 +549,7 @@ namespace Components
void Script::AddFunctions()
{
Script::AddFunction("ReplaceFunc", []() // gsc: ReplaceFunc(<function>, <function>)
Script::AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(<function>, <function>)
{
if (Game::Scr_GetNumParam() != 2u)
{
@ -564,15 +564,7 @@ namespace Components
});
// System time
Script::AddFunction("GetSystemTime", []() // gsc: GetSystemTime()
{
SYSTEMTIME time;
GetSystemTime(&time);
Game::Scr_AddInt(time.wSecond);
});
Script::AddFunction("GetSystemMilliseconds", []() // gsc: GetSystemMilliseconds()
Script::AddFunction("GetSystemMilliseconds", [] // gsc: GetSystemMilliseconds()
{
SYSTEMTIME time;
GetSystemTime(&time);
@ -581,7 +573,7 @@ namespace Components
});
// Executes command to the console
Script::AddFunction("Exec", []() // gsc: Exec(<string>)
Script::AddFunction("Exec", [] // gsc: Exec(<string>)
{
const auto str = Game::Scr_GetString(0);
@ -595,7 +587,7 @@ namespace Components
});
// Allow printing to the console even when developer is 0
Script::AddFunction("PrintConsole", []() // gsc: PrintConsole(<string>)
Script::AddFunction("PrintConsole", [] // gsc: PrintConsole(<string>)
{
for (auto i = 0u; i < Game::Scr_GetNumParam(); i++)
{
@ -612,7 +604,7 @@ namespace Components
});
// Script Storage Functions
Script::AddFunction("StorageSet", []() // gsc: StorageSet(<str key>, <str data>);
Script::AddFunction("StorageSet", [] // gsc: StorageSet(<str key>, <str data>);
{
const auto* key = Game::Scr_GetString(0);
const auto* value = Game::Scr_GetString(1);
@ -626,7 +618,7 @@ namespace Components
Script::ScriptStorage.insert_or_assign(key, value);
});
Script::AddFunction("StorageRemove", []() // gsc: StorageRemove(<str key>);
Script::AddFunction("StorageRemove", [] // gsc: StorageRemove(<str key>);
{
const auto* key = Game::Scr_GetString(0);
@ -645,7 +637,7 @@ namespace Components
Script::ScriptStorage.erase(key);
});
Script::AddFunction("StorageGet", []() // gsc: StorageGet(<str key>);
Script::AddFunction("StorageGet", [] // gsc: StorageGet(<str key>);
{
const auto* key = Game::Scr_GetString(0);
@ -665,7 +657,7 @@ namespace Components
Game::Scr_AddString(data.data());
});
Script::AddFunction("StorageHas", []() // gsc: StorageHas(<str key>);
Script::AddFunction("StorageHas", [] // gsc: StorageHas(<str key>);
{
const auto* key = Game::Scr_GetString(0);
@ -678,7 +670,7 @@ namespace Components
Game::Scr_AddBool(static_cast<int>(Script::ScriptStorage.count(key))); // Until C++17
});
Script::AddFunction("StorageClear", []() // gsc: StorageClear();
Script::AddFunction("StorageClear", [] // gsc: StorageClear();
{
Script::ScriptStorage.clear();
});
@ -746,7 +738,7 @@ namespace Components
});
#ifdef _DEBUG
Script::AddFunction("DebugBox", []()
Script::AddFunction("DebugBox", []
{
const auto* message = Game::Scr_GetString(0);

View File

@ -116,7 +116,7 @@ namespace Components
void ScriptExtension::AddFunctions()
{
// File functions
Script::AddFunction("FileWrite", []() // gsc: FileWrite(<filepath>, <string>, <mode>)
Script::AddFunction("FileWrite", [] // gsc: FileWrite(<filepath>, <string>, <mode>)
{
const auto* path = Game::Scr_GetString(0);
auto* text = Game::Scr_GetString(1);
@ -159,7 +159,7 @@ namespace Components
}
});
Script::AddFunction("FileRead", []() // gsc: FileRead(<filepath>)
Script::AddFunction("FileRead", [] // gsc: FileRead(<filepath>)
{
const auto* path = Game::Scr_GetString(0);
@ -187,7 +187,7 @@ namespace Components
Game::Scr_AddString(FileSystem::FileReader(path).getBuffer().data());
});
Script::AddFunction("FileExists", []() // gsc: FileExists(<filepath>)
Script::AddFunction("FileExists", [] // gsc: FileExists(<filepath>)
{
const auto* path = Game::Scr_GetString(0);
@ -209,7 +209,7 @@ namespace Components
Game::Scr_AddInt(FileSystem::FileReader(path).exists());
});
Script::AddFunction("FileRemove", []() // gsc: FileRemove(<filepath>)
Script::AddFunction("FileRemove", [] // gsc: FileRemove(<filepath>)
{
const auto* path = Game::Scr_GetString(0);
@ -235,7 +235,7 @@ namespace Components
});
// Misc functions
Script::AddFunction("ToUpper", []() // gsc: ToUpper(<string>)
Script::AddFunction("ToUpper", [] // gsc: ToUpper(<string>)
{
const auto scriptValue = Game::Scr_GetConstString(0);
const auto* string = Game::SL_ConvertToString(scriptValue);
@ -280,7 +280,7 @@ namespace Components
});
// Func present on IW5
Script::AddFunction("StrICmp", []() // gsc: StrICmp(<string>, <string>)
Script::AddFunction("StrICmp", [] // gsc: StrICmp(<string>, <string>)
{
const auto value1 = Game::Scr_GetConstString(0);
const auto value2 = Game::Scr_GetConstString(1);
@ -292,7 +292,7 @@ namespace Components
});
// Func present on IW5
Script::AddFunction("IsEndStr", []() // gsc: IsEndStr(<string>, <string>)
Script::AddFunction("IsEndStr", [] // gsc: IsEndStr(<string>, <string>)
{
const auto* s1 = Game::Scr_GetString(0);
const auto* s2 = Game::Scr_GetString(1);
@ -305,6 +305,26 @@ namespace Components
Game::Scr_AddBool(Utils::String::EndsWith(s1, s2));
});
Script::AddFunction("IsArray", [] // gsc: IsArray(<object>)
{
const auto type = Game::Scr_GetType(0);
bool result;
if (type == Game::scrParamType_t::VAR_POINTER)
{
const auto ptr_type = Game::Scr_GetPointerType(0);
assert(ptr_type >= Game::FIRST_OBJECT);
result = (ptr_type == Game::scrParamType_t::VAR_ARRAY);
}
else
{
assert(type < Game::FIRST_OBJECT);
result = false;
}
Game::Scr_AddBool(result);
});
}
void ScriptExtension::AddMethods()

View File

@ -199,6 +199,11 @@ namespace Components
}
void ServerList::RefreshVisibleList(UIScript::Token)
{
ServerList::RefreshVisibleListInternal(UIScript::Token());
}
void ServerList::RefreshVisibleListInternal(UIScript::Token, bool refresh)
{
Dvar::Var("ui_serverSelected").set(false);
@ -207,6 +212,12 @@ namespace Components
auto list = ServerList::GetList();
if (!list) return;
if (refresh)
{
ServerList::Refresh(UIScript::Token());
return;
}
bool ui_browserShowFull = Dvar::Var("ui_browserShowFull").get<bool>();
bool ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get<bool>();
int ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get<int>();
@ -368,7 +379,7 @@ namespace Components
auto list = ServerList::GetList();
if (list) list->clear();
ServerList::RefreshVisibleList(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token());
Game::ShowMessageBox("Server removed from favourites.", "Success");
}
@ -530,7 +541,7 @@ namespace Components
if (lList)
{
lList->push_back(server);
ServerList::RefreshVisibleList(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token());
}
}
@ -693,7 +704,7 @@ namespace Components
netSource.set(source);
ServerList::RefreshVisibleList(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token(), true);
}
void ServerList::UpdateGameType()
@ -709,7 +720,7 @@ namespace Components
joinGametype.set(gametype);
ServerList::RefreshVisibleList(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token());
}
void ServerList::UpdateVisibleInfo()

View File

@ -35,6 +35,7 @@ namespace Components
static void Refresh(UIScript::Token);
static void RefreshVisibleList(UIScript::Token);
static void RefreshVisibleListInternal(UIScript::Token, bool refresh = false);
static void UpdateVisibleList(UIScript::Token);
static void InsertRequest(Network::Address address);
static void Insert(Network::Address address, Utils::InfoString info);

View File

@ -100,7 +100,7 @@ namespace Components
}
}
void Window::DrawCursorStub(void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Game::Material *material)
void Window::DrawCursorStub(Game::ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Game::Material* material)
{
if (Window::NativeCursor.get<bool>())
{

View File

@ -40,7 +40,7 @@ namespace Components
static BOOL WINAPI MessageHandler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
static int WINAPI ShowCursorHook(BOOL show);
static void DrawCursorStub(void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Game::Material *material);
static void DrawCursorStub(Game::ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Game::Material* material);
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);

View File

@ -171,6 +171,7 @@ namespace Game
Key_SetCatcher_t Key_SetCatcher = Key_SetCatcher_t(0x43BD00);
Key_RemoveCatcher_t Key_RemoveCatcher = Key_RemoveCatcher_t(0x408260);
Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive = Key_IsKeyCatcherActive_t(0x4DA010);
Key_SetBinding_t Key_SetBinding = Key_SetBinding_t(0x494C90);
LargeLocalInit_t LargeLocalInit = LargeLocalInit_t(0x4A62A0);
@ -293,6 +294,7 @@ namespace Game
Scr_ParamError_t Scr_ParamError = Scr_ParamError_t(0x4FBC70);
Scr_GetType_t Scr_GetType = Scr_GetType_t(0x422900);
Scr_GetPointerType_t Scr_GetPointerType = Scr_GetPointerType_t(0x4828E0);
Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0);
@ -385,6 +387,7 @@ namespace Game
UI_DrawHandlePic_t UI_DrawHandlePic = UI_DrawHandlePic_t(0x4D0EA0);
ScrPlace_GetActivePlacement_t ScrPlace_GetActivePlacement = ScrPlace_GetActivePlacement_t(0x4F8940);
UI_TextWidth_t UI_TextWidth = UI_TextWidth_t(0x6315C0);
UI_TextHeight_t UI_TextHeight = UI_TextHeight_t(0x4C8630);
UI_DrawText_t UI_DrawText = UI_DrawText_t(0x49C0D0);
UI_GetFontHandle_t UI_GetFontHandle = UI_GetFontHandle_t(0x4AEA60);
ScrPlace_ApplyRect_t ScrPlace_ApplyRect = ScrPlace_ApplyRect_t(0x454E20);
@ -546,17 +549,21 @@ namespace Game
FastCriticalSection* db_hashCritSect = reinterpret_cast<FastCriticalSection*>(0x16B8A54);
vec3_t* CorrectSolidDeltas = reinterpret_cast<vec3_t*>(0x739BB8); // Count 26
ScreenPlacement* scrPlaceFullUnsafe = reinterpret_cast<ScreenPlacement*>(0x1084460);
float (*CorrectSolidDeltas)[26][3] = reinterpret_cast<float(*)[26][3]>(0x739BB8); // Count 26
level_locals_t* level = reinterpret_cast<level_locals_t*>(0x1A831A8);
float(*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT] = reinterpret_cast<float(*)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT]>(0x7C4878);
float (*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT] = reinterpret_cast<float(*)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT]>(0x7C4878);
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);
int* g_waitingForKey = reinterpret_cast<int*>(0x63A50FC);
void Sys_LockRead(FastCriticalSection* critSect)
{
InterlockedIncrement(&critSect->readCount);
@ -1121,6 +1128,11 @@ namespace Game
return GraphGetValueFromFraction(graph->knotCount, graph->knots, fraction) * graph->scale;
}
ScreenPlacement* ScrPlace_GetUnsafeFullPlacement()
{
return scrPlaceFullUnsafe;
}
#pragma optimize("", off)
__declspec(naked) float UI_GetScoreboardLeft(void* /*a1*/)
{

View File

@ -420,6 +420,9 @@ namespace Game
typedef bool(__cdecl * Key_IsKeyCatcherActive_t)(int localClientNum, int catcher);
extern Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive;
typedef void(__cdecl * Key_SetBinding_t)(int localClientNum, int keyNum, const char* binding);
extern Key_SetBinding_t Key_SetBinding;
typedef void(__cdecl * LargeLocalInit_t)();
extern LargeLocalInit_t LargeLocalInit;
@ -735,9 +738,12 @@ namespace Game
typedef bool(__cdecl * Scr_IsSystemActive_t)();
extern Scr_IsSystemActive_t Scr_IsSystemActive;
typedef int(__cdecl * Scr_GetType_t)(unsigned int);
typedef int(__cdecl * Scr_GetType_t)(unsigned int index);
extern Scr_GetType_t Scr_GetType;
typedef int(__cdecl * Scr_GetPointerType_t)(unsigned int index);
extern Scr_GetPointerType_t Scr_GetPointerType;
typedef void(__cdecl * Scr_Error_t)(const char*);
extern Scr_Error_t Scr_Error;
@ -885,7 +891,7 @@ namespace Game
typedef bool(__cdecl * Sys_IsDatabaseThread_t)();
extern Sys_IsDatabaseThread_t Sys_IsDatabaseThread;
typedef char** (__cdecl * Sys_ListFiles_t)(const char *directory, const char *extension, const char *filter, int *numfiles, int wantsubs);
typedef char**(__cdecl * Sys_ListFiles_t)(const char* directory, const char* extension, const char* filter, int* numfiles, int wantsubs);
extern Sys_ListFiles_t Sys_ListFiles;
typedef int(__cdecl * Sys_Milliseconds_t)();
@ -930,28 +936,31 @@ namespace Game
typedef void(__cdecl * UI_SortArenas_t)();
extern UI_SortArenas_t UI_SortArenas;
typedef void(__cdecl * UI_DrawHandlePic_t)(/*ScreenPlacement*/void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Material *material);
typedef void(__cdecl * UI_DrawHandlePic_t)(ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Material* material);
extern UI_DrawHandlePic_t UI_DrawHandlePic;
typedef ScreenPlacement*(__cdecl * ScrPlace_GetActivePlacement_t)(int localClientNum);
extern ScrPlace_GetActivePlacement_t ScrPlace_GetActivePlacement;
typedef int(__cdecl * UI_TextWidth_t)(const char *text, int maxChars, Font_s *font, float scale);
typedef int(__cdecl * UI_TextWidth_t)(const char* text, int maxChars, Font_s* font, float scale);
extern UI_TextWidth_t UI_TextWidth;
typedef int(__cdecl * UI_TextHeight_t)(Font_s* font, float scale);
extern UI_TextHeight_t UI_TextHeight;
typedef void(__cdecl * UI_DrawText_t)(const ScreenPlacement* scrPlace, const char* text, int maxChars, Font_s* font, float x, float y, int horzAlign, int vertAlign, float scale, const float* color, int style);
extern UI_DrawText_t UI_DrawText;
typedef Font_s* (__cdecl* UI_GetFontHandle_t)(ScreenPlacement* scrPlace, int fontEnum, float scale);
extern UI_GetFontHandle_t UI_GetFontHandle;
typedef void(__cdecl* ScrPlace_ApplyRect_t)(ScreenPlacement* a1, float* x, float* y, float* w, float* h, int horzAlign, int vertAlign);
typedef void(__cdecl* ScrPlace_ApplyRect_t)(const ScreenPlacement* scrPlace, float* x, float* y, float* w, float* h, int horzAlign, int vertAlign);
extern ScrPlace_ApplyRect_t ScrPlace_ApplyRect;
typedef const char * (__cdecl * Win_GetLanguage_t)();
typedef const char*(__cdecl * Win_GetLanguage_t)();
extern Win_GetLanguage_t Win_GetLanguage;
typedef void (__cdecl * Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t *);
typedef void(__cdecl * Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t*);
extern Vec3UnpackUnitVec_t Vec3UnpackUnitVec;
typedef float(__cdecl * vectoyaw_t)(vec2_t* vec);
@ -996,10 +1005,10 @@ namespace Game
typedef void(__cdecl * Jump_ClearState_t)(playerState_s* ps);
extern Jump_ClearState_t Jump_ClearState;
typedef void(__cdecl * PM_playerTrace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int);
typedef void(__cdecl * PM_playerTrace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask);
extern PM_playerTrace_t PM_playerTrace;
typedef void(__cdecl * PM_Trace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int);
typedef void(__cdecl * PM_Trace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask);
extern PM_Trace_t PM_Trace;
typedef EffectiveStance(__cdecl * PM_GetEffectiveStance_t)(const playerState_s* ps);
@ -1142,24 +1151,30 @@ namespace Game
constexpr auto MAX_MODELS = 512;
extern XModel** cached_models;
extern vec3_t* CorrectSolidDeltas;
extern float (*CorrectSolidDeltas)[26][3];
extern FastCriticalSection* db_hashCritSect;
extern ScreenPlacement* scrPlaceFullUnsafe;
extern level_locals_t* level;
extern float(*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT];
extern float (*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT];
extern WinMouseVars_t* s_wmv;
extern int* window_center_x;
extern int* window_center_y;
extern int* g_waitingForKey;
void Sys_LockRead(FastCriticalSection* critSect);
void Sys_UnlockRead(FastCriticalSection* critSect);
XModel* G_GetModel(int index);
ScreenPlacement* ScrPlace_GetUnsafeFullPlacement();
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize);
void Menu_FreeItemMemory(Game::itemDef_s* item);
void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1);

View File

@ -234,7 +234,7 @@ namespace Game
CS_ACTIVE = 0x5,
} clientstate_t;
typedef enum
enum errorParm_t
{
ERR_FATAL = 0x0,
ERR_DROP = 0x1,
@ -244,7 +244,39 @@ namespace Game
ERR_SCRIPT_DROP = 0x5,
ERR_LOCALIZATION = 0x6,
ERR_MAPLOADERRORSUMMARY = 0x7
} errorParm_t;
};
enum conChannel_t
{
CON_CHANNEL_DONT_FILTER,
CON_CHANNEL_ERROR,
CON_CHANNEL_GAMENOTIFY,
CON_CHANNEL_BOLDGAME,
CON_CHANNEL_SUBTITLE,
CON_CHANNEL_OBITUARY,
CON_CHANNEL_LOGFILEONLY,
CON_CHANNEL_CONSOLEONLY,
CON_CHANNEL_GFX,
CON_CHANNEL_SOUND,
CON_CHANNEL_FILES,
CON_CHANNEL_DEVGUI,
CON_CHANNEL_PROFILE,
CON_CHANNEL_UI,
CON_CHANNEL_CLIENT,
CON_CHANNEL_SERVER,
CON_CHANNEL_SYSTEM,
CON_CHANNEL_PLAYERWEAP,
CON_CHANNEL_AI,
CON_CHANNEL_ANIM,
CON_CHANNEL_PHYS,
CON_CHANNEL_FX,
CON_CHANNEL_LEADERBOARDS,
CON_CHANNEL_PARSERSCRIPT,
CON_CHANNEL_SCRIPT,
CON_CHANNEL_NETWORK,
CON_BUILTIN_CHANNEL_COUNT,
};
enum entityFlag
{
@ -5096,7 +5128,7 @@ namespace Game
char buf[1];
};
enum VariableType
enum scrParamType_t
{
VAR_UNDEFINED = 0x0,
VAR_BEGIN_REF = 0x1,
@ -5114,21 +5146,30 @@ namespace Game
VAR_BUILTIN_METHOD = 0xB,
VAR_STACK = 0xC,
VAR_ANIMATION = 0xD,
VAR_PRE_ANIMATION = 0xE,
VAR_THREAD = 0xF,
VAR_NOTIFY_THREAD = 0x10,
VAR_TIME_THREAD = 0x11,
VAR_CHILD_THREAD = 0x12,
VAR_OBJECT = 0x13,
VAR_DEAD_ENTITY = 0x14,
VAR_ENTITY = 0x15,
VAR_ARRAY = 0x16,
VAR_DEAD_THREAD = 0x17,
VAR_COUNT = 0x18,
VAR_FREE = 0x18,
VAR_THREAD_LIST = 0x19,
VAR_ENDON_LIST = 0x1A,
VAR_TOTAL_COUNT = 0x1B,
VAR_DEVELOPER_CODEPOS = 0xE,
VAR_PRE_ANIMATION = 0xF,
VAR_THREAD = 0x10,
VAR_NOTIFY_THREAD = 0x11,
VAR_TIME_THREAD = 0x12,
VAR_CHILD_THREAD = 0x13,
VAR_OBJECT = 0x14,
VAR_DEAD_ENTITY = 0x15,
VAR_ENTITY = 0x16,
VAR_ARRAY = 0x17,
VAR_DEAD_THREAD = 0x18,
VAR_COUNT = 0x19,
VAR_THREAD_LIST = 0x1A,
VAR_ENDON_LIST = 0x1B,
};
enum $2441F0C7E439C64E6C27842ECB570A7C
{
FIRST_OBJECT = 0x10,
FIRST_CLEARABLE_OBJECT = 0x14,
LAST_NONENTITY_OBJECT = 0x14,
FIRST_ENTITY_OBJECT = 0x16,
FIRST_NONFIELD_OBJECT = 0x17,
FIRST_DEAD_OBJECT = 0x18,
};
union VariableUnion
@ -5147,7 +5188,7 @@ namespace Game
struct VariableValue
{
VariableUnion u;
VariableType type;
scrParamType_t type;
};
struct function_stack_t