Merge branch 'feature/scripting' of https://github.com/XLabsProject/s1x-client into feature/scripting

This commit is contained in:
quaK 2021-03-22 19:35:20 +02:00
commit c4e2eec77a
6 changed files with 169 additions and 4 deletions

View File

@ -4,13 +4,136 @@
#include "game/scripting/entity.hpp"
#include "game/scripting/execution.hpp"
#include "game/scripting/lua/value_conversion.hpp"
#include "game/scripting/lua/error.hpp"
#include <utils/hook.hpp>
#include "logfile.hpp"
namespace logfile
{
namespace
{
utils::hook::detour scr_player_killed_hook;
utils::hook::detour scr_player_damage_hook;
std::vector<sol::protected_function> player_killed_callbacks;
std::vector<sol::protected_function> player_damage_callbacks;
sol::lua_value convert_entity(lua_State* state, const game::mp::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**>(0x1409B5360)[meansOfDeath];
const auto string = game::SL_ConvertToString(*value);
return string;
}
void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, game::mp::gentity_s* attacker, int damage,
int meansOfDeath, const unsigned int weapon, bool isAlternate, const float* vDir, const unsigned int hitLoc, int psTimeOffset, int deathAnimDuration)
{
const std::string _hitLoc = reinterpret_cast<const char**>(0x1409B5400)[hitLoc];
const auto _mod = convert_mod(meansOfDeath);
const auto _weapon = get_weapon_name(weapon, isAlternate);
for (const auto& callback : player_killed_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, psTimeOffset, deathAnimDuration);
scripting::lua::handle_error(result);
if (result.valid() && result.get_type() == sol::type::number)
{
damage = result.get<int>();
}
}
if (damage == 0)
{
return;
}
scr_player_killed_hook.invoke<void>(self, inflictor, attacker, damage, meansOfDeath, weapon, isAlternate, vDir, hitLoc, psTimeOffset, deathAnimDuration);
}
void scr_player_damage_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, game::mp::gentity_s* attacker, int damage, int dflags,
int meansOfDeath, const unsigned int weapon, bool isAlternate, const float* vPoint, const float* vDir, const unsigned int hitLoc, int timeOffset)
{
const std::string _hitLoc = reinterpret_cast<const char**>(0x1409B5400)[hitLoc];
const auto _mod = convert_mod(meansOfDeath);
const auto _weapon = get_weapon_name(weapon, isAlternate);
for (const auto& callback : player_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 _vPoint = convert_vector(state, vPoint);
const auto _vDir = convert_vector(state, vDir);
const auto result = callback(_self, _inflictor, _attacker, damage, dflags, _mod, _weapon, _vPoint, _vDir, _hitLoc);
scripting::lua::handle_error(result);
if (result.valid() && result.get_type() == sol::type::number)
{
damage = result.get<int>();
}
}
if (damage == 0)
{
return;
}
scr_player_damage_hook.invoke<void>(self, inflictor, attacker, damage, dflags, meansOfDeath, weapon, isAlternate, vPoint, vDir, hitLoc, timeOffset);
}
bool evaluate_say(char* text, game::mp::gentity_s* ent)
{
auto hidden = false;
@ -39,6 +162,22 @@ namespace logfile
}
}
void add_player_damage_callback(const sol::protected_function& callback)
{
player_damage_callbacks.push_back(callback);
}
void add_player_killed_callback(const sol::protected_function& callback)
{
player_killed_callbacks.push_back(callback);
}
void clear_callbacks()
{
player_damage_callbacks.clear();
player_killed_callbacks.clear();
}
const auto say_stub = utils::hook::assemble([](utils::hook::assembler& a)
{
const auto hidden = a.newLabel();
@ -73,6 +212,9 @@ namespace logfile
}
utils::hook::jump(0x1402E99CC, say_stub, true);
scr_player_damage_hook.create(0x140332150, scr_player_damage_stub);
scr_player_killed_hook.create(0x1403323D0, scr_player_killed_stub);
}
};
}

