Merge remote-tracking branch 'origin/rf_improve' into octopus-merge

This commit is contained in:
TotallyNotElite 2020-12-28 12:28:45 +01:00
commit 323ce3153b
39 changed files with 454 additions and 158 deletions

View File

@ -5,7 +5,10 @@
<AutoVariable width="fill" target="warp.speed" label="Warp speed" tooltip="The discharge speed (0.5 = +50%, 2 = +200%. +2300% is the maximum possible)."/>
<AutoVariable width="fill" target="warp.key" label="Warp key" tooltip="Pressing this key will use all stored ticks to accelerate you."/>
<AutoVariable width="fill" target="warp.charge-key" label="Charge key" tooltip="Hold down this key to charge warp."/>
<AutoVariable width="fill" target="warp.draw" label="Draw warp" tooltip="Draws a bar indicating your warp readiness."/>
<AutoVariable width="fill" target="warp.draw" label="Draw warp text"/>
<AutoVariable width="fill" target="warp.draw-info.x" label="Text x position"/>
<AutoVariable width="fill" target="warp.draw-info.y" label="Text y position"/>
<AutoVariable width="fill" target="warp.draw-bar" label="Draw warp bar" tooltip="Draws a bar indicating your warp readiness."/>
<AutoVariable width="fill" target="warp.bar-size" label="Bar size"/>
<AutoVariable width="fill" target="warp.bar-x" label="X position"/>
<AutoVariable width="fill" target="warp.bar-y" label="Y position"/>
@ -25,6 +28,8 @@
<Box padding="12 6 6 6" width="content" height="content" name="Rapidfire" x="210">
<List width="185">
<AutoVariable width="fill" target="warp.rapidfire" label="Enable Rapidfire" tooltip="Allows you to shoot multiple shots at once or reduce time between shots."/>
<AutoVariable width="fill" target="warp.rapidfire.distance" label="Minimum distance" tooltip="How close an enemy has to be to be able to rapidfire. 0 is off."/>
<AutoVariable width="fill" target="warp.rapidfire.zoom" label="Enable Rapid zoom" tooltip="Allows you to instantly zoom in."/>
<AutoVariable width="fill" target="warp.rapidfire.no-movement" label="Prevent movement in rapidfire" tooltip="Attempt to not move when Rapidfiring."/>
<AutoVariable width="fill" target="warp.rapidfire.key" label="Rapidfire key" tooltip="Optional. If set you can use this key to control when to rapidfire."/>
<LabeledObject width="fill" label="Rapidfire key mode" tooltip="Controls what the rapidfire key does.">
@ -35,6 +40,14 @@
<Option name="Toggle" value="3"/>
</Select>
</LabeledObject>
<LabeledObject width="fill" label="Disable Rapidfire on">
<Select target="warp.rapidfire.disable-on">
<Option name="None" value="0"/>
<Option name="Projectile" value="1"/>
<Option name="Melee" value="2"/>
<Option name="Projectile + Melee" value="3"/>
</Select>
</LabeledObject>
</List>
</Box>
</Tab>

View File

@ -17,6 +17,7 @@ class ISurface;
class IPanel;
} // namespace vgui
class IToolFrameworkInternal;
class ISteamClient;
class ISteamFriends;
class IVEngineClient013;
@ -95,6 +96,7 @@ extern IUniformRandomStream *g_pUniformStream;
extern int *g_PredictionRandomSeed;
extern IFileSystem *g_IFileSystem;
extern IMDLCache *g_IMDLCache;
extern IToolFrameworkInternal *g_IToolFramework;
void CreateInterfaces();
void CreateEarlyInterfaces();

View File

@ -207,6 +207,7 @@ public:
offset_t m_iPlayerIndex;
offset_t m_hTargetPlayer;
offset_t m_flResetTime;
offset_t m_flMaxspeed;
};
extern NetVars netvar;

View File

@ -228,4 +228,8 @@ struct offsets
{
return PlatformOffset(0x2fb8, undefined, undefined);
}
static constexpr uint32_t Think()
{
return PlatformOffset(27, undefined, undefined);
}
};

View File

@ -18,6 +18,7 @@
#include <gametrace.h>
#include <engine/IEngineTrace.h>
#include <materialsystem/imaterialvar.h>
#include <toolframework/itoolframework.h>
#include <globalvars_base.h>
#include <materialsystem/itexture.h>
#include <engine/ivmodelinfo.h>

View File

@ -3,6 +3,8 @@
class INetMessage;
namespace hacks::tf2::warp
{
extern bool in_rapidfire;
extern bool in_warp;
void SendNetMessage(INetMessage &msg);
void CL_SendMove_hook();
} // namespace hacks::tf2::warp

View File

@ -121,6 +121,7 @@ Vector getShootPos(Vector angle);
Vector GetForwardVector(Vector origin, Vector viewangles, float distance, CachedEntity *punch_entity = nullptr);
Vector GetForwardVector(float distance, CachedEntity *punch_entity = nullptr);
CachedEntity *getClosestEntity(Vector vec);
CachedEntity *getClosestNonlocalEntity(Vector vec);
bool IsSentryBuster(CachedEntity *ent);
std::unique_ptr<char[]> strfmt(const char *fmt, ...);
// TODO move that to weaponid.h
@ -218,7 +219,7 @@ template <typename T, typename... Targs> void format_internal(std::stringstream
stream << value;
format_internal(stream, args...);
}
template <typename... Args> std::string format(const Args &... args)
template <typename... Args> std::string format(const Args &...args)
{
std::stringstream stream;
format_internal(stream, args...);

View File

@ -75,4 +75,5 @@ extern VMTHook materialsystem;
extern VMTHook enginevgui;
extern VMTHook vstd;
extern VMTHook eventmanager2;
extern VMTHook toolbox;
} // namespace hooks

View File

@ -15,10 +15,13 @@ enum ec_types
CreateMoveLate,
/* This kind of CreateMove will run earlier than "CreateMove" events
* and guranteed to run before EnginePrediction
* This is NEEDED for any kind of movement
*/
CreateMove_NoEnginePred,
/* Note: this is still CreateMove, just ran before original is called, needed in some cases like changing tickcount before original gets called*/
CreateMoveEarly,
/* Note: This will replace the normal CreateMove when we are warping. Used for performance purposes. */
CreateMoveWarp,
#if ENABLE_VISUALS
Draw,
#endif

View File

