Entity damage callbacks

This commit is contained in:
Federico Cecchetto 2021-09-17 00:12:54 +02:00
parent ce3cb82c48
commit e5a0630ad3
6 changed files with 106 additions and 6 deletions

View File

@ -17,6 +17,9 @@ namespace notifies
namespace namespace
{ {
utils::hook::detour scr_entity_damage_hook;
std::vector<sol::protected_function> entity_damage_callbacks;
char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END
unsigned int local_id_to_entity(unsigned int local_id) unsigned int local_id_to_entity(unsigned int local_id)
@ -99,11 +102,96 @@ namespace notifies
a.mov(r14, (char*)empty_function); a.mov(r14, (char*)empty_function);
a.jmp(end); a.jmp(end);
} }
sol::lua_value convert_entity(lua_State* state, const game::gentity_s* ent)
{
if (!ent)
{
return {};
}
const auto player = scripting::call("getentbynum", {ent->s.entityNum});
return scripting::lua::convert(state, player);
}
std::string get_weapon_name(unsigned int weapon, bool isAlternate)
{
char output[1024] = {0};
game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024);
return output;
}
sol::lua_value convert_vector(lua_State* state, const float* vec)
{
if (!vec)
{
return {};
}
const auto _vec = scripting::vector(vec);
return scripting::lua::convert(state, _vec);
}
std::string convert_mod(const int meansOfDeath)
{
const auto value = reinterpret_cast<game::scr_string_t**>(game::base_address + 0xBF49B0)[meansOfDeath];
const auto string = game::SL_ConvertToString(*value);
return string;
}
void scr_entity_damage_stub(game::gentity_s* self, game::gentity_s* inflictor, game::gentity_s* attacker, const float* vDir, const float* vPoint,
int damage, int dflags, const unsigned int hitLoc, const unsigned int weapon, bool isAlternate, unsigned int a11, const int meansOfDeath, unsigned int a13, unsigned int a14)
{
{
const std::string _hitLoc = reinterpret_cast<const char**>(game::base_address + 0xBF4AA0)[hitLoc];
const auto _mod = convert_mod(meansOfDeath);
const auto _weapon = get_weapon_name(weapon, isAlternate);
for (const auto& callback : entity_damage_callbacks)
{
const auto state = callback.lua_state();
const auto _self = convert_entity(state, self);
const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker);
const auto _vDir = convert_vector(state, vDir);
const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _vDir, _hitLoc);
scripting::lua::handle_error(result);
if (result.valid())
{
const auto value = result.get<sol::object>();
if (value.is<int>())
{
damage = value.as<int>();
}
}
}
if (damage == 0)
{
return;
}
}
scr_entity_damage_hook.invoke<void>(self, inflictor, attacker, vDir, vPoint, damage, dflags, hitLoc, weapon, isAlternate, a11, meansOfDeath, a13, a14);
}
}
void add_entity_damage_callback(const sol::protected_function& callback)
{
entity_damage_callbacks.push_back(callback);
} }
void clear_callbacks() void clear_callbacks()
{ {
vm_execute_hooks.clear(); vm_execute_hooks.clear();
entity_damage_callbacks.clear();
} }
class component final : public component_interface class component final : public component_interface
@ -112,6 +200,8 @@ namespace notifies
void post_unpack() override void post_unpack() override
{ {
utils::hook::jump(game::base_address + 0x5C90A5, utils::hook::assemble(vm_execute_stub), true); utils::hook::jump(game::base_address + 0x5C90A5, utils::hook::assemble(vm_execute_stub), true);
scr_entity_damage_hook.create(game::base_address + 0x4BD2E0, scr_entity_damage_stub);
} }
}; };
} }

View File

@ -5,5 +5,6 @@ namespace notifies
extern std::unordered_map<const char*, sol::protected_function> vm_execute_hooks; extern std::unordered_map<const char*, sol::protected_function> vm_execute_hooks;
extern bool hook_enabled; extern bool hook_enabled;
void add_entity_damage_callback(const sol::protected_function&);
void clear_callbacks(); void clear_callbacks();
} }

View File

@ -1015,7 +1015,7 @@ namespace scripting
{"setmotionblurzoomscale", 0x81BA}, {"setmotionblurzoomscale", 0x81BA},
{"viewkick", 0x81BB}, {"viewkick", 0x81BB},
{"sub_4ecfe0", 0x81BC}, {"sub_4ecfe0", 0x81BC},
{"getnodenumber", 0x81BD}, {"getentitynumber", 0x81BD},
{"sub_4ebbc0", 0x81BE}, {"sub_4ebbc0", 0x81BE},
{"enablegrenadetouchdamage", 0x81BF}, {"enablegrenadetouchdamage", 0x81BF},
{"disablegrenadetouchdamage", 0x81C0}, {"disablegrenadetouchdamage", 0x81C0},
@ -1706,7 +1706,7 @@ namespace scripting
{"removecomworld", 0x8587}, {"removecomworld", 0x8587},
{"sub_4b8f80", 0x8588}, {"sub_4b8f80", 0x8588},
{"sub_4b9270", 0x8589}, {"sub_4b9270", 0x8589},
{"getentitynumber", 0x858C}, {"sub_4eab30", 0x858C},
{"cleartargetentity", 0x858D}, {"cleartargetentity", 0x858D},
{"nullsub_359", 0x8590}, {"nullsub_359", 0x8590},
{"sub_4b3f60", 0x8595}, {"sub_4b3f60", 0x8595},

View File

@ -466,6 +466,11 @@ namespace scripting::lua
return result; return result;
}; };
game_type["onentitydamage"] = [](const game&, const sol::protected_function& callback)
{
notifies::add_entity_damage_callback(callback);
};
} }
} }

View File

@ -58,7 +58,8 @@ namespace game
struct gentity_s struct gentity_s
{ {
char __pad0[0x1C]; EntityState s;
char __pad0[0x1B];
vec3_t origin; vec3_t origin;
char __pad1[0xF0]; char __pad1[0xF0];
gclient_s* client; gclient_s* client;

View File

@ -12,6 +12,9 @@ namespace game
WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x5C29B0}; WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x5C29B0};
WEAK symbol<void(unsigned int id)> RemoveRefToObject{0x5C28A0}; WEAK symbol<void(unsigned int id)> RemoveRefToObject{0x5C28A0};
WEAK symbol<void(unsigned int weapon, bool isAlternate,
char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0x6A0800};
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x59A050}; WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x59A050};
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x37F450}; WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x37F450};