Lagexploit + convar fix (#36)

* InputSystem m33m

* CS fixes???

* doom'n'shoot

* Significantly cleanup lagexploit code and fix convar constructor issues

* Add clip1 to weapon class further lagexploit cleanup

* Fix some more code style

* Add convarwrapper meme

* Ensure that profiler leaf functions are never inlined to save the icache

* Enable AVX extensions and fix some platform defines

* Properly move cmd_delta into the target structure

* Fix some codestyle memes
This commit is contained in:
F1ssi0N 2018-04-05 13:08:38 +01:00 committed by Marc
parent 9c99ba9701
commit c34b8dd1b7
17 changed files with 468 additions and 67 deletions

View File

@ -39,6 +39,8 @@ workspace "doghook"
optimize "Full"
symbols "Off"
flags {"LinkTimeOptimization"}
floatingpoint "Fast"
vectorextensions "AVX"
filter {}

View File

@ -19,10 +19,11 @@
#include "hooks/engine_vgui.hh"
#include "modules/esp.hh"
#include "modules/misc.hh"
#include "utils/profiler.hh"
static Convar<bool> doghook_profiling_enabled{"doghook_profiling_enabled", false, nullptr};
static sdk::Convar<bool> doghook_profiling_enabled{"doghook_profiling_enabled", false, nullptr};
// Singleton for doing init / deinit of doghook
// and dealing with hooks from gamesystem
@ -104,6 +105,9 @@ public:
"client", "8B 0D ? ? ? ? 8B 01 FF 50 28 56", 2));
else if constexpr (doghook_platform::linux())
IFace<sdk::MoveHelper>().set_from_pointer(nullptr);
IFace<sdk::InputSystem>().set_from_interface("inputsystem", "InputSystemVersion");
inited = true;
}
@ -125,12 +129,14 @@ public:
sdk::Netvar::init_all();
// register all convars now that we have the interfaces we need
ConvarBase::init_all();
sdk::ConvarBase::init_all();
// Setup drawing and paint hook
sdk::draw::init(sdk::draw::RenderTarget::surface);
paint_hook::init_all();
misc::init_all();
// at this point we are now inited and ready to go!
inited = true;
}

View File