@ -94,6 +94,8 @@ DECLARE_HOOKED_METHOD(EmitSound2, void, void *, IRecipientFilter &, int, int, co
DECLARE_HOOKED_METHOD(EmitSound3, void, void *, IRecipientFilter &, int, int, int, float, soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int);
// g_IPrediction
DECLARE_HOOKED_METHOD(RunCommand, void, IPrediction *, IClientEntity *, CUserCmd *, IMoveHelper *);
// g_IToolFramework
DECLARE_HOOKED_METHOD(Think, void, IToolFrameworkInternal *, bool);
} // namespace hooked_methods
// TODO

6
include/hooks/Think.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
namespace hooked_methods
{
// Update Prediction, Used by warp/Doubletap aswell
void UpdatePred();
} // namespace hooked_methods

View File

@ -26,6 +26,8 @@ public:
// Start of CM
void Update();
// After prediction
void UpdateEye();
// End of CM
void UpdateEnd();
int team;

View File

@ -82,6 +82,13 @@ public:
typedef bool (*fn_t)(IClientEntity *, bool, IClientEntity *);
return vfunc<fn_t>(self, offsets::PlatformOffset(490, offsets::undefined, 490), 0)(self, unknown1, unknown2);
}
inline static float ApplyFireDelay(IClientEntity *self, float delay)
{
typedef float (*ApplyFireDelay_t)(IClientEntity *, float);
static auto signature = gSignatures.GetClientSignature("55 89 E5 57 56 53 83 EC 6C C7 45 ? 00 00 00 00 A1 ? ? ? ? C7 45 ? 00 00 00 00 8B 5D ? 85 C0 0F 84 ? ? ? ? 8D 55 ? 89 04 24 31 F6 89 54 24 ? C7 44 24 ? ? ? ? ? C7 44 24 ? ? ? ? ? C7 44 24 ? ? ? ? ? C7 44 24 ? ? ? ? ? C7 44 24 ? 6B 00 00 00 C7 44 24 ? ? ? ? ? C7 44 24 ? 00 00 00 00 C7 44 24 ? 00 00 00 00 C7 44 24 ? 00 00 00 00 C7 44 24 ? 00 00 00 00 FF 50 ? A1 ? ? ? ? 8B 0D ? ? ? ? 8B 55 ? 89 45 ? 8B 45 ? 85 C9 89 55 ? 89 45 ? 0F 85 ? ? ? ? 85 DB 0F 84 ? ? ? ? 8B 7B ? 85 FF 0F 84 ? ? ? ? C7 04 24 ? ? ? ? E8 ? ? ? ? 89 45 ? 8B 07 89 3C 24 FF 10 8B 7D ? 8B 10 C7 44 24 ? 00 00 00 00 89 5C 24 ? C7 44 24 ? ? ? ? ? 89 7C 24 ? 89 04 24 FF 52 ? D9 5D ? F3 0F 10 45 ? F3 0F 11 04 24 E8 ? ? ? ? D9 5D");
static ApplyFireDelay_t ApplyFireDelay_fn = (ApplyFireDelay_t) signature;
return ApplyFireDelay_fn(self, delay);
}
inline static void AddToCritBucket(IClientEntity *self, float value)
{
constexpr float max_bucket_capacity = 1000.0f;

View File

@ -18,44 +18,45 @@
// class ISteamFriends002;
IVModelRender *g_IVModelRender = nullptr;
ISteamClient *g_ISteamClient = nullptr;
ISteamFriends *g_ISteamFriends = nullptr;
IVEngineClient013 *g_IEngine = nullptr;
void *demoplayer = nullptr;
IEngineSound *g_ISoundEngine = nullptr;
vgui::ISurface *g_ISurface = nullptr;
vgui::IPanel *g_IPanel = nullptr;
IClientEntityList *g_IEntityList = nullptr;
ICvar *g_ICvar = nullptr;
IGameEventManager2 *g_IEventManager2 = nullptr;
IBaseClientDLL *g_IBaseClient = nullptr;
IEngineTrace *g_ITrace = nullptr;
IVModelInfoClient *g_IModelInfo = nullptr;
IInputSystem *g_IInputSystem = nullptr;
CGlobalVarsBase **rg_GlobalVars = nullptr;
IPrediction *g_IPrediction = nullptr;
IGameMovement *g_IGameMovement = nullptr;
IInput *g_IInput = nullptr;
ISteamUser *g_ISteamUser = nullptr;
IAchievementMgr *g_IAchievementMgr = nullptr;
ISteamUserStats *g_ISteamUserStats = nullptr;
IStudioRender *g_IStudioRender = nullptr;
IVDebugOverlay *g_IVDebugOverlay = nullptr;
IMaterialSystemFixed *g_IMaterialSystem = nullptr;
IVRenderView *g_IVRenderView = nullptr;
IMaterialSystem *g_IMaterialSystemHL = nullptr;
IMoveHelperServer *g_IMoveHelperServer = nullptr;
CBaseClientState *g_IBaseClientState = nullptr;
IGameEventManager *g_IGameEventManager = nullptr;
TFGCClientSystem *g_TFGCClientSystem = nullptr;
CHud *g_CHUD = nullptr;
CGameRules *g_pGameRules = nullptr;
IEngineVGui *g_IEngineVGui = nullptr;
IUniformRandomStream *g_pUniformStream = nullptr;
int *g_PredictionRandomSeed = nullptr;
IFileSystem *g_IFileSystem = nullptr;
IMDLCache *g_IMDLCache = nullptr;
IVModelRender *g_IVModelRender = nullptr;
ISteamClient *g_ISteamClient = nullptr;
ISteamFriends *g_ISteamFriends = nullptr;
IVEngineClient013 *g_IEngine = nullptr;
void *demoplayer = nullptr;
IEngineSound *g_ISoundEngine = nullptr;
vgui::ISurface *g_ISurface = nullptr;
vgui::IPanel *g_IPanel = nullptr;
IClientEntityList *g_IEntityList = nullptr;
ICvar *g_ICvar = nullptr;
IGameEventManager2 *g_IEventManager2 = nullptr;
IBaseClientDLL *g_IBaseClient = nullptr;
IEngineTrace *g_ITrace = nullptr;
IVModelInfoClient *g_IModelInfo = nullptr;
IInputSystem *g_IInputSystem = nullptr;
CGlobalVarsBase **rg_GlobalVars = nullptr;
IPrediction *g_IPrediction = nullptr;
IGameMovement *g_IGameMovement = nullptr;
IInput *g_IInput = nullptr;
ISteamUser *g_ISteamUser = nullptr;
IAchievementMgr *g_IAchievementMgr = nullptr;
ISteamUserStats *g_ISteamUserStats = nullptr;
IStudioRender *g_IStudioRender = nullptr;
IVDebugOverlay *g_IVDebugOverlay = nullptr;
IMaterialSystemFixed *g_IMaterialSystem = nullptr;
IVRenderView *g_IVRenderView = nullptr;
IMaterialSystem *g_IMaterialSystemHL = nullptr;
IMoveHelperServer *g_IMoveHelperServer = nullptr;
CBaseClientState *g_IBaseClientState = nullptr;
IGameEventManager *g_IGameEventManager = nullptr;
TFGCClientSystem *g_TFGCClientSystem = nullptr;
CHud *g_CHUD = nullptr;
CGameRules *g_pGameRules = nullptr;
IEngineVGui *g_IEngineVGui = nullptr;
IUniformRandomStream *g_pUniformStream = nullptr;
int *g_PredictionRandomSeed = nullptr;
IFileSystem *g_IFileSystem = nullptr;
IMDLCache *g_IMDLCache = nullptr;
IToolFrameworkInternal *g_IToolFramework = nullptr;
template <typename T> T *BruteforceInterface(std::string name, sharedobj::SharedObject &object, int start = 0)
{
@ -163,6 +164,7 @@ void CreateInterfaces()
g_IPanel = BruteforceInterface<vgui::IPanel>("VGUI_Panel", sharedobj::vgui2());
g_pUniformStream = **(IUniformRandomStream ***) (gSignatures.GetVstdSignature("A3 ? ? ? ? C3 89 F6") + 0x1);
g_IToolFramework = BruteforceInterface<IToolFrameworkInternal>("VTOOLFRAMEWORKVERSION", sharedobj::engine());
#if ENABLE_VISUALS
g_IVDebugOverlay = BruteforceInterface<IVDebugOverlay>("VDebugOverlay", sharedobj::engine());
g_ISurface = BruteforceInterface<vgui::ISurface>("VGUI_Surface", sharedobj::vguimatsurface());

View File

@ -33,6 +33,7 @@ void NetVars::Init()
IF_GAME(IsTF2())
{
this->m_flMaxspeed = gNetvars.get_offset("DT_BasePlayer", "m_flMaxspeed");
res_iTeam = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_iTeam");
res_bAlive = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_bAlive");
this->res_iMaxBuffedHealth = gNetvars.get_offset("DT_TFPlayerResource", "m_iMaxBuffedHealth");

View File

@ -257,6 +257,10 @@ void hack::Hook()
hooks::prediction.HookMethod(HOOK_ARGS(RunCommand));
hooks::prediction.Apply();
hooks::toolbox.Set(g_IToolFramework);
hooks::toolbox.HookMethod(HOOK_ARGS(Think));
hooks::toolbox.Apply();
#if ENABLE_VISUALS
sdl_hooks::applySdlHooks();
#endif

View File

@ -1594,6 +1594,7 @@ static InitRoutine EC([]() {
EC::Register(EC::LevelInit, Reset, "INIT_Aimbot", EC::average);
EC::Register(EC::LevelShutdown, Reset, "RESET_Aimbot", EC::average);
EC::Register(EC::CreateMove, CreateMove, "CM_Aimbot", EC::late);
EC::Register(EC::CreateMoveWarp, CreateMove, "CMW_Aimbot", EC::late);
#if ENABLE_VISUALS
EC::Register(EC::Draw, DrawText, "DRAW_Aimbot", EC::average);
#endif

View File

@ -14,7 +14,7 @@ static settings::Boolean debug{ "anti-anti-aim.debug.enable", "false" };
std::unordered_map<unsigned, brutedata> resolver_map;
std::array<CachedEntity *, 32> sniperdot_array;
static inline void modifyAnlges()
static inline void modifyAngles()
{
for (int i = 1; i <= g_IEngine->GetMaxClients(); i++)
{
@ -55,7 +55,7 @@ void frameStageNotify(ClientFrameStage_t stage)
return;
if (stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START)
{
modifyAnlges();
modifyAngles();
}
#endif
}
@ -259,8 +259,10 @@ static InitRoutine init([]() {
hook();
EC::Register(EC::Shutdown, shutdown, "antiantiaim_shutdown");
EC::Register(EC::CreateMove, CreateMove, "cm_antiantiaim");
EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_antiantiaim");
#if ENABLE_TEXTMODE
EC::Register(EC::CreateMove, modifyAnlges, "cm_textmodeantiantiaim");
EC::Register(EC::CreateMove, modifyAngles, "cm_textmodeantiantiaim");
EC::Register(EC::CreateMoveWarp, modifyAngles, "cmw_textmodeantiantiaim");
#endif
});
} // namespace hacks::shared::anti_anti_aim

View File

@ -133,5 +133,8 @@ void CreateMove()
noaa = false;
}
static InitRoutine EC([]() { EC::Register(EC::CreateMove, CreateMove, "antibackstab", EC::late); });
static InitRoutine EC([]() {
EC::Register(EC::CreateMove, CreateMove, "antibackstab", EC::late);
EC::Register(EC::CreateMoveWarp, CreateMove, "antibackstab_w", EC::late);
});
} // namespace hacks::tf2::antibackstab

View File

@ -35,5 +35,8 @@ void cm()
}
}
}
static InitRoutine EC([]() { EC::Register(EC::CreateMove, cm, "antidisguise", EC::average); });
static InitRoutine EC([]() {
EC::Register(EC::CreateMove, cm, "antidisguise", EC::average);
EC::Register(EC::CreateMoveWarp, cm, "antidisguise_w", EC::average);
});
} // namespace hacks::tf2::antidisguise

