From 8f6602ed3f17f693e7ba2c9b59504c2ad9b0c831 Mon Sep 17 00:00:00 2001 From: F1ssi0N Date: Sun, 8 Apr 2018 00:34:56 +0100 Subject: [PATCH] 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 --- src/doghook.cc | 5 ++ src/hooks/send_datagram.cc | 47 ++++++++++ src/hooks/send_datagram.hh | 7 ++ src/modules/aimbot.cc | 129 ++++++++++++++-------------- src/modules/backtra.cc | 171 ++++++++++++++++++++++++++++++++----- src/modules/backtrack.hh | 24 ++++-- src/modules/lagexploit.cc | 4 +- src/modules/misc.cc | 57 ++++++++++++- src/sdk/convar.cc | 7 ++ src/sdk/convar.hh | 29 +++++++ src/sdk/entity.hh | 4 +- src/sdk/hooks.hh | 2 +- src/sdk/player.cc | 6 +- src/sdk/player.hh | 1 + src/sdk/sdk.hh | 14 ++- 15 files changed, 402 insertions(+), 105 deletions(-) create mode 100644 src/hooks/send_datagram.cc create mode 100644 src/hooks/send_datagram.hh diff --git a/src/doghook.cc b/src/doghook.cc index 67632c1..f8fb584 100644 --- a/src/doghook.cc +++ b/src/doghook.cc @@ -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"); } diff --git a/src/hooks/send_datagram.cc b/src/hooks/send_datagram.cc new file mode 100644 index 0000000..39d4ed5 --- /dev/null +++ b/src/hooks/send_datagram.cc @@ -0,0 +1,47 @@ +#include + +#include +#include +#include + +#include + +using namespace sdk; + +class bf_write; + +namespace send_datagram { + +hooks::HookFunction *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(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(IFace()->net_channel_info(), 46, 47, 47, reinterpret_cast(&hooked_send_datagram)); +} + +void level_shutdown() { + delete send_datagram_hook; + send_datagram_hook = nullptr; +} + +} // namespace send_datagram diff --git a/src/hooks/send_datagram.hh b/src/hooks/send_datagram.hh new file mode 100644 index 0000000..4b253b7 --- /dev/null +++ b/src/hooks/send_datagram.hh @@ -0,0 +1,7 @@ +#pragma once + +namespace send_datagram { +void level_init(); +void level_shutdown(); + +} // namespace send_datagram diff --git a/src/modules/aimbot.cc b/src/modules/aimbot.cc index 20daaa1..e284a43 100644 --- a/src/modules/aimbot.cc +++ b/src/modules/aimbot.cc @@ -147,13 +147,12 @@ static auto find_best_box() { static Convar doghook_aimbot_enable_backtrack{"doghook_aimbot_enable_backtrack", true, nullptr}; static Convar doghook_aimbot_reverse_backtrack_order{"doghook_aimbot_reverse_backtrack_order", true, nullptr}; -auto visible_target_inner(Player *player, std::pair 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 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 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 &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()->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); - 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); + auto visible = visible_target_inner(p, best_box, tick, pos); + if (visible) return true; return false; } @@ -253,7 +211,8 @@ auto valid_target(Entity *e) { } void finished_target(Target t) { - IFace()->add_entity_text_overlay(t.e->index(), 2, 0, 255, 255, 255, 255, "finished"); + IFace()->add_entity_text_overlay(t.e->index(), 1, 0, 255, 255, 255, 255, "finished"); + IFace()->add_entity_text_overlay(t.e->index(), 2, 0, 255, 255, 255, 255, "%d", t.cmd_delta); targets.push_back(t); } @@ -270,27 +229,67 @@ 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 - for (auto e : IFace()->get_range()) { - if (!e->is_valid()) continue; - if (e->dormant()) continue; + auto find_target_inner = [&best_box](u32 tick, u32 delta) { + for (auto e : IFace()->get_range()) { + if (!e->is_valid()) continue; - if (valid_target(e)) { - auto pos = math::Vector::invalid(); - auto delta = 0u; - if (visible_target(e, pos, delta)) { - finished_target(Target{e, pos, delta}); + if (valid_target(e)) { + auto pos = math::Vector::invalid(); - // Now that we have a target break! - // TODO: only do this when we want to do speedy targets! - //break; + 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! + // TODO: only do this when we want to do speedy targets! + //break; + } + } } } + }; + + auto current_tick = IFace()->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(); } diff --git a/src/modules/backtra.cc b/src/modules/backtra.cc index 820b58a..5461e29 100644 --- a/src/modules/backtra.cc +++ b/src/modules/backtra.cc @@ -1,9 +1,11 @@ #include #include +#include #include "backtrack.hh" +#include #include #include #include @@ -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 players_to_restore; +struct sequence { + u32 in_state; + u32 out_state; + u32 in_sequence; + u32 out_sequence; + float cur_time; +}; + +std::deque sequences; +u32 last_incoming_sequence; + +Convar doghook_backtrack_latency{"doghook_backtrack_latency", 0, 0, 1, nullptr}; + +void add_latency_to_netchannel(NetChannel *c) { + float current_time = IFace()->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()->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()->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()->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()->time_to_ticks(lerp); - auto cmd_arrive_tick = IFace()->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()->ticks_to_time(cmd_arrive_tick - tick); + auto delta_time = correct - IFace()->ticks_to_time(IFace()->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()->tickcount - IFace()->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()->tickcount; auto local_player = Player::local(); @@ -286,7 +363,8 @@ 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.alive = player->alive(); + new_record.life_state = player->life_state(); + new_record.alive = player->alive(); if (player->dormant()) new_record.alive = false; // If this fails then it is clear to other algorithms whether this record is valid just by looking at this bool @@ -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()->tickcount + 1); + for (auto &r : record_track(player->index())) { + //auto &r = record(player->index(), IFace()->tickcount + 1); if (!r.alive) continue; + if (!tick_valid(r.this_tick)) continue; + + IFace()->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()->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()->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()->get_range(IFace()->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 diff --git a/src/modules/backtrack.hh b/src/modules/backtrack.hh index e6f1883..990e528 100644 --- a/src/modules/backtrack.hh +++ b/src/modules/backtrack.hh @@ -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); -bool tick_valid(u32 tick); +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 diff --git a/src/modules/lagexploit.cc b/src/modules/lagexploit.cc index d7bae7b..b2b58ad 100644 --- a/src/modules/lagexploit.cc +++ b/src/modules/lagexploit.cc @@ -92,8 +92,8 @@ void create_move(UserCmd *cmd) { last_wep_id = current_wep_id; - if (IFace()->is_button_down((ButtonCode)(int)doghook_lagexploit_key)) // SDK is gay // look in inputcodes.hh for possible solution and nicer shit + if (IFace()->is_button_down((ButtonCode)(int)doghook_lagexploit_key)) numsequnce = doghook_lagexploit_ticks * (doghook_lagexploit_backup ? 90 : 66); - IFace()->net_channel_info()->m_nOutSequenceNr() += numsequnce; + IFace()->net_channel_info()->out_sequence() += numsequnce; }; }; // namespace lagexploit diff --git a/src/modules/misc.cc b/src/modules/misc.cc index 7acab20..b6fd9f0 100644 --- a/src/modules/misc.cc +++ b/src/modules/misc.cc @@ -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 diff --git a/src/sdk/convar.cc b/src/sdk/convar.cc index 849186a..503d00e 100644 --- a/src/sdk/convar.cc +++ b/src/sdk/convar.cc @@ -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(current)); +} + +ConvarWrapper::Range::Iterator ConvarWrapper::Range::begin() const { return Iterator(IFace()->root_node()); } + } // namespace sdk diff --git a/src/sdk/convar.hh b/src/sdk/convar.hh index 310e2f8..e79dd7e 100644 --- a/src/sdk/convar.hh +++ b/src/sdk/convar.hh @@ -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(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 diff --git a/src/sdk/entity.hh b/src/sdk/entity.hh index 3862db7..34f2437 100644 --- a/src/sdk/entity.hh +++ b/src/sdk/entity.hh @@ -24,10 +24,10 @@ public: auto set(u32 offset, T data) { *reinterpret_cast(reinterpret_cast(this) + offset) = data; } template - auto get() { return *reinterpret_cast(reinterpret_cast(this) + offset); } + auto &get() { return *reinterpret_cast(reinterpret_cast(this) + offset); } template - auto get(u32 offset) { return *reinterpret_cast(reinterpret_cast(this) + offset); } + auto &get(u32 offset) { return *reinterpret_cast(reinterpret_cast(this) + offset); } // upcasts class Player *to_player(); diff --git a/src/sdk/hooks.hh b/src/sdk/hooks.hh index aff4db1..62f3c64 100644 --- a/src/sdk/hooks.hh +++ b/src/sdk/hooks.hh @@ -181,7 +181,7 @@ public: using F = ret(__thiscall *)(T *, Args...); #endif auto function = reinterpret_cast(original_function); - function(instance, args...); + return function(instance, args...); } }; diff --git a/src/sdk/player.cc b/src/sdk/player.cc index 9c6b0e2..40897d5 100644 --- a/src/sdk/player.cc +++ b/src/sdk/player.cc @@ -21,7 +21,11 @@ int & Player::health() { } static auto lifestate = Netvar("DT_BasePlayer", "m_lifeState"); -bool Player::alive() { +u8 & Player::life_state() { + return ::lifestate.get(this); +} + +bool Player::alive() { return ::lifestate.get(this) == 0; } diff --git a/src/sdk/player.hh b/src/sdk/player.hh index 9d9d887..4b63348 100644 --- a/src/sdk/player.hh +++ b/src/sdk/player.hh @@ -62,6 +62,7 @@ public: // netvars int &health(); + u8 & life_state(); bool alive(); int team(); diff --git a/src/sdk/sdk.hh b/src/sdk/sdk.hh index 31537bc..325dc3c 100644 --- a/src/sdk/sdk.hh +++ b/src/sdk/sdk.hh @@ -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 + auto &get() { return *reinterpret_cast(reinterpret_cast(this) + offset); } + + auto &out_sequence() { return get(); } + auto &in_sequence() { return get(); } + auto &in_reliable_state() { return get(); } + auto &out_reliable_state() { return get(); } }; class Globals {