1 second backtrack, reorganise aimbot (#38)
* 1 second backtrack, reorganise aimbot again, remove lots of flags from cvars * Fix linux codebug * Fix linux code bugs
This commit is contained in:
parent
c5c038157a
commit
8f6602ed3f
@ -17,6 +17,7 @@
|
||||
|
||||
#include "hooks/createmove.hh"
|
||||
#include "hooks/engine_vgui.hh"
|
||||
#include "hooks/send_datagram.hh"
|
||||
|
||||
#include "modules/esp.hh"
|
||||
#include "modules/misc.hh"
|
||||
@ -137,6 +138,8 @@ public:
|
||||
|
||||
misc::init_all();
|
||||
|
||||
logging::msg("DOGHOOK:tm: :joy: :joy: :jo3: :nice:\nBuild: " __DATE__ " " __TIME__);
|
||||
|
||||
// at this point we are now inited and ready to go!
|
||||
inited = true;
|
||||
}
|
||||
@ -155,6 +158,7 @@ public:
|
||||
|
||||
// Do level init here
|
||||
create_move::level_init();
|
||||
send_datagram::level_init();
|
||||
}
|
||||
void level_shutdown_pre_clear_steam_api_context() override { logging::msg("level_shutdown_pre_clear_steam_api_context"); }
|
||||
void level_shutdown_pre_entity() override {
|
||||
@ -162,6 +166,7 @@ public:
|
||||
|
||||
// Do level_shutdown here
|
||||
create_move::level_shutdown();
|
||||
send_datagram::level_shutdown();
|
||||
}
|
||||
void level_shutdown_post_entity() override { logging::msg("level_shutdown_post_entity"); }
|
||||
|
||||
|
47
src/hooks/send_datagram.cc
Normal file
47
src/hooks/send_datagram.cc
Normal file
@ -0,0 +1,47 @@
|
||||
#include <precompiled.hh>
|
||||
|
||||
#include <sdk/convar.hh>
|
||||
#include <sdk/hooks.hh>
|
||||
#include <sdk/sdk.hh>
|
||||
|
||||
#include <modules/backtrack.hh>
|
||||
|
||||
using namespace sdk;
|
||||
|
||||
class bf_write;
|
||||
|
||||
namespace send_datagram {
|
||||
|
||||
hooks::HookFunction<NetChannel, 0> *send_datagram_hook;
|
||||
|
||||
#if doghook_platform_windows()
|
||||
u32 __fastcall hooked_send_datagram(NetChannel *channel, void *, bf_write *datagram)
|
||||
#else
|
||||
u32 hooked_send_datagram(NetChannel *channel, bf_write *datagram)
|
||||
#endif
|
||||
{
|
||||
auto in_state = channel->in_reliable_state();
|
||||
auto in_sequence = channel->in_sequence();
|
||||
|
||||
// TODO: Call out to backtrack
|
||||
backtrack::add_latency_to_netchannel(channel);
|
||||
|
||||
auto ret = send_datagram_hook->call_original<u32>(datagram);
|
||||
|
||||
channel->in_reliable_state() = in_state;
|
||||
channel->in_sequence() = in_sequence;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void level_init() {
|
||||
assert(send_datagram_hook == nullptr);
|
||||
send_datagram_hook = new hooks::HookFunction<NetChannel, 0>(IFace<Engine>()->net_channel_info(), 46, 47, 47, reinterpret_cast<void *>(&hooked_send_datagram));
|
||||
}
|
||||
|
||||
void level_shutdown() {
|
||||
delete send_datagram_hook;
|
||||
send_datagram_hook = nullptr;
|
||||
}
|
||||
|
||||
} // namespace send_datagram
|
7
src/hooks/send_datagram.hh
Normal file
7
src/hooks/send_datagram.hh
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace send_datagram {
|
||||
void level_init();
|
||||
void level_shutdown();
|
||||
|
||||
} // namespace send_datagram
|
@ -147,13 +147,12 @@ static auto find_best_box() {
|
||||
static Convar<bool> doghook_aimbot_enable_backtrack{"doghook_aimbot_enable_backtrack", true, nullptr};
|
||||
static Convar<bool> doghook_aimbot_reverse_backtrack_order{"doghook_aimbot_reverse_backtrack_order", true, nullptr};
|
||||
|
||||
auto visible_target_inner(Player *player, std::pair<int, bool> best_box, u32 current_tick, u32 delta, PlayerHitboxes &hitboxes, u32 hitboxes_count, math::Vector &pos) {
|
||||
if (delta > 0) {
|
||||
auto success = backtrack::backtrack_player_to_tick(player, current_tick - delta);
|
||||
if (success == false) return false;
|
||||
auto visible_target_inner(Player *player, std::pair<int, bool> best_box, u32 tick, math::Vector &pos) {
|
||||
PlayerHitboxes hitboxes;
|
||||
u32 hitboxes_count;
|
||||
|
||||
hitboxes_count = backtrack::hitboxes_for_player(player, tick, hitboxes);
|
||||
|
||||
backtrack::hitboxes_for_player(player, current_tick - delta, hitboxes);
|
||||
}
|
||||
// check best hitbox first
|
||||
if (visible(player, hitboxes.centre[best_box.first], best_box.first)) {
|
||||
pos = hitboxes.centre[best_box.first];
|
||||
@ -191,52 +190,11 @@ auto visible_target_inner(Player *player, std::pair<int, bool> best_box, u32 cur
|
||||
// To compliment this we can check whether any player is visible first, then check all players in tickcount -1
|
||||
// and then -2, so on so forth.
|
||||
|
||||
auto visible_target(Entity *e, math::Vector &pos, u32 &cmd_delta) {
|
||||
auto visible_player(Player *p, std::pair<int, bool> &best_box, u32 tick, math::Vector &pos) {
|
||||
profiler_profile_function();
|
||||
|
||||
// TODO: should entity have a to_player_nocheck() method
|
||||
// as we already know at this point that this is a player...
|
||||
auto player = e->to_player();
|
||||
|
||||
PlayerHitboxes hitboxes;
|
||||
auto hitboxes_count = player->hitboxes(&hitboxes, false);
|
||||
|
||||
// Tell backtrack about these hitboxes
|
||||
backtrack::update_player_hitboxes(player, hitboxes, hitboxes_count);
|
||||
|
||||
auto current_tick = IFace<Globals>()->tickcount;
|
||||
auto best_box = find_best_box();
|
||||
bool reverse_order = doghook_aimbot_reverse_backtrack_order;
|
||||
|
||||
if (!reverse_order) {
|
||||
// Do no backtrack first
|
||||
auto visible = visible_target_inner(player, best_box, current_tick, 0, hitboxes, hitboxes_count, pos);
|
||||
auto visible = visible_target_inner(p, best_box, tick, pos);
|
||||
if (visible) return true;
|
||||
}
|
||||
|
||||
if (!doghook_aimbot_enable_backtrack) return false;
|
||||
|
||||
// If we are going in reverse order then make sure that happens
|
||||
const auto delta_delta = reverse_order ? -1 : 1;
|
||||
auto delta = reverse_order ? backtrack::max_ticks : 0;
|
||||
|
||||
u32 new_tick;
|
||||
|
||||
do {
|
||||
// Go onto the next tick and see what
|
||||
delta += delta_delta;
|
||||
new_tick = current_tick - delta;
|
||||
if (!backtrack::tick_valid(new_tick)) continue;
|
||||
|
||||
if (backtrack::backtrack_player_to_tick(player, current_tick - delta)) {
|
||||
auto visible = visible_target_inner(player, best_box, current_tick, delta, hitboxes, hitboxes_count, pos);
|
||||
if (visible) {
|
||||
cmd_delta = delta;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} while (delta > 0 && delta < backtrack::max_ticks);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -253,7 +211,8 @@ auto valid_target(Entity *e) {
|
||||
}
|
||||
|
||||
void finished_target(Target t) {
|
||||
IFace<DebugOverlay>()->add_entity_text_overlay(t.e->index(), 2, 0, 255, 255, 255, 255, "finished");
|
||||
IFace<DebugOverlay>()->add_entity_text_overlay(t.e->index(), 1, 0, 255, 255, 255, 255, "finished");
|
||||
IFace<DebugOverlay>()->add_entity_text_overlay(t.e->index(), 2, 0, 255, 255, 255, 255, "%d", t.cmd_delta);
|
||||
|
||||
targets.push_back(t);
|
||||
}
|
||||
@ -270,18 +229,17 @@ auto sort_targets() {
|
||||
auto find_targets() {
|
||||
profiler_profile_function();
|
||||
|
||||
if (can_find_targets == false) return;
|
||||
auto best_box = find_best_box();
|
||||
|
||||
// find targets
|
||||
// TODO: clean up this mess
|
||||
auto find_target_inner = [&best_box](u32 tick, u32 delta) {
|
||||
for (auto e : IFace<EntList>()->get_range()) {
|
||||
if (!e->is_valid()) continue;
|
||||
if (e->dormant()) continue;
|
||||
|
||||
if (valid_target(e)) {
|
||||
auto pos = math::Vector::invalid();
|
||||
auto delta = 0u;
|
||||
if (visible_target(e, pos, delta)) {
|
||||
|
||||
if (auto p = e->to_player()) {
|
||||
if (visible_player(p, best_box, tick, pos)) {
|
||||
finished_target(Target{e, pos, delta});
|
||||
|
||||
// Now that we have a target break!
|
||||
@ -290,6 +248,47 @@ auto find_targets() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto current_tick = IFace<Globals>()->tickcount;
|
||||
|
||||
bool reverse_order = doghook_aimbot_reverse_backtrack_order;
|
||||
|
||||
// Easy out
|
||||
if (!reverse_order || !doghook_aimbot_enable_backtrack) {
|
||||
find_target_inner(current_tick, 0);
|
||||
if (targets.size() > 0) {
|
||||
sort_targets();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!doghook_aimbot_enable_backtrack) return;
|
||||
|
||||
const auto delta_delta = reverse_order ? -1 : 1;
|
||||
auto delta = reverse_order ? backtrack::max_ticks : 1;
|
||||
|
||||
u32 new_tick;
|
||||
|
||||
backtrack::RewindState rewind;
|
||||
|
||||
do {
|
||||
new_tick = current_tick - delta;
|
||||
|
||||
if (backtrack::tick_valid(new_tick)) {
|
||||
rewind.to_tick(new_tick);
|
||||
|
||||
find_target_inner(new_tick, delta);
|
||||
|
||||
// we found some targets for this state... stop
|
||||
if (targets.size() > 0) break;
|
||||
}
|
||||
|
||||
// Move to the next tick
|
||||
delta += delta_delta;
|
||||
new_tick = current_tick - delta;
|
||||
} while (delta > 0 && delta < backtrack::max_ticks);
|
||||
|
||||
sort_targets();
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include <precompiled.hh>
|
||||
|
||||
#include <algorithm>
|
||||
#include <queue>
|
||||
|
||||
#include "backtrack.hh"
|
||||
|
||||
#include <sdk/convar.hh>
|
||||
#include <sdk/log.hh>
|
||||
#include <sdk/player.hh>
|
||||
#include <sdk/sdk.hh>
|
||||
@ -84,6 +86,7 @@ public:
|
||||
u32 max_hitboxes;
|
||||
|
||||
// misc
|
||||
u8 life_state;
|
||||
float simulation_time;
|
||||
float animation_time;
|
||||
float choked_time;
|
||||
@ -123,25 +126,91 @@ auto ¤t_record(u32 index) { return record(index, current_tick); }
|
||||
// Players that have been moved this tick and need restoring
|
||||
std::vector<sdk::Player *> players_to_restore;
|
||||
|
||||
struct sequence {
|
||||
u32 in_state;
|
||||
u32 out_state;
|
||||
u32 in_sequence;
|
||||
u32 out_sequence;
|
||||
float cur_time;
|
||||
};
|
||||
|
||||
std::deque<sequence> sequences;
|
||||
u32 last_incoming_sequence;
|
||||
|
||||
Convar<float> doghook_backtrack_latency{"doghook_backtrack_latency", 0, 0, 1, nullptr};
|
||||
|
||||
void add_latency_to_netchannel(NetChannel *c) {
|
||||
float current_time = IFace<Globals>()->realtime;
|
||||
for (auto &s : sequences) {
|
||||
if (current_time - s.cur_time > doghook_backtrack_latency) {
|
||||
c->in_reliable_state() = s.in_state;
|
||||
c->in_sequence() = s.in_sequence;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_incoming_sequences() {
|
||||
NetChannel *c = IFace<Engine>()->net_channel_info();
|
||||
|
||||
auto incoming_sequence = c->in_sequence();
|
||||
|
||||
if (incoming_sequence > last_incoming_sequence) {
|
||||
last_incoming_sequence = incoming_sequence;
|
||||
|
||||
sequences.push_front({c->in_reliable_state(), c->out_reliable_state(), c->in_sequence(), c->out_sequence(), IFace<Globals>()->realtime});
|
||||
}
|
||||
|
||||
if (sequences.size() > 2048)
|
||||
sequences.pop_back();
|
||||
}
|
||||
|
||||
auto latency_outgoing = 0.0f;
|
||||
auto latency_incoming = 0.0f;
|
||||
auto total_latency_time = 0.0f;
|
||||
u32 total_latency_ticks = 0;
|
||||
|
||||
sdk::ConvarWrapper cl_interp{"cl_interp"};
|
||||
|
||||
sdk::ConvarWrapper cl_interp_ratio{"cl_interp_ratio"};
|
||||
sdk::ConvarWrapper cl_update_rate{"cl_updaterate"};
|
||||
|
||||
sdk::ConvarWrapper sv_client_min_interp_ratio{"sv_client_min_interp_ratio"};
|
||||
sdk::ConvarWrapper sv_client_max_interp_ratio{"sv_client_max_interp_ratio"};
|
||||
|
||||
sdk::ConvarWrapper sv_minupdaterate{"sv_minupdaterate"};
|
||||
sdk::ConvarWrapper sv_maxupdaterate{"sv_maxupdaterate"};
|
||||
|
||||
sdk::ConvarWrapper sv_maxunlag{"sv_maxunlag"};
|
||||
|
||||
float lerp_time() {
|
||||
auto interp_ratio = std::clamp(cl_interp_ratio.get_float(), sv_client_min_interp_ratio.get_float(), sv_client_max_interp_ratio.get_float());
|
||||
auto update_rate = std::clamp(cl_update_rate.get_float(), sv_minupdaterate.get_float(), sv_maxupdaterate.get_float());
|
||||
|
||||
auto lerp_time = std::max(interp_ratio / update_rate, cl_interp.get_float());
|
||||
|
||||
return lerp_time;
|
||||
}
|
||||
|
||||
bool tick_valid(u32 tick) {
|
||||
auto net_channel = IFace<Engine>()->net_channel_info();
|
||||
|
||||
// TODO: do not hardcode
|
||||
// Assuming lowest possible
|
||||
auto lerp_time = 0.015f;
|
||||
auto lerp_ticks = 1;
|
||||
auto lerp = lerp_time();
|
||||
auto lerp_ticks = IFace<Globals>()->time_to_ticks(lerp);
|
||||
|
||||
auto cmd_arrive_tick = IFace<Globals>()->tickcount + 1;
|
||||
auto correct = std::clamp(lerp + doghook_backtrack_latency + latency_outgoing, 0.0f, sv_maxunlag.get_float());
|
||||
|
||||
auto correct = std::clamp(lerp_time + latency_outgoing, 0.0f, 0.1f) -
|
||||
IFace<Globals>()->ticks_to_time(cmd_arrive_tick - tick);
|
||||
auto delta_time = correct - IFace<Globals>()->ticks_to_time(IFace<Globals>()->tickcount + 1 + lerp_ticks - tick);
|
||||
|
||||
return std::abs(correct) <= 0.2;
|
||||
bool valid = std::abs(delta_time) <= 0.2;
|
||||
|
||||
if (!valid) {
|
||||
auto new_tick = IFace<Globals>()->tickcount - IFace<Globals>()->time_to_ticks(correct);
|
||||
//logging::msg("[Backtracking] !valid (%d -> %d d: %d)", tick, new_tick, new_tick - tick);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
// Update player to this record
|
||||
@ -219,16 +288,20 @@ static bool restore_player_to_record(sdk::Player *p, const Record &r) {
|
||||
}
|
||||
|
||||
// Backtrack a player to this tick
|
||||
bool backtrack_player_to_tick(sdk::Player *p, u32 tick, bool restoring) {
|
||||
bool backtrack_player_to_tick(sdk::Player *p, u32 tick, bool set_alive, bool restoring) {
|
||||
profiler_profile_function();
|
||||
|
||||
auto array_index = entity_index_to_array_index(p->index());
|
||||
|
||||
auto &r = record(array_index, tick);
|
||||
if (!r.alive) return false;
|
||||
|
||||
if (set_alive) p->life_state() = r.life_state;
|
||||
|
||||
if (!restoring) players_to_restore.push_back(p);
|
||||
return restore_player_to_record(p, r);
|
||||
|
||||
bool success = restore_player_to_record(p, r);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Set the hitboxes for this player at this tick
|
||||
@ -243,22 +316,26 @@ void update_player_hitboxes(sdk::Player *p, const sdk::PlayerHitboxes &hitboxes,
|
||||
|
||||
// Get the hitboxes for this player at this tick
|
||||
// TODO: this can probably just return a const pointer to the hitboxes inside the record
|
||||
void hitboxes_for_player(sdk::Player *p, u32 tick, sdk::PlayerHitboxes &hitboxes) {
|
||||
u32 hitboxes_for_player(sdk::Player *p, u32 tick, sdk::PlayerHitboxes &hitboxes) {
|
||||
profiler_profile_function();
|
||||
|
||||
auto array_index = entity_index_to_array_index(p->index());
|
||||
|
||||
auto &r = record(array_index, tick);
|
||||
|
||||
if (!r.alive) return;
|
||||
if (!r.alive) return 0;
|
||||
|
||||
std::memcpy(&hitboxes, &r.hitboxes, sizeof(PlayerHitboxes));
|
||||
|
||||
return r.max_hitboxes;
|
||||
}
|
||||
|
||||
// Get new information about each player
|
||||
void create_move_pre_predict(sdk::UserCmd *cmd) {
|
||||
profiler_profile_function();
|
||||
|
||||
update_incoming_sequences();
|
||||
|
||||
current_tick = IFace<Globals>()->tickcount;
|
||||
|
||||
auto local_player = Player::local();
|
||||
@ -286,6 +363,7 @@ void create_move_pre_predict(sdk::UserCmd *cmd) {
|
||||
// Clean out the record - might not be necessary but a memset is pretty cheap
|
||||
new_record.reset();
|
||||
|
||||
new_record.life_state = player->life_state();
|
||||
new_record.alive = player->alive();
|
||||
if (player->dormant()) new_record.alive = false;
|
||||
|
||||
@ -330,7 +408,7 @@ void create_move_pre_predict(sdk::UserCmd *cmd) {
|
||||
new_record.animation_layers[i] = player->anim_layer(i);
|
||||
}
|
||||
|
||||
// TODO: pose parameters (are these even important??)
|
||||
new_record.max_hitboxes = player->hitboxes(&new_record.hitboxes, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,12 +421,16 @@ void create_move(sdk::UserCmd *cmd) {
|
||||
|
||||
auto player = entity->to_player();
|
||||
if (auto player = entity->to_player()) {
|
||||
// for (auto &r : record_track(player->index()))
|
||||
{
|
||||
auto &r = record(player->index(), IFace<Globals>()->tickcount + 1);
|
||||
for (auto &r : record_track(player->index())) {
|
||||
//auto &r = record(player->index(), IFace<Globals>()->tickcount + 1);
|
||||
|
||||
if (!r.alive) continue;
|
||||
|
||||
if (!tick_valid(r.this_tick)) continue;
|
||||
|
||||
IFace<DebugOverlay>()->add_box_overlay(r.origin, {-2, -2, -2}, {2, 2, 2}, {0, 0, 0}, 0, 255, 0, 100, 0);
|
||||
|
||||
#if 0
|
||||
auto &hitboxes = r.hitboxes;
|
||||
for (u32 i = 0; i < r.max_hitboxes; i++) {
|
||||
|
||||
@ -359,8 +441,6 @@ void create_move(sdk::UserCmd *cmd) {
|
||||
|
||||
IFace<DebugOverlay>()->add_box_overlay(hitboxes.origin[i], hitboxes.raw_min[i], hitboxes.raw_max[i], hitboxes.rotation[i], r, g, b, 100, 0);
|
||||
|
||||
auto bone_transform = hitboxes.bone_to_world[i];
|
||||
|
||||
//math::Vector origin;
|
||||
//math::Vector angles;
|
||||
//math::matrix_angles(bone_transform, angles, origin);
|
||||
@ -371,19 +451,64 @@ void create_move(sdk::UserCmd *cmd) {
|
||||
|
||||
//IFace<DebugOverlay>()->add_box_overlay(origin, hitboxes.raw_min[i], hitboxes.raw_max[i], angles, r, g, b, 100, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void restore_all_players() {
|
||||
for (auto &p : players_to_restore)
|
||||
backtrack_player_to_tick(p, current_tick, true, true);
|
||||
|
||||
players_to_restore.clear();
|
||||
}
|
||||
|
||||
void create_move_finish(sdk::UserCmd *cmd) {
|
||||
profiler_profile_function();
|
||||
|
||||
// Cleanup from whatever has been done
|
||||
for (auto &p : players_to_restore)
|
||||
backtrack_player_to_tick(p, current_tick, true);
|
||||
restore_all_players();
|
||||
}
|
||||
|
||||
players_to_restore.clear();
|
||||
bool rewind_state_active = false;
|
||||
RewindState::RewindState() {
|
||||
assert(!rewind_state_active);
|
||||
|
||||
rewind_state_active = true;
|
||||
}
|
||||
|
||||
RewindState::~RewindState() {
|
||||
restore_all_players();
|
||||
|
||||
rewind_state_active = false;
|
||||
}
|
||||
|
||||
// TODO: if a player isnt alive at a record then we need a way
|
||||
// of effectively eliminating their bones from traceray
|
||||
void RewindState::to_tick(u32 t) {
|
||||
// TODO: could this be multithreaded effectively?
|
||||
|
||||
auto local_player = Player::local();
|
||||
|
||||
for (auto entity : IFace<EntList>()->get_range(IFace<Engine>()->max_clients() + 1)) {
|
||||
if (!entity->is_valid()) continue;
|
||||
|
||||
if (auto p = entity->to_player()) {
|
||||
if (p == local_player) continue;
|
||||
|
||||
if (p->team() == local_player->team()) continue;
|
||||
|
||||
// Setalive so that dead players at this tick are dead...
|
||||
// This means that aimbots is_valid will work properly
|
||||
auto success = backtrack_player_to_tick(p, t, true);
|
||||
|
||||
if (!success) {
|
||||
// Player isnt valid this tick...
|
||||
// TODO: Set hitboxes to invalid here...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace backtrack
|
||||
|
@ -5,20 +5,34 @@
|
||||
namespace sdk {
|
||||
class UserCmd;
|
||||
class Player;
|
||||
class NetChannel;
|
||||
struct PlayerHitboxes;
|
||||
} // namespace sdk
|
||||
|
||||
namespace backtrack {
|
||||
// Helper class to rewind all players back to a specific tick
|
||||
class RewindState {
|
||||
public:
|
||||
RewindState();
|
||||
~RewindState();
|
||||
|
||||
void to_tick(u32 tick);
|
||||
};
|
||||
|
||||
enum { max_ticks = 66 };
|
||||
|
||||
void create_move_pre_predict(sdk::UserCmd *cmd);
|
||||
void create_move(sdk::UserCmd *cmd);
|
||||
void create_move_finish(sdk::UserCmd *cmd);
|
||||
|
||||
// Returns true if this tick was valid
|
||||
bool backtrack_player_to_tick(sdk::Player *p, u32 tick, bool restoring = false);
|
||||
float lerp_time();
|
||||
bool tick_valid(u32 tick);
|
||||
|
||||
void update_player_hitboxes(sdk::Player *p, const sdk::PlayerHitboxes &hitboxes, u32 hitboxes_count);
|
||||
void hitboxes_for_player(sdk::Player *p, u32 tick, sdk::PlayerHitboxes &hitboxes);
|
||||
u32 hitboxes_for_player(sdk::Player *p, u32 tick, sdk::PlayerHitboxes &hitboxes);
|
||||
|
||||
// Returns true if this tick was valid
|
||||
// You should be using RewindState instead of this...
|
||||
bool backtrack_player_to_tick(sdk::Player *p, u32 tick, bool set_alive = false, bool restoring = false);
|
||||
|
||||
void add_latency_to_netchannel(sdk::NetChannel *channel);
|
||||
} // namespace backtrack
|
||||
|
@ -92,8 +92,8 @@ void create_move(UserCmd *cmd) {
|
||||
|
||||
last_wep_id = current_wep_id;
|
||||
|
||||
if (IFace<InputSystem>()->is_button_down((ButtonCode)(int)doghook_lagexploit_key)) // SDK is gay // look in inputcodes.hh for possible solution and nicer shit
|
||||
if (IFace<InputSystem>()->is_button_down((ButtonCode)(int)doghook_lagexploit_key))
|
||||
numsequnce = doghook_lagexploit_ticks * (doghook_lagexploit_backup ? 90 : 66);
|
||||
IFace<Engine>()->net_channel_info()->m_nOutSequenceNr() += numsequnce;
|
||||
IFace<Engine>()->net_channel_info()->out_sequence() += numsequnce;
|
||||
};
|
||||
}; // namespace lagexploit
|
||||
|
@ -10,9 +10,62 @@ using namespace sdk;
|
||||
|
||||
namespace misc {
|
||||
|
||||
static sdk::ConvarWrapper sv_cheats{"sv_cheats"};
|
||||
// TODO: cleanup and move out of here
|
||||
enum cvar_flags {
|
||||
FCVAR_UNREGISTERED = (1 << 0), // If this is set, don't add to linked list, etc.
|
||||
FCVAR_DEVELOPMENTONLY = (1 << 1), // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined.
|
||||
FCVAR_GAMEDLL = (1 << 2), // defined by the game DLL
|
||||
FCVAR_CLIENTDLL = (1 << 3), // defined by the client DLL
|
||||
FCVAR_HIDDEN = (1 << 4), // Hidden. Doesn't appear in find or autocomplete. Like DEVELOPMENTONLY, but can't be compiled out.
|
||||
|
||||
// ConVar only
|
||||
FCVAR_PROTECTED = (1 << 5), // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
|
||||
FCVAR_SPONLY = (1 << 6), // This cvar cannot be changed by clients connected to a multiplayer server.
|
||||
FCVAR_ARCHIVE = (1 << 7), // set to cause it to be saved to vars.rc
|
||||
FCVAR_NOTIFY = (1 << 8), // notifies players when changed
|
||||
FCVAR_USERINFO = (1 << 9), // changes the client's info string
|
||||
FCVAR_CHEAT = (1 << 14), // Only useable in singleplayer / debug / multiplayer & sv_cheats
|
||||
|
||||
FCVAR_PRINTABLEONLY = (1 << 10), // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
|
||||
FCVAR_UNLOGGED = (1 << 11), // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
|
||||
FCVAR_NEVER_AS_STRING = (1 << 12), // never try to print that cvar
|
||||
|
||||
// It's a ConVar that's shared between the client and the server.
|
||||
// At signon, the values of all such ConVars are sent from the server to the client (skipped for local
|
||||
// client, of course )
|
||||
// If a change is requested it must come from the console (i.e., no remote client changes)
|
||||
// If a value is changed while a server is active, it's replicated to all connected clients
|
||||
FCVAR_REPLICATED = (1 << 13), // server setting enforced on clients, TODO rename to FCAR_SERVER at some time
|
||||
FCVAR_DEMO = (1 << 16), // record this cvar when starting a demo file
|
||||
FCVAR_DONTRECORD = (1 << 17), // don't record these command in demofiles
|
||||
FCVAR_RELOAD_MATERIALS = (1 << 20), // If this cvar changes, it forces a material reload
|
||||
FCVAR_RELOAD_TEXTURES = (1 << 21), // If this cvar changes, if forces a texture reload
|
||||
|
||||
FCVAR_NOT_CONNECTED = (1 << 22), // cvar cannot be changed by a client that is connected to a server
|
||||
FCVAR_MATERIAL_SYSTEM_THREAD = (1 << 23), // Indicates this cvar is read from the material system thread
|
||||
FCVAR_ARCHIVE_XBOX = (1 << 24), // cvar written to config.cfg on the Xbox
|
||||
|
||||
FCVAR_ACCESSIBLE_FROM_THREADS = (1 << 25), // used as a debugging tool necessary to check material system thread convars
|
||||
|
||||
FCVAR_SERVER_CAN_EXECUTE = (1 << 28), // the server is allowed to execute this command on clients via ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd.
|
||||
FCVAR_SERVER_CANNOT_QUERY = (1 << 29), // If this is set, then the server is not allowed to query this cvar's value (via IServerPluginHelpers::StartQueryCvarValue).
|
||||
FCVAR_CLIENTCMD_CAN_EXECUTE = (1 << 30), // IVEngineClient::ClientCmd is allowed to execute this command.
|
||||
// Note: IVEngineClient::ClientCmd_Unrestricted can run any client command.
|
||||
};
|
||||
|
||||
void init_all() {
|
||||
sv_cheats.set_flags(0);
|
||||
for (auto c : sdk::ConvarWrapper::get_range()) {
|
||||
auto flags = c.flags();
|
||||
flags &= ~FCVAR_CHEAT;
|
||||
flags &= ~FCVAR_DEVELOPMENTONLY;
|
||||
flags &= ~FCVAR_PROTECTED;
|
||||
flags &= ~FCVAR_SPONLY;
|
||||
flags &= ~FCVAR_CHEAT;
|
||||
flags &= ~FCVAR_REPLICATED;
|
||||
flags &= ~FCVAR_NOT_CONNECTED;
|
||||
flags &= ~FCVAR_HIDDEN;
|
||||
|
||||
c.set_flags(flags);
|
||||
}
|
||||
}
|
||||
} // namespace misc
|
||||
|
@ -412,4 +412,11 @@ void ConvarWrapper::set_value(const char *v) {
|
||||
base->set_value(v);
|
||||
}
|
||||
|
||||
ConvarWrapper ConvarWrapper::Range::Iterator::operator++() {
|
||||
current = current->next;
|
||||
return ConvarWrapper(const_cast<ConCommandBase *>(current));
|
||||
}
|
||||
|
||||
ConvarWrapper::Range::Iterator ConvarWrapper::Range::begin() const { return Iterator(IFace<Cvar>()->root_node()); }
|
||||
|
||||
} // namespace sdk
|
||||
|
@ -309,6 +309,8 @@ public:
|
||||
class ConvarWrapper {
|
||||
ConCommandBase *base;
|
||||
|
||||
ConvarWrapper(ConCommandBase *b) : base(b) {}
|
||||
|
||||
public:
|
||||
ConvarWrapper(const char *name);
|
||||
|
||||
@ -325,6 +327,33 @@ public:
|
||||
void set_value(int v);
|
||||
void set_value(float v);
|
||||
void set_value(const char *v);
|
||||
|
||||
class Range {
|
||||
public:
|
||||
class Iterator {
|
||||
const ConCommandBase *current;
|
||||
|
||||
public:
|
||||
Iterator() : current(nullptr) {}
|
||||
explicit Iterator(const ConCommandBase *b) : current(b) {}
|
||||
|
||||
ConvarWrapper operator++();
|
||||
|
||||
auto operator*() const {
|
||||
assert(current);
|
||||
return ConvarWrapper(const_cast<ConCommandBase *>(current));
|
||||
}
|
||||
|
||||
auto operator==(const Iterator &b) const { return current == b.current; }
|
||||
auto operator!=(const Iterator &b) const { return !(*this == b); }
|
||||
};
|
||||
|
||||
Iterator begin() const;
|
||||
|
||||
Iterator end() const { return Iterator(nullptr); }
|
||||
};
|
||||
|
||||
static auto get_range() { return Range(); }
|
||||
};
|
||||
|
||||
} // namespace sdk
|
||||
|
@ -24,10 +24,10 @@ public:
|
||||
auto set(u32 offset, T data) { *reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + offset) = data; }
|
||||
|
||||
template <typename T, u32 offset>
|
||||
auto get() { return *reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + offset); }
|
||||
auto &get() { return *reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + offset); }
|
||||
|
||||
template <typename T>
|
||||
auto get(u32 offset) { return *reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + offset); }
|
||||
auto &get(u32 offset) { return *reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + offset); }
|
||||
|
||||
// upcasts
|
||||
class Player *to_player();
|
||||
|
@ -181,7 +181,7 @@ public:
|
||||
using F = ret(__thiscall *)(T *, Args...);
|
||||
#endif
|
||||
auto function = reinterpret_cast<F>(original_function);
|
||||
function(instance, args...);
|
||||
return function(instance, args...);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,10 @@ int & Player::health() {
|
||||
}
|
||||
|
||||
static auto lifestate = Netvar("DT_BasePlayer", "m_lifeState");
|
||||
u8 & Player::life_state() {
|
||||
return ::lifestate.get<u8>(this);
|
||||
}
|
||||
|
||||
bool Player::alive() {
|
||||
return ::lifestate.get<u8>(this) == 0;
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ public:
|
||||
// netvars
|
||||
int &health();
|
||||
|
||||
u8 & life_state();
|
||||
bool alive();
|
||||
int team();
|
||||
|
||||
|
@ -91,11 +91,17 @@ public:
|
||||
return queued_packets;
|
||||
}
|
||||
|
||||
i32 &m_nOutSequenceNr() {
|
||||
static u32 m_nOutSequenceNr_offset = 8; // TODO: don't hardcode
|
||||
// Below this point are functions that use offsets
|
||||
// These offsets should be consistent accross multiple platforms
|
||||
// As the netchannel structure is the same
|
||||
|
||||
return *(i32 *)((u32)this + m_nOutSequenceNr_offset);
|
||||
}
|
||||
template <typename T, u32 offset>
|
||||
auto &get() { return *reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + offset); }
|
||||
|
||||
auto &out_sequence() { return get<u32, 8>(); }
|
||||
auto &in_sequence() { return get<u32, 12>(); }
|
||||
auto &in_reliable_state() { return get<u32, 24>(); }
|
||||
auto &out_reliable_state() { return get<u32, 20>(); }
|
||||
};
|
||||
|
||||
class Globals {
|
||||
|
Reference in New Issue
Block a user