View File

@ -0,0 +1,8 @@
#pragma once
namespace logfile
{
void add_player_damage_callback(const sol::protected_function& callback);
void add_player_killed_callback(const sol::protected_function& callback);
void clear_callbacks();
}

View File

@ -7,6 +7,7 @@
#include "../functions.hpp"
#include "../../../component/command.hpp"
#include "../../../component/logfile.hpp"
#include <utils/string.hpp>
@ -248,6 +249,16 @@ namespace scripting::lua
{
command::execute(command, false);
};
game_type["onplayerdamage"] = [](const game&, const sol::protected_function& callback)
{
logfile::add_player_damage_callback(callback);
};
game_type["onplayerkilled"] = [](const game&, const sol::protected_function& callback)
{
logfile::add_player_killed_callback(callback);
};
}
}

View File

@ -3,6 +3,7 @@
#include "context.hpp"
#include "../execution.hpp"
#include "../../../component/logfile.hpp"
#include <utils/io.hpp>
@ -52,6 +53,7 @@ namespace scripting::lua::engine
void stop()
{
logfile::clear_callbacks();
get_scripts().clear();
}

View File

@ -106,7 +106,7 @@ namespace scripting::lua
table[sol::metatable_key] = metatable;
return { state, table };
return {state, table};
}
}

View File

@ -13,6 +13,8 @@ namespace game
WEAK symbol<void(void*, void*)> AimAssist_AddToTargetList{0, 0x140001730};
WEAK symbol<void(unsigned int weapon, bool isAlternate, char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0x0, 0x140165580};
WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{0x1402F7570, 0x1403CE480};
WEAK symbol<void()> Com_Frame_Try_Block_Function{0x1402F7E10, 0x1403CEF30};
WEAK symbol<CodPlayMode()> Com_GetCurrentCoDPlayMode{0, 0x1404C9690};
@ -45,9 +47,9 @@ namespace game
WEAK symbol<void(XAssetType type, void (__cdecl* func)(XAssetHeader, void*), void* inData, bool includeOverride)>
DB_EnumXAssets_FastFile{0x14017D7C0, 0x14026EC10};
WEAK symbol<void(XAssetType type, void(__cdecl* func)(game::XAssetHeader, void*), const void* inData, bool includeOverride)>
DB_EnumXAssets_Internal{ 0x14017D830, 0x14026EC80 };
DB_EnumXAssets_Internal{0x14017D830, 0x14026EC80};
WEAK symbol<game::XAssetEntry(game::XAssetType type, const char* name)>
DB_FindXAssetEntry{ 0x14017D830, 0x14026F020 };
DB_FindXAssetEntry{0x14017D830, 0x14026F020};
WEAK symbol<const char* (const XAsset* asset)> DB_GetXAssetName{0x140151C00, 0x140240DD0};
WEAK symbol<int(XAssetType type)> DB_GetXAssetTypeSize{0x140151C20, 0x140240DF0};
WEAK symbol<void(XZoneInfo* zoneInfo, unsigned int zoneCount, DBSyncMode syncMode)> DB_LoadXAssets{
@ -219,7 +221,7 @@ namespace game
WEAK symbol<jmp_buf> g_script_error{0x14A1917B0, 0x1487FA0C0};
WEAK symbol<scr_classStruct_t> g_classMap{0x14080A840, 0x1409BE1B0};
WEAK symbol<scrVarGlob_t> scr_VarGlob{ 0x149B1D680, 0x148185F80 };
WEAK symbol<scrVarGlob_t> scr_VarGlob{0x149B1D680, 0x148185F80};
WEAK symbol<scrVmPub_t> scr_VmPub{0x14A1938C0, 0x1487FC1C0};
WEAK symbol<const char*> command_whitelist{0x140808EF0, 0x1409B8DC0};