[Chat] Add say notify

This commit is contained in:
Diavolo 2022-05-16 14:02:15 +02:00
parent cf281ed7e5
commit b4b7c45624
No known key found for this signature in database
GPG Key ID: FA77F074E98D98A5
8 changed files with 170 additions and 32 deletions

View File

@ -34,9 +34,12 @@ namespace game
Scr_AddEntityNum_t Scr_AddEntityNum;
Scr_Notify_t Scr_Notify;
Scr_NotifyLevel_t Scr_NotifyLevel;
Sys_ShowConsole_t Sys_ShowConsole;
Sys_Error_t Sys_Error;
VM_Notify_t VM_Notify;
BG_NetDataChecksum_t BG_NetDataChecksum;
@ -92,6 +95,7 @@ namespace game
char** scrMemTreePub;
char* scrMemTreeGlob;
scrVarPub_t* scr_VarPub;
scrVmPub_t* scr_VmPub;
scr_call_t* scr_instanceFunctions;
@ -255,7 +259,7 @@ namespace game
(SELECT_VALUE(0x539550, 0x5BDCC0, 0x0))(dvarName);
}
__declspec(naked) const dvar_t* Dvar_RegisterVariant(const char* dvarName, unsigned char type,
__declspec(naked) const dvar_t* dvar_register_variant_dedicated(const char* dvar_name, unsigned char type,
unsigned __int16 flags, DvarValue value, DvarLimits domain, const char* description)
{
static DWORD func = 0x531F70;
@ -307,10 +311,23 @@ namespace game
dvar_value.value = value;
return Dvar_RegisterVariant(dvarName, dvar_type::DVAR_TYPE_FLOAT,
return dvar_register_variant_dedicated(dvarName, dvar_type::DVAR_TYPE_FLOAT,
flags, dvar_value, domain, description);
}
void IncInParam()
{
Scr_ClearOutParams();
if (scr_VmPub->top == scr_VmPub->maxStack)
{
Sys_Error("Internal script stack overflow");
}
scr_VmPub->top++;
scr_VmPub->inparamcount++;
}
const float* Scr_AllocVector(const float* v)
{
const auto mem = static_cast<DWORD*>(MT_Alloc(16, 2));
@ -396,16 +413,16 @@ namespace game
{
if (is_mp())
{
return scr_notify_id_multiplayer(id, stringValue, paramcount);
scr_notify_id_multiplayer(id, stringValue, paramcount);
}
else if (is_sp())
{
return scr_notify_id_singleplayer(id, stringValue, paramcount);
scr_notify_id_singleplayer(id, stringValue, paramcount);
}
else
{
return reinterpret_cast<void(*)(unsigned int, unsigned int, unsigned int)>(0x4EFAA0)(
id, stringValue, paramcount);
reinterpret_cast<void(*)(unsigned int, unsigned int, unsigned int)>(0x4EFAA0)
(id, stringValue, paramcount);
}
}
@ -437,7 +454,7 @@ namespace game
}
}
__declspec(naked) void scr_add_string_dedi(const char* value)
__declspec(naked) void scr_add_string_dedicated(const char* value)
{
static DWORD func = 0x4F1010;
@ -453,15 +470,23 @@ namespace game
{
if (is_dedi())
{
scr_add_string_dedi(value);
scr_add_string_dedicated(value);
}
else if (is_mp())
else
{
reinterpret_cast<void(*)(const char*)>
(0x56AC00)(value);
(SELECT_VALUE(0x4A5600, 0x56AC00, 0x0))(value);
}
}
void Scr_AddInt(int value)
{
IncInParam();
scr_VmPub->top->type = SCRIPT_INTEGER;
scr_VmPub->top->u.intValue = value;
}
const char* SL_ConvertToString(const unsigned int stringValue)
{
if (!stringValue) return nullptr;
@ -472,7 +497,7 @@ namespace game
unsigned int SL_GetString(const char* str, const unsigned int user)
{
return SL_GetStringOfSize(str, user, strlen(str) + 1, 7);
return SL_GetStringOfSize(str, user, std::strlen(str) + 1, 7);
}
__declspec(naked) void sv_send_client_game_state_mp(mp::client_t* /*client*/)
@ -544,7 +569,7 @@ namespace game
}
}
__declspec(naked) void client_command_dedi(int client_num)
__declspec(naked) void client_command_dedicated(int client_num)
{
static DWORD func = 0x47EA40;
@ -560,7 +585,7 @@ namespace game
{
if (is_dedi())
{
client_command_dedi(clientNum);
client_command_dedicated(clientNum);
}
else if (is_mp())
{
@ -578,7 +603,7 @@ namespace game
addr->type = type;
}
__declspec(naked) void cbuf_add_text_dedi(LocalClientNum_t local_client_num, const char* text)
__declspec(naked) void cbuf_add_text_dedicated(LocalClientNum_t local_client_num, const char* text)
{
static DWORD func = 0x4CB5D0;
@ -596,7 +621,7 @@ namespace game
{
if (is_dedi())
{
cbuf_add_text_dedi(localClientNum, text);
cbuf_add_text_dedicated(localClientNum, text);
}
else
{
@ -605,7 +630,7 @@ namespace game
}
}
__declspec(naked) void teleport_player_dedi(gentity_s* player, float* origin, float* angles)
__declspec(naked) void teleport_player_dedicated(gentity_s* player, float* origin, float* angles)
{
static DWORD func = 0x48B840;
@ -624,7 +649,7 @@ namespace game
{
if (is_dedi())
{
teleport_player_dedi(player, origin, angles);
teleport_player_dedicated(player, origin, angles);
}
else if (is_mp())
{
@ -708,9 +733,12 @@ namespace game
native::Scr_AddEntityNum = native::Scr_AddEntityNum_t(SELECT_VALUE(0x0, 0x56ABC0, 0x4EA2F0));
native::Scr_Notify = native::Scr_Notify_t(SELECT_VALUE(0x4895B0, 0x52B190, 0x0));
native::Scr_NotifyLevel = native::Scr_NotifyLevel_t(SELECT_VALUE(0x445E10, 0x56B6B0, 0x0));
native::Sys_ShowConsole = native::Sys_ShowConsole_t(SELECT_VALUE(0x470AF0, 0x5CF590, 0));
native::Sys_Error = native::Sys_Error_t(SELECT_VALUE(0x490D90, 0x5CC3B0, 0x539590));
native::VM_Notify = native::VM_Notify_t(SELECT_VALUE(0x610200, 0x569720, 0x4EF450));
native::BG_NetDataChecksum = native::BG_NetDataChecksum_t(SELECT_VALUE(0x0, 0x41BB20, 0x0));
@ -774,6 +802,7 @@ namespace game
native::scrMemTreePub = reinterpret_cast<char**>(SELECT_VALUE(0x196FB00, 0x1E32000, 0x1C152A4));
native::scrMemTreeGlob = reinterpret_cast<char*>(SELECT_VALUE(0x186DA00, 0x1D6FF00, 0x1C16600));
native::scr_VarPub = reinterpret_cast<native::scrVarPub_t*>(SELECT_VALUE(0x0, 0x208E188, 0x1CD8720));
native::scr_VmPub = reinterpret_cast<native::scrVmPub_t*>(SELECT_VALUE(0x1BF2580, 0x20B4A80, 0x1F5B080));
native::scr_instanceFunctions = reinterpret_cast<native::scr_call_t*>(SELECT_VALUE(0x184CDB0, 0x1D4F258,

View File

@ -55,12 +55,18 @@ namespace game
typedef void (*Scr_AddEntityNum_t)(int entnum, unsigned int classnum);
extern Scr_AddEntityNum_t Scr_AddEntityNum;
typedef void (*Scr_Notify_t)(gentity_s* ent, unsigned __int16 stringValue, unsigned int paramcount);
typedef void (*Scr_Notify_t)(gentity_s* ent, unsigned int stringValue, unsigned int paramcount);
extern Scr_Notify_t Scr_Notify;
typedef void (*Scr_NotifyLevel_t)(unsigned int stringValue, unsigned int paramcount);
extern Scr_NotifyLevel_t Scr_NotifyLevel;
typedef void (*Sys_ShowConsole_t)();
extern Sys_ShowConsole_t Sys_ShowConsole;
typedef void (*Sys_Error_t)(const char* error, ...);
extern Sys_Error_t Sys_Error;
typedef void (*VM_Notify_t)(unsigned int notifyListOwnerId, unsigned int stringValue, VariableValue* top);
extern VM_Notify_t VM_Notify;
@ -145,6 +151,7 @@ namespace game
extern char** scrMemTreePub;
extern char* scrMemTreeGlob;
extern scrVarPub_t* scr_VarPub;
extern scrVmPub_t* scr_VmPub;
extern scr_call_t* scr_instanceFunctions;
@ -201,7 +208,6 @@ namespace game
void* MT_Alloc(int numBytes, int type);
dvar_t* Dvar_FindVar(const char* dvarName);
const dvar_t* Dvar_RegisterVariant(const char* dvarName, unsigned char type, unsigned __int16 flags, DvarValue value, DvarLimits domain, const char* description);
const dvar_t* Dvar_RegisterFloat(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description);
const float* Scr_AllocVector(const float* v);
@ -211,6 +217,7 @@ namespace game
void Scr_NotifyId(unsigned int id, unsigned int stringValue, unsigned int paramcount);
int Scr_SetObjectField(unsigned int classnum, int entnum, int offset);
void Scr_AddString(const char* value);
void Scr_AddInt(int value);
const char* SL_ConvertToString(unsigned int stringValue);
unsigned int SL_GetString(const char* str, unsigned int user);

View File

@ -14,19 +14,19 @@ namespace game::scripting
const std::string string = native::SL_ConvertToString(value.u.stringValue);
return chaiscript::var(string);
}
else if (value.type == native::SCRIPT_FLOAT)
if (value.type == native::SCRIPT_FLOAT)
{
return chaiscript::var(value.u.floatValue);
}
else if (value.type == native::SCRIPT_INTEGER)
if (value.type == native::SCRIPT_INTEGER)
{
return chaiscript::var(value.u.intValue);
}
else if (value.type == native::SCRIPT_OBJECT)
if (value.type == native::SCRIPT_OBJECT)
{
return chaiscript::var(entity(this->context_, value.u.entityId));
}
else if (value.type == native::SCRIPT_VECTOR)
if (value.type == native::SCRIPT_VECTOR)
{
std::vector<chaiscript::Boxed_Value> values;
values.push_back(chaiscript::var(value.u.vectorValue[0]));
@ -46,7 +46,7 @@ namespace game::scripting
native::Scr_ClearOutParams();
}
if (native::scr_VmPub->top == native::scr_VmPub->maxstack)
if (native::scr_VmPub->top == native::scr_VmPub->maxStack)
{
throw std::runtime_error("Internal script stack overflow");
}
@ -75,6 +75,12 @@ namespace game::scripting
value_ptr->type = native::SCRIPT_INTEGER;
value_ptr->u.intValue = real_value;
}
else if (value.get_type_info() == typeid(unsigned int))
{
const auto real_value = this->context_->get_chai()->boxed_cast<unsigned int>(value);
value_ptr->type = native::SCRIPT_INTEGER;
value_ptr->u.intValue = static_cast<int>(real_value);
}
else if (value.get_type_info() == typeid(bool))
{
const auto real_value = this->context_->get_chai()->boxed_cast<bool>(value);

View File

@ -8,10 +8,10 @@ namespace game::scripting
this->in_param_count_ = native::scr_VmPub->inparamcount;
this->out_param_count_ = native::scr_VmPub->outparamcount;
this->top_ = native::scr_VmPub->top;
this->max_stack_ = native::scr_VmPub->maxstack;
this->max_stack_ = native::scr_VmPub->maxStack;
native::scr_VmPub->top = this->stack_;
native::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1];
native::scr_VmPub->maxStack = &this->stack_[ARRAYSIZE(this->stack_) - 1];
native::scr_VmPub->inparamcount = 0;
native::scr_VmPub->outparamcount = 0;
}
@ -22,6 +22,6 @@ namespace game::scripting
native::scr_VmPub->inparamcount = this->in_param_count_;
native::scr_VmPub->outparamcount = this->out_param_count_;
native::scr_VmPub->top = this->top_;
native::scr_VmPub->maxstack = this->max_stack_;
native::scr_VmPub->maxStack = this->max_stack_;
}
}

View File

@ -468,9 +468,11 @@ namespace game
SCRIPT_NONE = 0,
SCRIPT_OBJECT = 1,
SCRIPT_STRING = 2,
SCRIPT_ISTRING = 2,
SCRIPT_VECTOR = 4,
SCRIPT_FLOAT = 5,
SCRIPT_INTEGER = 6,
SCRIPT_CODEPOS = 7,
SCRIPT_END = 8,
// Custom
};
@ -521,7 +523,7 @@ namespace game
struct scrVmPub_t
{
unsigned int* localVars;
VariableValue* maxstack;
VariableValue* maxStack;
int function_count;
function_frame_t* function_frame;
VariableValue* top;
@ -537,6 +539,52 @@ namespace game
VariableValue stack[2048];
};
struct HunkUser
{
HunkUser* current;
HunkUser* next;
int maxSize;
int end;
int pos;
const char* name;
bool fixed;
int type;
unsigned char buf[1];
};
static_assert(sizeof(HunkUser) == 0x24);
struct scrVarPub_t
{
const char* fieldBuffer;
bool evaluate;
unsigned int time;
unsigned int timeArrayId;
unsigned int pauseArrayId;
unsigned int notifyArrayId;
unsigned int objectStackId;
unsigned int levelId;
unsigned int gameId;
unsigned int animId;
unsigned int freeEntList;
unsigned int tempVariable;
unsigned int numScriptValues[2];
bool bInited;
bool abort;
unsigned __int16 savecount;
unsigned __int16 savecountMark;
unsigned int entId;
unsigned int entFieldName;
unsigned int checksum;
HunkUser* programHunkUser;
HunkUser* canonicalStringHunkUser;
const char* programBuffer;
unsigned __int16 saveIdMap[36864];
unsigned __int16 saveIdMapRev[36864];
};
static_assert(sizeof(scrVarPub_t) == 0x24058);
struct scr_classStruct_t
{
unsigned __int16 id;
@ -974,7 +1022,7 @@ namespace game
int maxHealth;
int damage;
int count;
unsigned char __pad2[0xc8];
unsigned char __pad2[0xC8];
};
static_assert(sizeof(gentity_s) == 0x274);

48
src/module/chat.cpp Normal file
View File

@ -0,0 +1,48 @@
#include <std_include.hpp>
#include <loader/module_loader.hpp>
#include "game/game.hpp"
#include <utils/hook.hpp>
static void notify_on_say(game::native::gentity_s* ent, int mode, const char* message)
{
game::native::Scr_AddString(message + 1); // First character has nothing to do with actual message
game::native::Scr_AddInt(mode);
game::native::Scr_AddEntityNum(ent->s.number, 0);
game::native::Scr_NotifyLevel(game::native::SL_GetString("say", 0), 3);
}
static __declspec(naked) void g_say_stub()
{
__asm
{
pushad
push [esp + 0x20 + 0x108] // message
push [esp + 0x20 + 0x108] // mode
push ebp // ent
call notify_on_say
add esp, 0xC
popad
push 0x5C2940 // I_strncpyz
retn
}
}
class chat final : public module
{
public:
void post_load() override
{
if (game::is_mp())
{
utils::hook(0x502BAF, &g_say_stub, HOOK_CALL).install()->quick(); // I_strncpyz
}
}
};
REGISTER_MODULE(chat)

View File

@ -61,7 +61,7 @@ game::native::gentity_s* test_clients::sv_add_test_client()
game::native::SV_Cmd_EndTokenizedString();
// Find the bot
auto idx = 1;
int idx;
for (idx = 0; idx < *game::native::svs_clientCount; idx++)
{
if (game::native::mp::svs_clients[idx].header.state == game::native::clientState_t::CS_FREE)
@ -135,7 +135,7 @@ void test_clients::spawn(const int count)
void test_clients::scr_shutdown_system_mp_stub(unsigned char sys)
{
game::native::SV_DropAllBots();
reinterpret_cast<void (*)(unsigned char)>(0x569E30)(sys);
reinterpret_cast<void(*)(unsigned char)>(0x569E30)(sys);
}
__declspec(naked) void test_clients::reset_reliable_mp()