Merge pull request #1014 from nullworks/warp_improvements
Alot of warp related stuff (see description)
This commit is contained in:
commit
224ecfbaa3
@ -5,7 +5,7 @@
|
||||
<AutoVariable width="fill" target="antiaim.draw-fakes" label="Draw Fakes"/>
|
||||
<AutoVariable width="fill" target="antiaim.crouch" label="Fake Crouch"/>
|
||||
<AutoVariable width="fill" target="antiaim.no-clamp" label="No Clamping"/>
|
||||
<AutoVariable width="fill" target="misc.fakelag" label="Fakelag" min="0" max="15"/>
|
||||
<AutoVariable width="fill" target="misc.fakelag" label="Fakelag" min="0" max="22"/>
|
||||
<AutoVariable width="fill" target="antiaim.spin-speed" label="Spin speed" min="-45" max="45" step="0.1"/>
|
||||
<AutoVariable width="fill" target="antiaim.roll" label="Roll"/>
|
||||
<AutoVariable width="fill" target="antiaim.pitch.static" label="Custom Pitch"/>
|
||||
|
@ -59,6 +59,7 @@
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Warp" x="370" y="65">
|
||||
<List width="180">
|
||||
<AutoVariable width="fill" target="warp.enabled" label="Enable Warp" tooltip="Allows you to charge a burst of speed"/>
|
||||
<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.draw" label="Draw Warp" tooltip="Draws a bar indicating your warp readyness"/>
|
||||
<AutoVariable width="fill" target="warp.bar-size" label="Bar Size"/>
|
||||
|
@ -202,8 +202,7 @@ template <condition cond> inline bool CondBitCheck(condition_data_s &data)
|
||||
}
|
||||
if (cond < 32)
|
||||
{
|
||||
if (data.cond_0)
|
||||
return data.cond_0 & (1u << (cond));
|
||||
return data.cond_0 & (1u << (cond));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -231,20 +230,19 @@ template <condition cond, bool state> inline void CondBitSet(condition_data_s &d
|
||||
{
|
||||
if (cond > 32 * 3)
|
||||
{
|
||||
data.cond_3 |= (1 << (cond % 32));
|
||||
data.cond_3 |= (1u << (cond % 32));
|
||||
}
|
||||
else if (cond > 32 * 2)
|
||||
{
|
||||
data.cond_2 |= (1 << (cond % 32));
|
||||
data.cond_2 |= (1u << (cond % 32));
|
||||
}
|
||||
else if (cond > 32 * 1)
|
||||
{
|
||||
data.cond_1 |= (1 << (cond % 32));
|
||||
data.cond_1 |= (1u << (cond % 32));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.cond_0)
|
||||
data.cond_0 |= (1 << (cond));
|
||||
data.cond_0 |= (1u << (cond));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -263,8 +261,7 @@ template <condition cond, bool state> inline void CondBitSet(condition_data_s &d
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.cond_0)
|
||||
data.cond_0 &= ~(1u << (cond));
|
||||
data.cond_0 &= ~(1u << (cond));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,26 @@ public:
|
||||
{
|
||||
if (g_pLocalPlayer->holding_sapper)
|
||||
return 115;
|
||||
IClientEntity *owner = re::C_TFWeaponBase::GetOwnerViaInterface(self);
|
||||
bool add_charging = false;
|
||||
if (owner)
|
||||
{
|
||||
CachedEntity *owner_ce = ENTITY(owner->entindex());
|
||||
if (HasCondition<TFCond_Charging>(owner_ce))
|
||||
{
|
||||
CondBitSet<TFCond_Charging, false>(CE_VAR(owner_ce, netvar.iCond, condition_data_s));
|
||||
add_charging = true;
|
||||
}
|
||||
}
|
||||
typedef int (*fn_t)(IClientEntity *);
|
||||
return vfunc<fn_t>(self, offsets::PlatformOffset(521, offsets::undefined, 521), 0)(self);
|
||||
int return_value = vfunc<fn_t>(self, offsets::PlatformOffset(521, offsets::undefined, 521), 0)(self);
|
||||
|
||||
if (add_charging)
|
||||
{
|
||||
CachedEntity *owner_ce = ENTITY(owner->entindex());
|
||||
CondBitSet<TFCond_Charging, true>(CE_VAR(owner_ce, netvar.iCond, condition_data_s));
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
};
|
||||
} // namespace re
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <inetmsghandler.h>
|
||||
#include <KeyValues.h>
|
||||
#include "bitvec.h"
|
||||
#include "CSignature.h"
|
||||
|
||||
#define DECLARE_BASE_MESSAGE(msgtype) \
|
||||
public: \
|
||||
@ -98,6 +99,26 @@ public:
|
||||
return false;
|
||||
}; // no handler set
|
||||
|
||||
public:
|
||||
// I don't get what it does but we need it
|
||||
virtual bool BIncomingMessageForProcessing(double param_1, int param_2)
|
||||
{
|
||||
// Call original to be sure nothing breaks
|
||||
typedef bool (*BIncomingMessageForProcessing_t)(CNetMessage *, double, int);
|
||||
static auto addr = gSignatures.GetEngineSignature("55 89 E5 56 53 83 EC 10 8B 5D ? F2 0F 10 45");
|
||||
BIncomingMessageForProcessing_t BIncomingMessageForProcessing_fn = (BIncomingMessageForProcessing_t)addr;
|
||||
return BIncomingMessageForProcessing_fn(this, param_1, param_2);
|
||||
};
|
||||
// I don't get what it does but we need it
|
||||
virtual void SetRatePolicy()
|
||||
{
|
||||
// Call original to be sure nothing breaks
|
||||
typedef bool (*SetRatePolicy_t)(CNetMessage *);
|
||||
static auto addr = gSignatures.GetEngineSignature("55 89 E5 83 EC 18 C7 04 24 2C 00 00 00");
|
||||
SetRatePolicy_t SetRatePolicy_fn = (SetRatePolicy_t)addr;
|
||||
SetRatePolicy_fn(this);
|
||||
};
|
||||
|
||||
protected:
|
||||
bool m_bReliable; // true if message should be send reliable
|
||||
INetChannel *m_NetChannel; // netchannel this message is from/for
|
||||
@ -177,7 +198,7 @@ protected:
|
||||
|
||||
#define MAX_OSPATH 260
|
||||
|
||||
#define NETMSG_TYPE_BITS 5
|
||||
#define NETMSG_TYPE_BITS 6
|
||||
typedef int QueryCvarCookie_t;
|
||||
typedef enum
|
||||
{
|
||||
|
@ -72,7 +72,7 @@ static void updateAntiAfk()
|
||||
if (!afk_timer)
|
||||
afk_timer = g_ICvar->FindVar("mp_idlemaxtime");
|
||||
// Trigger 10 seconds before kick
|
||||
else if (afk_timer->m_nValue != 0 && anti_afk_timer.check(afk_timer->m_nValue * 60 * 1000 - 10000))
|
||||
else if (afk_timer->GetInt() != 0 && anti_afk_timer.check(afk_timer->m_nValue * 60 * 1000 - 10000))
|
||||
{
|
||||
// Just duck tf
|
||||
if (current_user_cmd->buttons & (IN_DUCK | IN_JUMP))
|
||||
@ -85,7 +85,7 @@ static void updateAntiAfk()
|
||||
current_late_user_cmd->buttons |= flip ? IN_FORWARD : IN_BACK;
|
||||
// Flip flip
|
||||
flip = !flip;
|
||||
if (anti_afk_timer.check(afk_timer->m_nValue * 60 * 1000 + 1000))
|
||||
if (anti_afk_timer.check(afk_timer->GetInt() * 60 * 1000 + 1000))
|
||||
{
|
||||
anti_afk_timer.update();
|
||||
}
|
||||
|
@ -11,10 +11,12 @@
|
||||
#endif
|
||||
#include "MiscAimbot.hpp"
|
||||
#include "PlayerTools.hpp"
|
||||
#include "DetourHook.hpp"
|
||||
|
||||
namespace hacks::tf2::warp
|
||||
{
|
||||
static settings::Boolean enabled{ "warp.enabled", "false" };
|
||||
static settings::Float speed{ "warp.speed", "23" };
|
||||
static settings::Boolean draw{ "warp.draw", "false" };
|
||||
static settings::Button warp_key{ "warp.key", "<null>" };
|
||||
static settings::Boolean charge_passively{ "warp.charge-passively", "true" };
|
||||
@ -29,68 +31,97 @@ static settings::Boolean warp_backwards{ "warp.on-hit.backwards", "false" };
|
||||
static settings::Boolean warp_left{ "warp.on-hit.left", "true" };
|
||||
static settings::Boolean warp_right{ "warp.on-hit.right", "true" };
|
||||
|
||||
// Hidden control rvars for communtiy servers
|
||||
static settings::Int maxusrcmdprocessticks("warp.maxusrcmdprocessticks", "24");
|
||||
|
||||
// Draw control
|
||||
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 bool should_charge = false;
|
||||
static int warp_amount = 0;
|
||||
static int warp_amount_override = 0;
|
||||
static int warp_override_one_tick = 0;
|
||||
static bool charged = false;
|
||||
|
||||
// Taken from MrSteyk
|
||||
class clc_move_proto
|
||||
{
|
||||
public:
|
||||
int VTable;
|
||||
char reliable;
|
||||
int netchan;
|
||||
int field_C;
|
||||
int field_10;
|
||||
int m_nBackupCommands;
|
||||
int m_nNewCommands;
|
||||
int m_nLength;
|
||||
bf_write m_DataIn;
|
||||
bf_write m_DataOut;
|
||||
};
|
||||
|
||||
int GetWarpAmount()
|
||||
{
|
||||
static auto sv_max_dropped_packets_to_process = g_ICvar->FindVar("sv_max_dropped_packets_to_process");
|
||||
return warp_override_one_tick ? warp_override_one_tick : sv_max_dropped_packets_to_process->GetInt();
|
||||
}
|
||||
static bool should_charge = false;
|
||||
static int warp_amount = 0;
|
||||
static int warp_amount_override = 0;
|
||||
static bool should_melee = false;
|
||||
static bool charged = false;
|
||||
|
||||
static bool should_warp = true;
|
||||
static bool was_hurt = false;
|
||||
|
||||
// Warping part
|
||||
void Warp()
|
||||
// Should we warp?
|
||||
bool shouldWarp(bool check_amount)
|
||||
{
|
||||
return ((warp_key && warp_key.isKeyDown()) || was_hurt) && (!check_amount || warp_amount);
|
||||
}
|
||||
|
||||
// How many ticks of excess we have (for decimal speeds)
|
||||
float excess_ticks = 0.0f;
|
||||
int GetWarpAmount(bool finalTick)
|
||||
{
|
||||
int max_extra_ticks = *maxusrcmdprocessticks - 1;
|
||||
// No limit set
|
||||
if (!*maxusrcmdprocessticks)
|
||||
max_extra_ticks = INT_MAX;
|
||||
float warp_amount_preprocessed = std::max(*speed, 0.05f);
|
||||
|
||||
// How many ticks to warp, add excess too
|
||||
int warp_amount_processed = std::floor(warp_amount_preprocessed) + std::floor(excess_ticks);
|
||||
|
||||
// Remove the used amount from excess
|
||||
if (finalTick)
|
||||
excess_ticks -= std::floor(excess_ticks);
|
||||
|
||||
// Store excess
|
||||
if (finalTick)
|
||||
excess_ticks += warp_amount_preprocessed - std::floor(warp_amount_preprocessed);
|
||||
|
||||
// Return smallest of the two
|
||||
return std::min(warp_amount_processed, max_extra_ticks);
|
||||
}
|
||||
|
||||
DetourHook cl_move_detour;
|
||||
typedef void (*CL_Move_t)(float accumulated_extra_samples, bool bFinalTick);
|
||||
|
||||
// Warping part, uses CL_Move
|
||||
void Warp(float accumulated_extra_samples, bool finalTick)
|
||||
{
|
||||
auto ch = g_IEngine->GetNetChannelInfo();
|
||||
if (!ch)
|
||||
return;
|
||||
if (!should_warp)
|
||||
{
|
||||
should_warp = true;
|
||||
if (finalTick)
|
||||
should_warp = true;
|
||||
return;
|
||||
}
|
||||
int &m_nOutSequenceNr = *(int *) ((uintptr_t) ch + offsets::m_nOutSequenceNr());
|
||||
|
||||
int warp_ticks = warp_amount;
|
||||
if (warp_amount_override)
|
||||
warp_ticks = warp_amount_override;
|
||||
|
||||
// Don' add more than the warp_ticks
|
||||
m_nOutSequenceNr += std::min(warp_ticks, GetWarpAmount());
|
||||
warp_amount -= std::min(warp_ticks, GetWarpAmount());
|
||||
warp_ticks -= std::min(warp_ticks, GetWarpAmount());
|
||||
CL_Move_t original = (CL_Move_t) cl_move_detour.GetOriginalFunc();
|
||||
|
||||
// Call CL_Move once for every warp tick
|
||||
int warp_amnt = GetWarpAmount(finalTick);
|
||||
if (warp_amnt)
|
||||
{
|
||||
int calls = std::min(warp_ticks, warp_amnt);
|
||||
for (int i = 0; i < calls; i++)
|
||||
{
|
||||
original(accumulated_extra_samples, finalTick);
|
||||
// Only decrease ticks for the final CL_Move tick
|
||||
if (finalTick)
|
||||
{
|
||||
warp_amount--;
|
||||
warp_ticks--;
|
||||
}
|
||||
}
|
||||
}
|
||||
cl_move_detour.RestorePatch();
|
||||
|
||||
if (warp_amount_override)
|
||||
warp_amount_override = warp_ticks;
|
||||
|
||||
// Don't attack while warping
|
||||
current_user_cmd->buttons &= ~IN_ATTACK;
|
||||
if (warp_ticks <= 0)
|
||||
{
|
||||
was_hurt = false;
|
||||
@ -102,8 +133,7 @@ void Warp()
|
||||
|
||||
int GetMaxWarpTicks()
|
||||
{
|
||||
static auto usercmd_cvar = g_ICvar->FindVar("sv_maxusrcmdprocessticks");
|
||||
int ticks = usercmd_cvar->GetInt();
|
||||
int ticks = *maxusrcmdprocessticks;
|
||||
// No limit set
|
||||
if (!ticks)
|
||||
ticks = INT_MAX;
|
||||
@ -122,7 +152,8 @@ void SendNetMessage(INetMessage &msg)
|
||||
if (should_charge && !charged)
|
||||
{
|
||||
int ticks = GetMaxWarpTicks();
|
||||
auto movemsg = (clc_move_proto *) &msg;
|
||||
auto movemsg = (CLC_Move *) &msg;
|
||||
|
||||
// Just null it :shrug:
|
||||
movemsg->m_nBackupCommands = 0;
|
||||
movemsg->m_nNewCommands = 0;
|
||||
@ -138,22 +169,38 @@ void SendNetMessage(INetMessage &msg)
|
||||
charged = true;
|
||||
}
|
||||
}
|
||||
// Warp
|
||||
if ((warp_key.isKeyDown() || was_hurt) && warp_amount)
|
||||
{
|
||||
Warp();
|
||||
if (warp_amount < GetMaxWarpTicks())
|
||||
charged = false;
|
||||
}
|
||||
}
|
||||
should_charge = false;
|
||||
}
|
||||
|
||||
static bool move_last_tick = true;
|
||||
static bool warp_last_tick = false;
|
||||
static bool should_warp_last_tick = false;
|
||||
static bool was_hurt_last_tick = false;
|
||||
static int ground_ticks = 0;
|
||||
// Approximate demoknight shield speed at a given tick
|
||||
float approximateSpeedAtTick(int ticks_since_start, float initial_speed)
|
||||
{
|
||||
// Formula only holds up until like 20 ticks
|
||||
float speed = ticks_since_start >= 20 ? 750.0f : (ticks_since_start * (113.8f - 2.8f * ticks_since_start) + 1.0f);
|
||||
return std::min(750.0f * g_GlobalVars->interval_per_tick, initial_speed * g_GlobalVars->interval_per_tick + speed * g_GlobalVars->interval_per_tick);
|
||||
}
|
||||
|
||||
// Approximate the amount of ticks needed for a given distance as demoknight
|
||||
int approximateTicksForDist(float distance, float initial_speed, int max_ticks)
|
||||
{
|
||||
float travelled_dist = 0.0f;
|
||||
for (int i = 0; i <= max_ticks; i++)
|
||||
{
|
||||
travelled_dist += approximateSpeedAtTick(i, initial_speed);
|
||||
|
||||
// We hit the needed range
|
||||
if (travelled_dist >= distance)
|
||||
return i;
|
||||
}
|
||||
// Not within Max range
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool move_last_tick = true;
|
||||
static bool warp_last_tick = false;
|
||||
static bool was_hurt_last_tick = false;
|
||||
static int ground_ticks = 0;
|
||||
// Left and right by default
|
||||
static std::vector<float> yaw_selections{ 90.0f, -90.0f };
|
||||
|
||||
@ -165,7 +212,19 @@ enum charge_state
|
||||
DONE
|
||||
};
|
||||
|
||||
charge_state current_state = ATTACK;
|
||||
enum peek_state
|
||||
{
|
||||
IDLE = 0,
|
||||
MOVE_TOWARDS,
|
||||
MOVE_BACK,
|
||||
STOP
|
||||
};
|
||||
|
||||
charge_state current_state = ATTACK;
|
||||
peek_state current_peek_state = IDLE;
|
||||
|
||||
// Used to determine when we should start moving back with peek
|
||||
static int charge_at_start = 0;
|
||||
|
||||
// Used to determine when demoknight warp should be over
|
||||
static bool was_overridden = false;
|
||||
@ -175,11 +234,11 @@ void CreateMove()
|
||||
return;
|
||||
if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer())
|
||||
return;
|
||||
warp_override_one_tick = 0;
|
||||
if (!warp_key.isKeyDown() && !was_hurt)
|
||||
if (!shouldWarp(false))
|
||||
{
|
||||
warp_last_tick = false;
|
||||
current_state = ATTACK;
|
||||
warp_last_tick = false;
|
||||
current_state = ATTACK;
|
||||
current_peek_state = IDLE;
|
||||
|
||||
Vector velocity{};
|
||||
velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), velocity);
|
||||
@ -267,25 +326,47 @@ void CreateMove()
|
||||
if (result.first)
|
||||
{
|
||||
float distance = LOCAL_E->m_vecOrigin().DistTo(result.first->m_vecOrigin());
|
||||
// Subtract melee range
|
||||
distance -= 130.0f;
|
||||
|
||||
// Divide by the amount we travel per tick to get how much of our charge we'll need
|
||||
int charge_ticks = distance / (750.0f * g_GlobalVars->interval_per_tick);
|
||||
// We want to hit their bounding box, not their center
|
||||
distance -= 40.0f;
|
||||
|
||||
// For every started 10 ticks We can subtract 1 because we'll get an extra CreateMove call.
|
||||
charge_ticks -= std::ceil(charge_ticks / 10.0f);
|
||||
// This approximates the ticks needed for the distance
|
||||
Vector vel;
|
||||
velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), vel);
|
||||
// +11 to account for the melee delay
|
||||
int charge_ticks = approximateTicksForDist(distance, vel.Length(), GetMaxWarpTicks() + 11);
|
||||
|
||||
// Not in range, try again with melee range taken into compensation
|
||||
if (charge_ticks <= 0)
|
||||
charge_ticks = approximateTicksForDist(distance - 128.0f, vel.Length(), GetMaxWarpTicks() + 11);
|
||||
// Out of range
|
||||
if (charge_ticks <= 0)
|
||||
{
|
||||
charge_ticks = warp_amount;
|
||||
should_melee = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
charge_ticks = std::clamp(charge_ticks, 0, warp_amount);
|
||||
// For every started batch We can subtract 1 because we'll get an extra CreateMove call.
|
||||
charge_ticks -= std::ceil(charge_ticks / *speed);
|
||||
should_melee = true;
|
||||
}
|
||||
// Use these ticks
|
||||
warp_amount_override = std::clamp(charge_ticks, 0, warp_amount);
|
||||
was_overridden = true;
|
||||
warp_amount_override = charge_ticks;
|
||||
|
||||
was_overridden = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
should_melee = false;
|
||||
was_overridden = false;
|
||||
}
|
||||
|
||||
// Force a crit
|
||||
criticals::force_crit_this_tick = true;
|
||||
current_user_cmd->buttons |= IN_ATTACK;
|
||||
if (should_melee)
|
||||
current_user_cmd->buttons |= IN_ATTACK;
|
||||
current_state = CHARGE;
|
||||
}
|
||||
// Just warp normally if meter isn't full
|
||||
@ -329,34 +410,59 @@ void CreateMove()
|
||||
// Warp peaking
|
||||
else if (warp_peek)
|
||||
{
|
||||
// We have Warp
|
||||
if (warp_amount)
|
||||
switch (current_peek_state)
|
||||
{
|
||||
// Warped last tick, time to reverse
|
||||
if (warp_last_tick)
|
||||
{
|
||||
// Wait 1 tick before warping back
|
||||
if (should_warp && !should_warp_last_tick)
|
||||
{
|
||||
should_warp_last_tick = true;
|
||||
should_warp = false;
|
||||
}
|
||||
else
|
||||
should_warp_last_tick = false;
|
||||
case IDLE:
|
||||
{
|
||||
// Not doing anything, update warp amount
|
||||
charge_at_start = warp_amount;
|
||||
|
||||
// Inverse direction
|
||||
current_user_cmd->forwardmove = -current_user_cmd->forwardmove;
|
||||
current_user_cmd->sidemove = -current_user_cmd->sidemove;
|
||||
}
|
||||
Vector vel;
|
||||
velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), vel);
|
||||
|
||||
// if we move more than 1.0 HU/s and buttons are pressed, and we are grounded, go to move towards statement...
|
||||
if (CE_INT(LOCAL_E, netvar.iFlags) & FL_ONGROUND && !vel.IsZero(1.0f) && current_user_cmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT))
|
||||
current_peek_state = MOVE_TOWARDS;
|
||||
// ...else don't warp
|
||||
else
|
||||
warp_override_one_tick = warp_amount / 2;
|
||||
warp_last_tick = true;
|
||||
{
|
||||
should_warp = false;
|
||||
break;
|
||||
}
|
||||
|
||||
[[fallthrough]];
|
||||
}
|
||||
// Prevent movement so you don't overshoot when you don't want to
|
||||
else
|
||||
case MOVE_TOWARDS:
|
||||
{
|
||||
// Just wait until we used about a third of our warp, the rest has to be used for moving back
|
||||
if (warp_amount <= charge_at_start * (2.0f / 3.0f))
|
||||
current_peek_state = MOVE_BACK;
|
||||
break;
|
||||
}
|
||||
case MOVE_BACK:
|
||||
{
|
||||
// Inverse direction if we still have warp left
|
||||
if (warp_amount)
|
||||
{
|
||||
current_user_cmd->forwardmove *= -1.0f;
|
||||
current_user_cmd->sidemove *= -1.0f;
|
||||
break;
|
||||
}
|
||||
// ... Else we stop in our tracks
|
||||
else
|
||||
current_peek_state = STOP;
|
||||
|
||||
[[fallthrough]];
|
||||
}
|
||||
case STOP:
|
||||
{
|
||||
// Stop dead in our tracks while key is still held
|
||||
current_user_cmd->forwardmove = 0.0f;
|
||||
current_user_cmd->sidemove = 0.0f;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
was_hurt_last_tick = was_hurt;
|
||||
@ -438,12 +544,94 @@ void rvarCallback(settings::VariableBase<bool> &, bool)
|
||||
yaw_selections.push_back(90.0f);
|
||||
}
|
||||
|
||||
DetourHook cl_sendmove_detour;
|
||||
typedef void (*CL_SendMove_t)();
|
||||
void CL_SendMove_hook()
|
||||
{
|
||||
byte data[4000];
|
||||
|
||||
// the +4 one is choked commands
|
||||
int nextcommandnr = NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand()) + NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand() + 4) + 1;
|
||||
|
||||
// send the client update packet
|
||||
|
||||
CLC_Move moveMsg;
|
||||
|
||||
moveMsg.m_DataOut.StartWriting(data, sizeof(data));
|
||||
|
||||
// Determine number of backup commands to send along
|
||||
int cl_cmdbackup = 2;
|
||||
|
||||
// How many real new commands have queued up
|
||||
moveMsg.m_nNewCommands = 1 + NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand() + 4);
|
||||
moveMsg.m_nNewCommands = std::clamp(moveMsg.m_nNewCommands, 0, 15);
|
||||
|
||||
// Excessive commands (Used for longer fakelag, credits to https://www.unknowncheats.me/forum/source-engine/370916-23-tick-guwop-fakelag-break-lag-compensation-running.html)
|
||||
int extra_commands = NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand() + 4) + 1 - moveMsg.m_nNewCommands;
|
||||
cl_cmdbackup = std::max(2, extra_commands);
|
||||
moveMsg.m_nBackupCommands = std::clamp(cl_cmdbackup, 0, 7);
|
||||
|
||||
int numcmds = moveMsg.m_nNewCommands + moveMsg.m_nBackupCommands;
|
||||
|
||||
int from = -1; // first command is deltaed against zeros
|
||||
|
||||
bool bOK = true;
|
||||
|
||||
for (int to = nextcommandnr - numcmds + 1; to <= nextcommandnr; to++)
|
||||
{
|
||||
bool isnewcmd = to >= (nextcommandnr - moveMsg.m_nNewCommands + 1);
|
||||
|
||||
// Call the write to buffer
|
||||
typedef bool (*WriteUsercmdDeltaToBuffer_t)(IBaseClientDLL *, bf_write *, int, int, bool);
|
||||
|
||||
// first valid command number is 1
|
||||
bOK = bOK && vfunc<WriteUsercmdDeltaToBuffer_t>(g_IBaseClient, offsets::PlatformOffset(23, offsets::undefined, offsets::undefined), 0)(g_IBaseClient, &moveMsg.m_DataOut, from, to, isnewcmd);
|
||||
from = to;
|
||||
}
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
// Make fakelag work as we want it to
|
||||
if (extra_commands > 0)
|
||||
((INetChannel *) g_IEngine->GetNetChannelInfo())->m_nChokedPackets -= extra_commands;
|
||||
|
||||
// only write message if all usercmds were written correctly, otherwise parsing would fail
|
||||
((INetChannel *) g_IEngine->GetNetChannelInfo())->SendNetMsg(moveMsg);
|
||||
}
|
||||
}
|
||||
|
||||
void CL_Move_hook(float accumulated_extra_samples, bool bFinalTick)
|
||||
{
|
||||
CL_Move_t original = (CL_Move_t) cl_move_detour.GetOriginalFunc();
|
||||
original(accumulated_extra_samples, bFinalTick);
|
||||
cl_move_detour.RestorePatch();
|
||||
|
||||
// Should we warp?
|
||||
if (shouldWarp(true))
|
||||
{
|
||||
Warp(accumulated_extra_samples, bFinalTick);
|
||||
if (warp_amount < GetMaxWarpTicks())
|
||||
charged = false;
|
||||
}
|
||||
}
|
||||
|
||||
static InitRoutine init([]() {
|
||||
static auto cl_sendmove_addr = gSignatures.GetEngineSignature("55 89 E5 57 56 53 81 EC 2C 10 00 00 C6 85 ? ? ? ? 01");
|
||||
cl_sendmove_detour.Init(cl_sendmove_addr, (void *) CL_SendMove_hook);
|
||||
static auto cl_move_addr = gSignatures.GetEngineSignature("55 89 E5 57 56 53 81 EC 9C 00 00 00 83 3D ? ? ? ? 01");
|
||||
cl_move_detour.Init(cl_move_addr, (void *) CL_Move_hook);
|
||||
|
||||
EC::Register(EC::LevelShutdown, LevelShutdown, "warp_levelshutdown");
|
||||
EC::Register(EC::CreateMove, CreateMove, "warp_createmove", EC::very_late);
|
||||
g_IEventManager2->AddListener(&listener, "player_hurt", false);
|
||||
EC::Register(
|
||||
EC::Shutdown, []() { g_IEventManager2->RemoveListener(&listener); }, "warp_shutdown");
|
||||
EC::Shutdown,
|
||||
[]() {
|
||||
g_IEventManager2->RemoveListener(&listener);
|
||||
cl_sendmove_detour.Shutdown();
|
||||
cl_move_detour.Shutdown();
|
||||
},
|
||||
"warp_shutdown");
|
||||
warp_forward.installChangeCallback(rvarCallback);
|
||||
warp_backwards.installChangeCallback(rvarCallback);
|
||||
warp_left.installChangeCallback(rvarCallback);
|
||||
|
@ -498,7 +498,7 @@ const char *CLC_ListenEvents::ToString(void) const
|
||||
|
||||
const char *CLC_Move::ToString(void) const
|
||||
{
|
||||
return strfmt("%s: backup %i, new %i, bytes %i", GetName(), m_nNewCommands, m_nBackupCommands, Bits2Bytes(m_nLength)).release();
|
||||
return "";
|
||||
}
|
||||
|
||||
bool CLC_Move::WriteToBuffer(bf_write &buffer)
|
||||
|
Reference in New Issue
Block a user