View File

@ -356,5 +356,8 @@ void CreateMove()
}
}
static InitRoutine EC([]() { EC::Register(EC::CreateMove, CreateMove, "autobackstab", EC::average); });
static InitRoutine EC([]() {
EC::Register(EC::CreateMove, CreateMove, "autobackstab", EC::average);
EC::Register(EC::CreateMoveWarp, CreateMove, "autobackstab_w", EC::average);
});
} // namespace hacks::tf2::autobackstab

View File

@ -238,6 +238,7 @@ void Draw()
static InitRoutine EC([]() {
EC::Register(EC::CreateMove, CreateMove, "cm_auto_reflect", EC::average);
EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_auto_reflect", EC::average);
#if ENABLE_VISUALS
EC::Register(EC::Draw, Draw, "draw_auto_reflect", EC::average);
#endif

View File

@ -549,7 +549,9 @@ std::optional<std::pair<CachedEntity *, BacktrackData>> getClosestTick(Vector ve
static InitRoutine init([]() {
EC::Register(EC::CreateMove, CreateMove, "backtrack_cm", EC::early);
EC::Register(EC::CreateMoveWarp, CreateMove, "backtrack_cmw", EC::early);
EC::Register(EC::CreateMove, CreateMoveLate, "backtrack_cmlate", EC::very_late);
EC::Register(EC::CreateMoveWarp, CreateMoveLate, "backtrack_cmwlate", EC::very_late);
#if ENABLE_VISUALS
EC::Register(EC::Draw, Draw, "backtrack_draw");
#endif

View File

@ -56,5 +56,5 @@ static void CreateMove()
if (!jump)
ticks_last_jump = 0;
}
static InitRoutine EC([]() { EC::Register(EC::CreateMove_NoEnginePred, CreateMove, "Bunnyhop", EC::average); });
static InitRoutine EC([]() { EC::Register(EC::CreateMove_NoEnginePred, CreateMove, "Bunnyhop", EC::early); });
} // namespace hacks::shared::bunnyhop

View File

@ -774,7 +774,7 @@ void rvarCallback(settings::VariableBase<int> &var, int after)
}
static InitRoutine runinit([]() {
EC::Register(EC::CreateMove, cm, "cm_followbot", EC::average);
EC::Register(EC::CreateMove_NoEnginePred, cm, "cm_followbot", EC::average);
#if ENABLE_VISUALS
EC::Register(EC::Draw, draw, "draw_followbot", EC::average);
#endif

View File

@ -960,6 +960,7 @@ static InitRoutine init([]() {
teammatesPushaway = g_ICvar->FindVar("tf_avoidteammates_pushaway");
EC::Register(EC::Shutdown, Shutdown, "draw_local_player", EC::average);
EC::Register(EC::CreateMove, CreateMove, "cm_misc_hacks", EC::average);
EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_misc_hacks", EC::average);
#if ENABLE_VISUALS
EC::Register(EC::Draw, Draw, "draw_misc_hacks", EC::average);
#if !ENFORCE_STREAM_SAFETY

View File

@ -589,6 +589,7 @@ float CAM_CapYaw_Hook(IInput *this_, float fVal)
#define foffset(p, i) ((unsigned char *) &p)[i]
static InitRoutine init([]() {
EC::Register(EC::CreateMove, CreateMove, "cm_miscaimbot", EC::average);
EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_miscaimbot", EC::average);
static auto signature = gSignatures.GetClientSignature("55 89 E5 53 83 EC 14 E8 ? ? ? ? 85 C0 74 ? 8D 98 ? ? ? ? C7 44 24 ? 11 00 00 00");

View File

@ -1395,6 +1395,7 @@ ObjectDestroyListener &listener()
static InitRoutine runinit([]() {
g_IEventManager2->AddListener(&listener(), "object_destroyed", false);
EC::Register(EC::CreateMove, CreateMove, "navbot", EC::early);
EC::Register(EC::CreateMoveWarp, CreateMove, "navbot_w", EC::early);
EC::Register(
EC::Shutdown, []() { g_IEventManager2->RemoveListener(&listener()); }, "navbot_shutdown");
});

View File

@ -627,5 +627,8 @@ void Draw()
{
}
static InitRoutine EC([]() { EC::Register(EC::CreateMove, CreateMove, "triggerbot", EC::average); });
static InitRoutine EC([]() {
EC::Register(EC::CreateMove, CreateMove, "triggerbot", EC::average);
EC::Register(EC::CreateMoveWarp, CreateMove, "triggerbot_w", EC::average);
});
} // namespace hacks::shared::triggerbot

View File

@ -1219,7 +1219,7 @@ static void cm()
}
static InitRoutine init([]() {
EC::Register(EC::CreateMove, cm, "cm_walkbot", EC::average);
EC::Register(EC::CreateMove_NoEnginePred, cm, "cm_walkbot", EC::average);
EC::Register(EC::LevelInit, OnLevelInit, "init_walkbot", EC::average);
#if ENABLE_VISUALS
EC::Register(EC::Draw, Draw, "draw_walkbot", EC::average);

View File

@ -14,17 +14,22 @@
#include "DetourHook.hpp"
#include "WeaponData.hpp"
#include "MiscTemporary.hpp"
#include "Think.hpp"
namespace hacks::tf2::warp
{
static settings::Boolean enabled{ "warp.enabled", "false" };
static settings::Boolean no_movement{ "warp.rapidfire.no-movement", "true" };
static settings::Boolean rapidfire{ "warp.rapidfire", "false" };
static settings::Int distance{ "warp.rapidfire.distance", "0" };
static settings::Boolean rapidfire_zoom{ "warp.rapidfire.zoom", "true" };
static settings::Boolean wait_full{ "warp.rapidfire.wait-full", "true" };
static settings::Button rapidfire_key{ "warp.rapidfire.key", "<null>" };
static settings::Int rapidfire_key_mode{ "warp.rapidfire.key-mode", "1" };
static settings::Int rf_disable_on{ "warp.rapidfire.disable-on", "0" };
static settings::Float speed{ "warp.speed", "23" };
static settings::Boolean draw{ "warp.draw", "false" };
static settings::Boolean draw_bar{ "warp.draw-bar", "false" };
static settings::Button warp_key{ "warp.key", "<null>" };
static settings::Button charge_key{ "warp.charge-key", "<null>" };
static settings::Boolean charge_passively{ "warp.charge-passively", "true" };
@ -42,13 +47,16 @@ static settings::Boolean warp_right{ "warp.on-hit.right", "true" };
// Hidden control rvars for communtiy servers
static settings::Int maxusrcmdprocessticks("warp.maxusrcmdprocessticks", "24");
bool in_warp = false;
bool in_rapidfire = false;
bool in_warp = false;
bool in_rapidfire = false;
bool in_rapidfire_zoom = false;
// Should we choke the packet or not? (in rapidfire)
bool choke_packet = false;
// Were we warping last tick?
// why is this needed at all, why do i have to write this janky bs
bool was_in_warp = false;
// Is this the first warp tick?
bool first_warp_tick = false;
// How many ticks we have to add to our CreateMove packet
int ticks_to_add = 0;
@ -60,6 +68,34 @@ void warpLogic();
static settings::Int size{ "warp.bar-size", "100" };
static settings::Int bar_x{ "warp.bar-x", "50" };
static settings::Int bar_y{ "warp.bar-y", "200" };
static settings::Int draw_string_x{ "warp.draw-info.x", "8" };
static settings::Int draw_string_y{ "warp.draw-info.y", "800" };
// Need our own Text drawing
static std::array<std::string, 32> warp_strings;
static size_t warp_strings_count{ 0 };
static std::array<rgba_t, 32> warp_strings_colors{ colors::empty };
void AddWarpString(const std::string &string, const rgba_t &color)
{
warp_strings[warp_strings_count] = string;
warp_strings_colors[warp_strings_count] = color;
++warp_strings_count;
}
void DrawWarpStrings()
{
float x = *draw_string_x;
float y = *draw_string_y;
for (size_t i = 0; i < warp_strings_count; ++i)
{
float sx, sy;
fonts::menu->stringSize(warp_strings[i], &sx, &sy);
draw::String(x, y, warp_strings_colors[i], warp_strings[i].c_str(), *fonts::center_screen);
y += fonts::center_screen->size + 1;
}
warp_strings_count = 0;
}
static bool should_charge = false;
static int warp_amount = 0;
@ -109,6 +145,39 @@ bool UpdateRFKey()
return allow_key;
}
float getFireDelay()
{
auto weapon_data = GetWeaponData(RAW_ENT(LOCAL_W));
return re::C_TFWeaponBase::ApplyFireDelay(RAW_ENT(LOCAL_W), weapon_data->m_flTimeFireDelay);
}
bool canInstaZoom()
{
return in_rapidfire_zoom || (g_pLocalPlayer->holding_sniper_rifle && current_user_cmd->buttons & IN_ATTACK2 && !HasCondition<TFCond_Zoomed>(LOCAL_E) && CE_FLOAT(LOCAL_W, netvar.flNextSecondaryAttack) <= g_GlobalVars->curtime);
}
// This is needed in order to make zoom/unzoom smooth even with insta zoom
static int ignore_ticks = 0;
void handleSniper()
{
// Prevent unzooming
if (in_rapidfire)
{
// Holding ready sniper rifle
if (canInstaZoom())
{
current_user_cmd->buttons &= ~IN_ATTACK2;
ignore_ticks = TIME_TO_TICKS(0.2f);
}
}
else if (ignore_ticks)
{
ignore_ticks--;
current_user_cmd->buttons &= ~IN_ATTACK2;
}
}
bool shouldRapidfire()
{
if (!rapidfire)
@ -138,9 +207,16 @@ bool shouldRapidfire()
if (LOCAL_W->m_iClassID() == CL_CLASS(CTFMinigun) && CE_INT(LOCAL_W, netvar.iWeaponState) != 3 && CE_INT(LOCAL_W, netvar.iWeaponState) != 2)
return false;
// Check if enemies are close enough
if (distance)
{
auto closest = getClosestNonlocalEntity(LOCAL_E->m_vecOrigin());
if (!closest || closest->m_flDistance() > *distance)
return false;
}
// We do not have the amount of ticks needed, don't try it
auto weapon_data = GetWeaponData(RAW_ENT(LOCAL_W));
if (warp_amount < TIME_TO_TICKS(weapon_data->m_flTimeFireDelay) && (TIME_TO_TICKS(weapon_data->m_flTimeFireDelay) < *maxusrcmdprocessticks - 1 || (wait_full && warp_amount != GetMaxWarpTicks())))
if (warp_amount < TIME_TO_TICKS(getFireDelay()) && (TIME_TO_TICKS(getFireDelay()) < *maxusrcmdprocessticks - 1 || (wait_full && warp_amount != GetMaxWarpTicks())))
return false;
// Mouse 1 is held, do it.
@ -150,6 +226,33 @@ bool shouldRapidfire()
if (LOCAL_W->m_iClassID() == CL_CLASS(CTFFlameThrower))
buttons_pressed = current_user_cmd && current_user_cmd->buttons & IN_ATTACK2;
if (g_pLocalPlayer->holding_sniper_rifle)
{
// Run if m2 is pressed and sniper rifle is ready
buttons_pressed = rapidfire_zoom && current_user_cmd && current_user_cmd->buttons & IN_ATTACK2 && canInstaZoom();
// Heatmaker is the only exception here, it can also run on m1
if (!buttons_pressed && HasCondition<TFCond_FocusBuff>(LOCAL_E))
buttons_pressed = current_user_cmd && current_user_cmd->buttons & IN_ATTACK;
}
switch (*rf_disable_on)
{
case 0: // Always on
return buttons_pressed;
case 1: // Disable on projectile
if (g_pLocalPlayer->weapon_mode == weapon_projectile)
return false;
break;
case 2: // Disable on melee
if (g_pLocalPlayer->weapon_mode == weapon_melee)
return false;
break;
case 3: // Disable on projectile and melee
if (g_pLocalPlayer->weapon_mode == weapon_projectile || g_pLocalPlayer->weapon_mode == weapon_melee)
return false;
break;
}
return buttons_pressed;
}
@ -175,9 +278,17 @@ int GetWarpAmount(bool finalTick)
{
int max_extra_ticks = *maxusrcmdprocessticks - 1;
// Rapidfire ignores speed
// Rapidfire ignores speed, and we send 15 + 7, aka maximum new + backup commands
if (in_rapidfire)
return max_extra_ticks;
{
// Warp right before the next shot
float shot_time = getFireDelay();
// This is to prevent Minigun/Pistol from only shooting once
if (TICKS_TO_TIME(22) / shot_time >= 2)
shot_time = TICKS_TO_TIME(23);
return std::min(22, TIME_TO_TICKS(shot_time) - 2);
// return 22;
}
// No limit set
if (!*maxusrcmdprocessticks)
max_extra_ticks = INT_MAX;
@ -214,6 +325,8 @@ void Warp(float accumulated_extra_samples, bool finalTick)
return;
}
PROF_SECTION(warp_profiler);
int warp_ticks = warp_amount;
if (warp_amount_override)
warp_ticks = warp_amount_override;
@ -230,6 +343,10 @@ void Warp(float accumulated_extra_samples, bool finalTick)
int packets_sent = 1;
for (int i = 0; i < calls; i++)
{
if (!i)
first_warp_tick = true;
else
first_warp_tick = false;
// Choke unless we sent too many already
choke_packet = true;
@ -239,6 +356,8 @@ void Warp(float accumulated_extra_samples, bool finalTick)
choke_packet = false;
packets_sent = -1;
}
else
hooked_methods::UpdatePred();
original(accumulated_extra_samples, finalTick);
// Only decrease ticks for the final CL_Move tick
@ -346,11 +465,6 @@ static bool was_overridden = false;
static int ticks_in_revved = 0;
static bool replaced_last_tick = false;
// Original Player origin and velocity, needed to not break because our engine pred.
// We adjust it as the ticks go.
static Vector original_origin;
static Vector original_velocity;
// Reset all the revv data
void resetRevvstate()
{
@ -416,20 +530,17 @@ void CL_Move_hook(float accumulated_extra_samples, bool bFinalTick)
if (shouldRapidfire())
{
in_rapidfire = true;
// Store original info
original_origin = LOCAL_E->m_vecOrigin();
velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), original_velocity);
// Zero out non z movement, it will just get messy else
original_velocity.x = 0.0f;
original_velocity.y = 0.0f;
if (canInstaZoom())
in_rapidfire_zoom = true;
}
Warp(accumulated_extra_samples, bFinalTick);
if (warp_amount < GetMaxWarpTicks())
charged = false;
in_warp = false;
in_rapidfire = false;
was_in_warp = true;
in_warp = false;
in_rapidfire = false;
in_rapidfire_zoom = false;
was_in_warp = true;
}
}
@ -449,24 +560,28 @@ void CreateMoveEarly()
}
}
// Fix the player origin after engine prediction, as it tries to predict the local
// player linearly and just breaks doubletap when falling/moving
void CreateMoveFixPrediction()
{
if (hacks::tf2::warp::in_rapidfire && current_user_cmd)
{
// Run very simple gravity calculations to ensure we do not miss
if (no_movement)
{
static ConVar *sv_gravity = g_ICvar->FindVar("sv_gravity");
Vector gravity{ 0.0f, 0.0f, -sv_gravity->GetFloat() };
static float original_curtime = 0.0f;
auto mins = RAW_ENT(LOCAL_E)->GetCollideable()->OBBMins();
auto maxs = RAW_ENT(LOCAL_E)->GetCollideable()->OBBMaxs();
std::pair<Vector, Vector> minmax{ mins, maxs };
PredictStep(original_origin, original_velocity, gravity, &minmax);
// Restore from the engine prediction
const_cast<Vector &>(RAW_ENT(LOCAL_E)->GetAbsOrigin()) = original_origin;
// Run before prediction so we can do Faststop logic
void CreateMovePrePredict()
{
// Attempt to stop fast in place to make movement smoother
if (in_rapidfire && no_movement)
FastStop();
if (in_rapidfire_zoom)
{
float adjusted_curtime = g_GlobalVars->curtime;
// Original curtime we need to use while in here
if (first_warp_tick)
original_curtime = g_GlobalVars->curtime;
// Update the data
g_pLocalPlayer->bZoomed = true;
g_pLocalPlayer->flZoomBegin = adjusted_curtime;
// Do not exceed headshot time, we can only hs next tick
if (adjusted_curtime - original_curtime > 0.2f)
{
g_pLocalPlayer->flZoomBegin = original_curtime - 0.2f - TICKS_TO_TIME(1);
}
}
}
@ -490,10 +605,6 @@ void CreateMove()
was_in_warp = false;
}
// Attempt to stop fast in place to make movement smoother
if (in_rapidfire && no_movement)
FastStop();
}
// Does all the logic related to charging and mode/settings specific actions like peek warp
@ -507,6 +618,8 @@ void warpLogic()
// Handle minigun in rapidfire
handleMinigun();
// Handle sniper in rapidfire
handleSniper();
// Charge logic
if (!shouldWarp(false))
@ -859,25 +972,44 @@ void SendNetMessage(INetMessage &msg)
#if ENABLE_VISUALS
void Draw()
{
if (!enabled || !draw)
if (!enabled)
return;
if (!draw && !draw_bar)
return;
if (!g_IEngine->IsInGame())
return;
if (CE_BAD(LOCAL_E))
return;
if (!LOCAL_E->m_bAlivePlayer())
return;
float charge_percent = (float) warp_amount / (float) GetMaxWarpTicks();
// Draw background
static rgba_t background_color = colors::FromRGBA8(96, 96, 96, 150);
float bar_bg_x_size = *size * 2.0f;
float bar_bg_y_size = *size / 5.0f;
draw::Rectangle(*bar_x - 5.0f, *bar_y - 5.0f, bar_bg_x_size + 10.0f, bar_bg_y_size + 10.0f, background_color);
// Draw bar
rgba_t color_bar = colors::orange;
if (GetMaxWarpTicks() == warp_amount)
color_bar = colors::green;
color_bar.a = 100 / 255.0f;
draw::Rectangle(*bar_x, *bar_y, *size * 2.0f * charge_percent, *size / 5.0f, color_bar);
if (draw)
{
rgba_t color = colors::orange;
if (warp_amount == 0)
color = colors::FromRGBA8(128.0f, 128.0f, 128.0f, 255.0f);
else if (GetMaxWarpTicks() == warp_amount)
color = colors::green;
AddWarpString("Shiftable ticks: " + std::to_string(warp_amount), color);
}
if (draw_bar)
{
float charge_percent = (float) warp_amount / (float) GetMaxWarpTicks();
// Draw background
static rgba_t background_color = colors::FromRGBA8(96, 96, 96, 150);
float bar_bg_x_size = *size * 2.0f;
float bar_bg_y_size = *size / 5.0f;
draw::Rectangle(*bar_x - 5.0f, *bar_y - 5.0f, bar_bg_x_size + 10.0f, bar_bg_y_size + 10.0f, background_color);
// Draw bar
rgba_t color_bar = colors::orange;
if (GetMaxWarpTicks() == warp_amount)
color_bar = colors::green;
color_bar.a = 100 / 255.0f;
draw::Rectangle(*bar_x, *bar_y, *size * 2.0f * charge_percent, *size / 5.0f, color_bar);
}
DrawWarpStrings();
}
#endif
@ -948,8 +1080,9 @@ static InitRoutine init([]() {
cl_move_detour.Init(cl_move_addr, (void *) CL_Move_hook);
EC::Register(EC::LevelShutdown, LevelShutdown, "warp_levelshutdown");
EC::Register(EC::CreateMove, CreateMoveFixPrediction, "warp_createmove_fixpred", EC::very_early);
EC::Register(EC::CreateMove, CreateMove, "warp_createmove", EC::very_late);
EC::Register(EC::CreateMoveWarp, CreateMove, "warp_createmovew", EC::very_late);
EC::Register(EC::CreateMove_NoEnginePred, CreateMovePrePredict, "warp_prepredict");
EC::Register(EC::CreateMoveEarly, CreateMoveEarly, "warp_createmove_early", EC::very_early);
g_IEventManager2->AddListener(&listener, "player_hurt", false);
EC::Register(

View File

@ -705,6 +705,22 @@ CachedEntity *getClosestEntity(Vector vec)
return best_ent;
}
CachedEntity *getClosestNonlocalEntity(Vector vec)
{
float distance = FLT_MAX;
CachedEntity *best_ent = nullptr;
for (int i = 1; i <= g_IEngine->GetMaxClients(); i++)
{
CachedEntity *ent = ENTITY(i);
if (CE_VALID(ent) && ent->m_IDX != g_pLocalPlayer->entity_idx && ent->m_vecDormantOrigin() && ent->m_bAlivePlayer() && ent->m_bEnemy() && vec.DistTo(ent->m_vecOrigin()) < distance)
{
distance = vec.DistTo(*ent->m_vecDormantOrigin());
best_ent = ent;
}
}
return best_ent;
}
void VectorTransform(const float *in1, const matrix3x4_t &in2, float *out)
{
out[0] = (in1[0] * in2[0][0] + in1[1] * in2[0][1] + in1[2] * in2[0][2]) + in2[0][3];
@ -1621,28 +1637,40 @@ void AimAtHitbox(CachedEntity *ent, int hitbox, CUserCmd *cmd, bool compensate_p
AimAt(g_pLocalPlayer->v_Eye, r, cmd, compensate_punch);
}
// Thanks to "copypaste" on UnknownCheats, this really helped
void FastStop()
{
// Get velocity
Vector vel;
velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), vel);
Vector direction;
VectorAngles(vel, direction);
float speed = vel.Length();
static auto sv_friction = g_ICvar->FindVar("sv_friction");
static auto sv_stopspeed = g_ICvar->FindVar("sv_stopspeed");
// Prevent overshooting
speed *= 0.5f;
auto speed = vel.Length2D();
auto friction = sv_friction->GetFloat() * CE_FLOAT(LOCAL_E, 0x12b8);
auto control = (speed < sv_stopspeed->GetFloat()) ? sv_stopspeed->GetFloat() : speed;
auto drop = control * friction * g_GlobalVars->interval_per_tick;
direction.y = current_user_cmd->viewangles.y - direction.y;
if (speed > drop - 1.0f)
{
Vector velocity = vel;
Vector direction;
VectorAngles(vel, direction);
float speed = velocity.Length();
Vector negated_direction;
AngleVectors2(VectorToQAngle(direction), &negated_direction);
negated_direction *= -speed;
direction.y = current_user_cmd->viewangles.y - direction.y;
current_user_cmd->forwardmove = negated_direction.x;
current_user_cmd->sidemove = negated_direction.y;
Vector forward;
AngleVectors2(VectorToQAngle(direction), &forward);
Vector negated_direction = forward * -speed;
current_user_cmd->forwardmove = negated_direction.x;
current_user_cmd->sidemove = negated_direction.y;
}
else
{
current_user_cmd->forwardmove = current_user_cmd->sidemove = 0.0f;
}
}
bool IsEntityVisiblePenetration(CachedEntity *entity, int hb)

View File

@ -118,4 +118,5 @@ VMTHook soundclient{};
VMTHook enginevgui{};
VMTHook vstd{};
VMTHook eventmanager2{};
VMTHook toolbox{};
} // namespace hooks

View File

@ -15,6 +15,7 @@ set(files "${CMAKE_CURRENT_LIST_DIR}/CanPacket.cpp"
"${CMAKE_CURRENT_LIST_DIR}/RunCommand.cpp"
"${CMAKE_CURRENT_LIST_DIR}/SendNetMsg.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Shutdown.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Think.cpp"
"${CMAKE_CURRENT_LIST_DIR}/FireEvent.cpp"
"${CMAKE_CURRENT_LIST_DIR}/FireEventClientSide.cpp"
"${CMAKE_CURRENT_LIST_DIR}/IsPlayingTimeDemo.cpp"

View File

@ -23,7 +23,7 @@
static settings::Boolean minigun_jump{ "misc.minigun-jump-tf2c", "false" };
static settings::Boolean roll_speedhack{ "misc.roll-speedhack", "false" };
static settings::Boolean forward_speedhack{ "misc.roll-speedhack.forward", "false" };
static settings::Boolean engine_pred{ "misc.engine-prediction", "true" };
settings::Boolean engine_pred{ "misc.engine-prediction", "true" };
static settings::Boolean debug_projectiles{ "debug.projectiles", "false" };
static settings::Int fullauto{ "misc.full-auto", "0" };
static settings::Boolean fuckmode{ "misc.fuckmode", "false" };
@ -31,6 +31,7 @@ static settings::Boolean fuckmode{ "misc.fuckmode", "false" };
class CMoveData;
namespace engine_prediction
{
static Vector original_origin;
void RunEnginePrediction(IClientEntity *ent, CUserCmd *ucmd)
{
@ -51,6 +52,8 @@ void RunEnginePrediction(IClientEntity *ent, CUserCmd *ucmd)
// Backup
float frameTime = g_GlobalVars->frametime;
float curTime = g_GlobalVars->curtime;
int tickcount = g_GlobalVars->tickcount;
original_origin = ent->GetAbsOrigin();
CUserCmd defaultCmd{};
if (ucmd == nullptr)
@ -79,11 +82,19 @@ void RunEnginePrediction(IClientEntity *ent, CUserCmd *ucmd)
g_GlobalVars->frametime = frameTime;
g_GlobalVars->curtime = curTime;
g_GlobalVars->tickcount = tickcount;
// Adjust tickbase
NET_INT(ent, netvar.nTickBase)++;
return;
}
// Restore Origin
void FinishEnginePrediction(IClientEntity *ent, CUserCmd *ucmd)
{
const_cast<Vector &>(ent->GetAbsOrigin()) = original_origin;
original_origin.Invalidate();
}
} // namespace engine_prediction
void PrecalculateCanShoot()
@ -222,6 +233,8 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs
}
// PROF_BEGIN();
// Do not update if in warp, since the entities will stay identical either way
if (!hacks::tf2::warp::in_warp)
{
PROF_SECTION(EntityCache);
entity_cache::Update();
@ -317,10 +330,17 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs
{
PROF_SECTION(CM_WRAPPER);
EC::run(EC::CreateMove_NoEnginePred);
if (engine_pred)
engine_prediction::RunEnginePrediction(RAW_ENT(LOCAL_E), current_user_cmd);
EC::run(EC::CreateMove);
if (engine_pred)
{
engine_prediction::RunEnginePrediction(RAW_ENT(LOCAL_E), current_user_cmd);
g_pLocalPlayer->UpdateEye();
}
if (hacks::tf2::warp::in_warp)
EC::run(EC::CreateMoveWarp);
else
EC::run(EC::CreateMove);
}
if (time_replaced)
g_GlobalVars->curtime = curtime_old;
@ -464,6 +484,12 @@ DEFINE_HOOKED_METHOD(CreateMoveInput, void, IInput *this_, int sequence_nr, floa
// Run EC
EC::run(EC::CreateMoveLate);
if (CE_GOOD(LOCAL_E))
{
// Restore prediction
if (engine_prediction::original_origin.IsValid())
engine_prediction::FinishEnginePrediction(RAW_ENT(LOCAL_E), current_late_user_cmd);
}
// Write the usercmd
WriteCmd(this_, current_late_user_cmd, sequence_nr);
}

28
src/hooks/Think.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "HookedMethods.hpp"
extern settings::Boolean engine_pred;
namespace hooked_methods
{
// Update Prediction, Used by warp/Doubletap aswell
void UpdatePred()
{
if (isHackActive() && g_IEngine->IsInGame() && CE_GOOD(LOCAL_E) && engine_pred)
{
int signon_state = *(int *) (*(unsigned *) &g_IBaseClientState + 304);
int m_nDeltaTick = *(int *) (*(unsigned *) &g_IBaseClientState + 408);
int lastoutgoingcommand = *(int *) (*(unsigned *) &g_IBaseClientState + offsets::lastoutgoingcommand());
int chokedcommands = *(int *) (*(unsigned *) &g_IBaseClientState + offsets::lastoutgoingcommand() + 4);
int last_command_ack = *(int *) (*(unsigned *) &g_IBaseClientState + offsets::lastoutgoingcommand() + 8);
// Only run if fully connected
if (signon_state == 6 && m_nDeltaTick > 0)
g_IPrediction->Update(m_nDeltaTick ? m_nDeltaTick + 1 : 0, m_nDeltaTick > 0, last_command_ack, lastoutgoingcommand + chokedcommands);
}
}
DEFINE_HOOKED_METHOD(Think, void, IToolFrameworkInternal *_this, bool finaltick)
{
UpdatePred();
return original::Think(_this, finaltick);
}
} // namespace hooked_methods

View File

@ -156,6 +156,11 @@ void LocalPlayer::Update()
}
}
void LocalPlayer::UpdateEye()
{
v_Eye = entity->m_vecOrigin() + CE_VECTOR(entity, netvar.vViewOffset);
}
void LocalPlayer::UpdateEnd()
{
if (!isFakeAngleCM)

View File

@ -807,7 +807,7 @@ static void drawcrumbs()
#endif
static InitRoutine runinit([]() {
EC::Register(EC::CreateMove, cm, "cm_navparser", EC::average);
EC::Register(EC::CreateMove_NoEnginePred, cm, "cm_navparser", EC::average);
#if ENABLE_VISUALS
EC::Register(EC::Draw, drawcrumbs, "draw_navparser", EC::average);
#endif

View File

@ -845,6 +845,41 @@ void FX_FireBullets_hook(IClientEntity *weapon, int player, Vector *origin, Vect
}*/
static Timer update_nospread_timer{};
void CreateMove2()
{
if (bullet)
{
static auto sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed");
if (!sv_usercmd_custom_random_seed)
sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed");
// Server owner decided it would be a great idea to give the user control over the random seed
else if (!sv_usercmd_custom_random_seed->GetBool())
{
auto seed = MD5_PseudoRandom(current_user_cmd->command_number) & 0x7FFFFFFF;
prediction_seed = *reinterpret_cast<float *>(&seed);
use_usercmd_seed = true;
}
// Normal server
else
use_usercmd_seed = false;
// Synced, mark as such to other modules
if (no_spread_synced == SYNCED)
is_syncing = false;
// Not synced currently, try to sync
if (no_spread_synced == NOT_SYNCED && !bad_mantissa)
{
is_syncing = true;
should_update_time = true;
update_nospread_timer.update();
}
// Else if mantissa bad, update every 10 mins
else if (no_spread_synced == NOT_SYNCED && update_nospread_timer.test_and_set(10 * 60 * 1000))
no_spread_synced = CORRECTING;
}
}
static InitRoutine init_bulletnospread([]() {
// Get our detour hooks running
static auto writeusercmd_addr = gSignatures.GetClientSignature("55 89 E5 57 56 53 83 EC 2C 8B 45 ? 8B 7D ? 8B 5D ? 89 45 ? 8B 40");
@ -855,42 +890,8 @@ static InitRoutine init_bulletnospread([]() {
net_sendpacket_detour.Init(net_sendpacket_addr, (void *) NET_SendPacket_hook);*/
// Register Event callbacks
EC::Register(
EC::CreateMove,
[]() {
if (bullet)
{
static auto sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed");
if (!sv_usercmd_custom_random_seed)
sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed");
// Server owner decided it would be a great idea to give the user control over the random seed
else if (!sv_usercmd_custom_random_seed->GetBool())
{
auto seed = MD5_PseudoRandom(current_user_cmd->command_number) & 0x7FFFFFFF;
prediction_seed = *reinterpret_cast<float *>(&seed);
use_usercmd_seed = true;
}
// Normal server
else
use_usercmd_seed = false;
// Synced, mark as such to other modules
if (no_spread_synced == SYNCED)
is_syncing = false;
// Not synced currently, try to sync
if (no_spread_synced == NOT_SYNCED && !bad_mantissa)
{
is_syncing = true;
should_update_time = true;
update_nospread_timer.update();
}
// Else if mantissa bad, update every 10 mins
else if (no_spread_synced == NOT_SYNCED && update_nospread_timer.test_and_set(10 * 60 * 1000))
no_spread_synced = CORRECTING;
}
},
"nospread_createmove2");
EC::Register(EC::CreateMove, CreateMove2, "nospread_createmove2");
EC::Register(EC::CreateMoveWarp, CreateMove2, "nospread_createmove2w");
#if ENABLE_VISUALS
EC::Register(
EC::Draw,