@ -2,7 +2,6 @@
#include "aimbot.hh"
// TODO:
#include "backtrack.hh"
#include "sdk/class_id.hh"
@ -23,7 +22,11 @@
using namespace sdk;
namespace aimbot {
using Target = std::pair<Entity *, math::Vector>;
struct Target {
Entity * e;
math::Vector v;
u32 cmd_delta;
};
std::vector<Target> targets;
@ -35,10 +38,6 @@ Weapon *local_weapon;
int local_team;
math::Vector local_view;
// TODO: HORRIBLE HACK
// this needs to be done on a per target basis and not like this !!!
u32 cmd_delta = 0;
// Check it a point is visible to the player
static auto visible_no_entity(const math::Vector &position) {
trace::TraceResult result;
@ -182,7 +181,7 @@ auto visible_target_inner(Player *player, std::pair<int, bool> best_box, u32 cur
return false;
}
auto visible_target(Entity *e, math::Vector &pos) {
auto visible_target(Entity *e, math::Vector &pos, u32 &cmd_delta) {
profiler_profile_function();
// TODO: should entity have a to_player_nocheck() method
@ -197,7 +196,7 @@ auto visible_target(Entity *e, math::Vector &pos) {
auto current_tick = IFace<Globals>()->tickcount;
auto best_box = find_best_box();
auto reverse_order = !!doghook_aimbot_reverse_backtrack_order;
bool reverse_order = doghook_aimbot_reverse_backtrack_order;
if (!reverse_order) {
// Do no backtrack first
@ -208,8 +207,8 @@ auto visible_target(Entity *e, math::Vector &pos) {
if (!doghook_aimbot_enable_backtrack) return false;
// If we are going in reverse order then make sure that happens
const auto delta_delta = doghook_aimbot_reverse_backtrack_order ? -1 : 1;
auto delta = doghook_aimbot_reverse_backtrack_order ? backtrack::max_ticks : 0;
const auto delta_delta = reverse_order ? -1 : 1;
auto delta = reverse_order ? backtrack::max_ticks : 0;
u32 new_tick;
@ -244,9 +243,7 @@ auto valid_target(Entity *e) {
}
void finished_target(Target t) {
assert(t.first != nullptr);
IFace<DebugOverlay>()->add_entity_text_overlay(t.first->index(), 2, 0, 255, 255, 255, 255, "finished");
IFace<DebugOverlay>()->add_entity_text_overlay(t.e->index(), 2, 0, 255, 255, 255, 255, "finished");
targets.push_back(t);
}
@ -254,13 +251,11 @@ void finished_target(Target t) {
auto sort_targets() {
profiler_profile_function();
auto count = targets.size();
std::sort(targets.begin(), targets.end(),
[](const Target &a, const Target &b) {
// Ignore null targets (artifact of having a resized vector mess
if (a.first == nullptr) return false;
if (b.first == nullptr) return false;
return a.second.distance(local_view) < b.second.distance(local_view);
return a.v.distance(local_view) < b.v.distance(local_view);
});
}
@ -277,8 +272,9 @@ auto find_targets() {
if (valid_target(e)) {
auto pos = math::Vector::invalid();
if (visible_target(e, pos)) {
finished_target(Target{e, pos});
auto delta = 0u;
if (visible_target(e, pos, delta)) {
finished_target(Target{e, pos, delta});
// Now that we have a target break!
// TODO: only do this when we want to do speedy targets!
@ -329,12 +325,16 @@ static auto try_autoshoot(sdk::UserCmd *cmd) {
auto autoshoot_allowed = false;
// Only allow autoshoot when we are zoomed and can get headshots
if (local_weapon->client_class()->class_id == class_id::CTFSniperRifle && (local_player->cond() & 2)) {
if (local_weapon->client_class()->class_id == class_id::CTFSniperRifle) {
if ((local_player->cond() & 2)) {
auto player_time = local_player->tick_base() * IFace<Globals>()->interval_per_tick;
auto time_delta = player_time - local_player->fov_time();
if (time_delta >= 0.2) autoshoot_allowed = true;
}
} else {
autoshoot_allowed = true;
}
if (autoshoot_allowed) cmd->buttons |= 1;
}
@ -356,14 +356,16 @@ void create_move(sdk::UserCmd *cmd) {
if ((cmd->buttons & 1) != 1) return;
}
if (targets.size() > 0 && targets[0].first != nullptr) {
IFace<DebugOverlay>()->add_box_overlay(targets[0].second, {-2, -2, -2}, {2, 2, 2}, {0, 0, 0}, 255, 255, 0, 100, 0);
if (targets.size() > 0 && targets[0].e != nullptr) {
auto &target = targets[0];
math::Vector delta = targets[0].second - local_view;
math::Vector new_angles = delta.to_angle();
IFace<DebugOverlay>()->add_box_overlay(target.v, {-2, -2, -2}, {2, 2, 2}, {0, 0, 0}, 255, 255, 0, 100, 0);
auto delta = target.v - local_view;
auto new_angles = delta.to_angle();
new_angles = clamp_angle(new_angles);
math::Vector new_movement = fix_movement_for_new_angles({cmd->forwardmove, cmd->sidemove, 0}, cmd->viewangles, new_angles);
auto new_movement = fix_movement_for_new_angles({cmd->forwardmove, cmd->sidemove, 0}, cmd->viewangles, new_angles);
if (local_weapon->can_shoot(local_player->tick_base())) {
cmd->viewangles = new_angles;
@ -373,8 +375,8 @@ void create_move(sdk::UserCmd *cmd) {
cmd->forwardmove = new_movement.x;
cmd->sidemove = new_movement.y;
logging::msg("cmd_delta = %d", cmd_delta);
cmd->tick_count -= cmd_delta;
logging::msg("cmd_delta = %d", target.cmd_delta);
cmd->tick_count -= target.cmd_delta;
}
if (doghook_aimbot_silent == false) IFace<Engine>()->set_view_angles(new_angles);

View File

@ -61,7 +61,7 @@ void paint() {
show_nodes(profiler::find_root_node(), {0, 100, 0});
if (IFace<Engine>()->in_game() == false) return;
if (!IFace<Engine>()->in_game()) return;
auto local_player = Player::local();
@ -71,10 +71,11 @@ void paint() {
auto enemy_color = draw::Color(hex::dword(doghook_esp_enemy.to_string()));
for (auto e : IFace<EntList>()->get_range()) {
if (e->is_valid() == false) continue;
if (!e->is_valid()) continue;
if (e->dormant()) continue;
if (auto player = e->to_player()) {
if (!player->alive()) continue;
auto player_color = player->team() == local_player_team ? friendly_color : enemy_color;
@ -111,7 +112,7 @@ void paint() {
draw::world_to_screen(point_list[0], min);
max = min;
bool visible = true;
auto visible = true;
for (u32 i = 1; i < 8; i++) {
math::Vector new_point;
draw::world_to_screen(point_list[i], new_point);

View File

@ -2,8 +2,11 @@
#include "lagexploit.hh"
#include <sdk/class_id.hh>
#include <sdk/convar.hh>
#include <sdk/netvar.hh>
#include <sdk/player.hh>
#include <sdk/weapon.hh>
#include <utils/profiler.hh>
using namespace sdk;
@ -11,15 +14,19 @@ using namespace sdk;
static Convar<bool> doghook_lagexploit_active = Convar<bool>{"doghook_lagexploit_active", false, nullptr};
static Convar<int> doghook_lagexploit_ticks = Convar<int>{"doghook_lagexploit_ticks", 3, 0, INT_MAX, nullptr};
static Convar<bool> doghook_lagexploit_backup = Convar<bool>{"doghook_lagexploit_backup", false, nullptr};
static Convar<int> doghook_lagexploit_key = Convar<int>{"doghook_lagexploit_key", 0, 0, KEY_COUNT, nullptr};
static Convar<bool> doghook_lagexploit_shoot = Convar<bool>{"doghook_lagexploit_shoot", false, nullptr};
static Convar<bool> doghook_lagexploit_doom = Convar<bool>{"doghook_lagexploit_doom", false, nullptr};
namespace lagexploit {
void create_move(UserCmd *cmd) { // TODO: add more usefull shit
profiler_profile_function(); // WHY??
auto local = IFace<EntList>()->entity(IFace<Engine>()->local_player_index())->to_player();
auto last_wep_id = 0;
auto was_holding = false;
if (!local) // should never happen but never say never
return;
void create_move(UserCmd *cmd) {
profiler_profile_function();
auto local = Player::local();
if (!local->alive())
return;
@ -27,7 +34,66 @@ void create_move(UserCmd *cmd) { // TODO: add more usefull shit
if (!doghook_lagexploit_active)
return;
// TODO: add actual button
IFace<Engine>()->net_channel_info()->m_nOutSequenceNr() += doghook_lagexploit_ticks * (doghook_lagexploit_backup ? 90 : 66);
auto numsequnce = 0;
auto is_holding_wep = (cmd->buttons & IN_ATTACK) || (cmd->buttons & IN_ATTACK2);
auto local_weapon = local->active_weapon();
auto current_wep_id = local_weapon->client_class()->class_id;
if (doghook_lagexploit_doom) {
// doesnt really work as intended
static auto i = 0;
auto server_time = IFace<Globals>()->ticks_to_time(local->tick_base());
static auto next_attack = 0.0f;
if (!next_attack || i == 0 || current_wep_id != last_wep_id) {
next_attack = local_weapon->next_primary_attack();
//i = 0; // when wep changes
}
if (server_time - next_attack > 30.0f) next_attack = server_time - 30.0f;
if (server_time - next_attack > 0.0f && (cmd->buttons & IN_ATTACK) || (cmd->buttons & IN_ATTACK2)) {
if (i == 0)
i = (int)server_time - (int)next_attack;
if (i > 75) i = 75;
numsequnce = i * 66;
if (local_weapon->clip1() == 0) {
// crash on rocket launcher
cmd->buttons &= ~IN_ATTACK;
cmd->buttons &= ~IN_ATTACK2;
}
}
if (i != 0) i -= 1;
} else if (doghook_lagexploit_shoot) {
// works every fucking time
auto can_shoot = local_weapon->can_shoot(local->tick_base());
if (current_wep_id == class_id::CTFSniperRifle) {
is_holding_wep = cmd->buttons & IN_ATTACK;
if ((can_shoot && is_holding_wep && !was_holding) || (was_holding && !is_holding_wep))
numsequnce = 1 * 90;
was_holding = is_holding_wep;
} else {
if ((can_shoot && is_holding_wep && !was_holding && current_wep_id != sdk::class_id::CTFFlareGun) ||
(was_holding && !is_holding_wep)) {
numsequnce = 1 * 90;
} else if (can_shoot && is_holding_wep && !was_holding && current_wep_id == sdk::class_id::CTFFlareGun) {
numsequnce = 2 * 90;
}
was_holding = (cmd->buttons & IN_ATTACK) || (cmd->buttons & IN_ATTACK2);
}
}
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
numsequnce = doghook_lagexploit_ticks * (doghook_lagexploit_backup ? 90 : 66);
IFace<Engine>()->net_channel_info()->m_nOutSequenceNr() += numsequnce;
};
}; // namespace lagexploit

18
src/modules/misc.cc Normal file
View File

@ -0,0 +1,18 @@
#include <precompiled.hh>
#include "misc.hh"
#include <sdk/convar.hh>
#include <sdk/interface.hh>
#include <sdk/sdk.hh>
using namespace sdk;
namespace misc {
sdk::ConvarWrapper sv_cheats{"sv_cheats"};
void init_all() {
sv_cheats.set_flags(0);
}
} // namespace misc

5
src/modules/misc.hh Normal file
View File

@ -0,0 +1,5 @@
#pragma once
namespace misc {
void init_all();
}

View File

@ -43,6 +43,7 @@ public:
ID(CTFPlayer, 246);
ID(CTFRevolver, 285);
ID(CTFSniperRifle, 306);
ID(CTFFlareGun, 208);
#undef ID

View File

@ -1,5 +1,7 @@
#include "precompiled.hh"
#include <mutex>
#include "convar.hh"
#include "interface.hh"
@ -272,7 +274,6 @@ public:
};
ConCommandBase *ConCommandBase::head;
} // namespace sdk
const ConvarBase *ConvarBase::head = nullptr;
@ -300,9 +301,19 @@ void ConvarBase::tf_convar_changed(sdk::IConVar *iconvar, const char *old_string
}
}
ConvarBase::ConvarBase(const char *name, ConvarType type, const ConvarBase *parent) : parent(parent), t(type), next(head), init_complete(false) {
std::mutex *constructor_mutex;
ConvarBase::ConvarBase(const char *name, ConvarType type, const ConvarBase *parent) : init_complete(false) {
if (constructor_mutex == nullptr) constructor_mutex = new std::mutex;
std::lock_guard<std::mutex> lock{*constructor_mutex};
this->next = head;
head = this;
this->parent = parent;
this->t = type;
#if doghook_platform_windows()
strcpy_s(internal_name, name);
#elif doghook_platform_linux()
@ -327,6 +338,8 @@ ConvarBase::~ConvarBase() {
}
void ConvarBase::init_all() {
std::lock_guard<std::mutex> lock{*constructor_mutex};
assert(IFace<sdk::Cvar>());
sdk::can_init_convars_at_construction_time = true;
@ -350,3 +363,61 @@ void ConvarBase::init_all() {
c->tf_convar->set_value(c->to_string());
}
}
// TODO: this needs a better method of keeping in sync with the
// Interface declaration in doghook.cc
Cvar *get_or_init_cvar() {
if (IFace<Cvar>().get() == nullptr) {
IFace<Cvar>().set_from_interface("vstdlib", "VEngineCvar");
}
return IFace<Cvar>().get();
}
ConvarWrapper::ConvarWrapper(const char *name) {
assert(name);
base = get_or_init_cvar()->find_var(name);
assert(base);
}
int ConvarWrapper::get_int() {
return base->value_int;
}
float ConvarWrapper::get_float() {
return base->value_float;
}
bool ConvarWrapper::get_bool() {
return !!base->value_int;
}
const char *ConvarWrapper::get_string() {
return base->value_string;
}
u32 ConvarWrapper::flags() {
return base->flags;
}
void ConvarWrapper::set_flags(u32 new_flags) {
base->flags = new_flags;
}
const char *ConvarWrapper::defualt_value() {
return base->default_value;
}
void ConvarWrapper::set_value(int v) {
base->set_value(v);
}
void ConvarWrapper::set_value(float v) {
base->set_value(v);
}
void ConvarWrapper::set_value(const char *v) {
base->set_value(v);
}
} // namespace sdk

View File

@ -18,7 +18,6 @@
namespace sdk {
class ConCommandBase;
class IConVar;
} // namespace sdk
enum class ConvarType {
Bool,
@ -312,3 +311,27 @@ public:
return value;
}
};
// This wraps access to a games convar by name (similar to convarref)
class ConvarWrapper {
ConCommandBase *base;
public:
ConvarWrapper(const char *name);
int get_int();
float get_float();
bool get_bool();
const char *get_string();
u32 flags();
void set_flags(u32 new_flags);
const char *defualt_value();
void set_value(int v);
void set_value(float v);
void set_value(const char *v);
};
} // namespace sdk

164
src/sdk/inputcodes.hh Normal file
View File

@ -0,0 +1,164 @@
#pragma once
namespace sdk {
enum ButtonCode {
BUTTON_CODE_INVALID = -1,
BUTTON_CODE_NONE = 0,
KEY_FIRST = 0,
KEY_NONE = KEY_FIRST,
KEY_0,
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_A,
KEY_B,
KEY_C,
KEY_D,
KEY_E,
KEY_F,
KEY_G,
KEY_H,
KEY_I,
KEY_J,
KEY_K,
KEY_L,
KEY_M,
KEY_N,
KEY_O,
KEY_P,
KEY_Q,
KEY_R,
KEY_S,
KEY_T,
KEY_U,
KEY_V,
KEY_W,
KEY_X,
KEY_Y,
KEY_Z,
KEY_PAD_0,
KEY_PAD_1,
KEY_PAD_2,
KEY_PAD_3,
KEY_PAD_4,
KEY_PAD_5,
KEY_PAD_6,
KEY_PAD_7,
KEY_PAD_8,
KEY_PAD_9,
KEY_PAD_DIVIDE,
KEY_PAD_MULTIPLY,
KEY_PAD_MINUS,
KEY_PAD_PLUS,
KEY_PAD_ENTER,
KEY_PAD_DECIMAL,
KEY_LBRACKET,
KEY_RBRACKET,
KEY_SEMICOLON,
KEY_APOSTROPHE,
KEY_BACKQUOTE,
KEY_COMMA,
KEY_PERIOD,
KEY_SLASH,
KEY_BACKSLASH,
KEY_MINUS,
KEY_EQUAL,
KEY_ENTER,
KEY_SPACE,
KEY_BACKSPACE,
KEY_TAB,
KEY_CAPSLOCK,
KEY_NUMLOCK,
KEY_ESCAPE,
KEY_SCROLLLOCK,
KEY_INSERT,
KEY_DELETE,
KEY_HOME,
KEY_END,
KEY_PAGEUP,
KEY_PAGEDOWN,
KEY_BREAK,
KEY_LSHIFT,
KEY_RSHIFT,
KEY_LALT,
KEY_RALT,
KEY_LCONTROL,
KEY_RCONTROL,
KEY_LWIN,
KEY_RWIN,
KEY_APP,
KEY_UP,
KEY_LEFT,
KEY_DOWN,
KEY_RIGHT,
KEY_F1,
KEY_F2,
KEY_F3,
KEY_F4,
KEY_F5,
KEY_F6,
KEY_F7,
KEY_F8,
KEY_F9,
KEY_F10,
KEY_F11,
KEY_F12,
KEY_CAPSLOCKTOGGLE,
KEY_NUMLOCKTOGGLE,
KEY_SCROLLLOCKTOGGLE,
KEY_LAST = KEY_SCROLLLOCKTOGGLE,
KEY_COUNT = KEY_LAST - KEY_FIRST + 1,
// Mouse
MOUSE_FIRST = KEY_LAST + 1,
MOUSE_LEFT = MOUSE_FIRST,
MOUSE_RIGHT,
MOUSE_MIDDLE,
MOUSE_4,
MOUSE_5,
MOUSE_WHEEL_UP, // A fake button which is 'pressed' and 'released' when the wheel is moved up
MOUSE_WHEEL_DOWN, // A fake button which is 'pressed' and 'released' when the wheel is moved down
MOUSE_LAST = MOUSE_WHEEL_DOWN,
MOUSE_COUNT = MOUSE_LAST - MOUSE_FIRST + 1,
};
enum player_controls {
IN_ATTACK = (1 << 0),
IN_JUMP = (1 << 1),
IN_DUCK = (1 << 2),
IN_FORWARD = (1 << 3),
IN_BACK = (1 << 4),
IN_USE = (1 << 5),
IN_CANCEL = (1 << 6),
IN_LEFT = (1 << 7),
IN_RIGHT = (1 << 8),
IN_MOVELEFT = (1 << 9),
IN_MOVERIGHT = (1 << 10),
IN_ATTACK2 = (1 << 11),
IN_RUN = (1 << 12),
IN_RELOAD = (1 << 13),
IN_ALT1 = (1 << 14),
IN_ALT2 = (1 << 15),
IN_SCORE = (1 << 16), // Used by client.dll for when scoreboard is held down
IN_SPEED = (1 << 17), // Player is holding the speed key
IN_WALK = (1 << 18), // Player holding walk key
IN_ZOOM = (1 << 19), // Zoom key for HUD zoom
IN_WEAPON1 = (1 << 20), // weapon defines these bits
IN_WEAPON2 = (1 << 21), // weapon defines these bits
IN_BULLRUSH = (1 << 22),
};
// TODO: mb add enumerated key array
// ToDo: make seperate convar type for keys
} // namespace sdk

View File

@ -41,7 +41,7 @@
#define doghook_platform_debug() false
#if defined(_DEBUG) || defined(DEBUG)
#if defined(_DEBUG) || defined(DEBUG) && !defined(NDEBUG)
#undef doghook_platform_debug
#define doghook_platform_debug() true
#endif

View File

@ -8,6 +8,7 @@
#include "interface.hh"
#include "signature.hh"
#include "inputcodes.hh"
#include "trace.hh"
namespace sdk {
@ -284,6 +285,14 @@ public:
void unregister_command(ConCommandBase *command) {
return_virtual_func(unregister_command, 7, 7, 7, 0, command);
}
ConCommandBase *root_node() {
return_virtual_func(root_node, 16, 16, 16, 0);
}
ConCommandBase *find_var(const char *name) {
return_virtual_func(find_var, 12, 12, 12, 0, name);
}
};
class Trace {
@ -485,4 +494,19 @@ class EngineVgui {
public:
};
class InputSystem {
public:
bool is_button_down(ButtonCode code) {
return_virtual_func(is_button_down, 11, 11, 11, 0, code);
}
//just to be sure, but above is all we really need since i have all keys enumerated
const char *button_code_to_string(ButtonCode code) {
return_virtual_func(button_code_to_string, 27, 27, 27, 0, code);
}
ButtonCode string_to_button_code(const char *string) {
return_virtual_func(string_to_button_code, 29, 29, 29, 0, string);
}
};
} // namespace sdk

View File

@ -21,6 +21,11 @@ bool Weapon::can_shoot(u32 tickbase) {
return tickbase * IFace<Globals>()->interval_per_tick > next_primary_attack();
}
auto clip1 = Netvar("DT_BaseCombatWeapon", "LocalWeaponData", "m_iClip1");
u32 Weapon::clip1() {
return ::clip1.get<u32>(this);
}
Entity *Weapon::owner() {
// TODO:
return nullptr;

View File

@ -10,6 +10,8 @@ public:
float next_primary_attack();
float next_secondary_attack();
u32 clip1();
Entity *owner();
};
} // namespace sdk

View File

@ -117,14 +117,17 @@ void init() {
nodes.push_back(root_node);
}
#ifdef _MSC_VER
__declspec(noinline)
#endif
void enter_node(u32 id, const char *name) {
if (!enable_profiling) return;
if (current_nodes.size() < 1) {
// we clearly arent inited yet...
current_nodes.push(find_root_node());
}
if (!enable_profiling) return;
// TODO: maybe we should try and search for nodes that we know are children first??
auto current_node = current_nodes.top();
auto node = find_node(id);
@ -159,11 +162,14 @@ void enter_node(u32 id, const char *name) {
}
}
#ifdef _MSC_VER
__declspec(noinline)
#endif
void exit_node() {
if (current_nodes.size() < 1) return; // we clearly arent inited yet...
if (!enable_profiling) return;
if (current_nodes.size() < 1) return; // we clearly arent inited yet...
auto node = current_nodes.top();
if (node->recursions == 1) {

View File

@ -61,12 +61,17 @@ ProfileNode *find_root_node();
class ProfileScope {
public:
ProfileScope(const char *name) {
if (!profiling_enabled()) return;
// assume that each name is unique
u32 id = reinterpret_cast<u32>(name);
enter_node(id, name);
}
~ProfileScope() { exit_node(); };
~ProfileScope() {
if (!profiling_enabled()) return;
exit_node();
}
};
//#ifdef _DEBUG