Closed incognico closed 3 years ago
idk if AngelScript exposes registration of pfnCvarValue
and pfnCvarValue2
to modders or not, but there are two server-to-client requests :
#define svc_sendcvarvalue 57
#define svc_sendcvarvalue2 58
Servers could send svc_sendcvarvalue/svc_sendcvarvalue2
request to client to query for value of specified cvar
NetworkMessage message( MSG_ONE, 57, pPlayer.edict() );//57=svc_sendcvarvalue
message.WriteString("r_light_dynamic");
message.End();
NetworkMessage message( MSG_ONE, 58, pPlayer.edict() );//58=svc_sendcvarvalue2
message.WriteLong(1234);//Request ID
message.WriteString("r_light_dynamic");
message.End();
and wait for result in:
void SV_ParseCvarValue(client_t *cl)
{
char *value;
value = MSG_ReadString();
if (gNewDLLFunctions.pfnCvarValue)
gNewDLLFunctions.pfnCvarValue(cl->edict, value);
Con_DPrintf("Cvar query response: name:%s, value:%s\n", cl->name, value);
}
void SV_ParseCvarValue2(client_t *cl)
{
char *value;
char cvarName[255];
int requestID;
requestID = MSG_ReadLong();
Q_strncpy(cvarName, MSG_ReadString(), sizeof(cvarName));
cvarName[sizeof(cvarName) - 1] = 0;
value = MSG_ReadString();
if (gNewDLLFunctions.pfnCvarValue2)
gNewDLLFunctions.pfnCvarValue2(cl->edict, requestID, cvarName, value);
Con_DPrintf("Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, cvarName, value);
}
typedef struct{
void (*pfnOnFreeEntPrivateData)(edict_t *pEnt);
void (*pfnGameShutdown)(void);
int (*pfnShouldCollide)( edict_t *pentTouched, edict_t *pentOther );
void (*pfnCvarValue)( const edict_t *pEnt, const char *value );
void (*pfnCvarValue2)( const edict_t *pEnt, int requestID, const char *cvarName, const char *value );
} NEW_DLL_FUNCTIONS;
It's definitely okay to intercept or handle those server.dll interfaces with metamod-p.
A new plugin called CommunicationDemo.dll
has been added into the default plugin list.
//#define svc_director 51
NetworkMessage message( MSG_ONE, 51, pPlayer.edict() );//58=svc_sendcvarvalue2
message.WriteLong(100);//MetaHookSv
message.WriteLong(1);//Query plugin list
message.End();
plugins will be reported with server command mh_reportplugin index apiver "name" "version"
CClientCommand g_HelloWorld("mh_reportplugin", "ReportPluginInfo", @ReportPluginInfo);
void ReportPluginInfo(const CCommand@ pArgs)
{
}
I'm testing with:
void PluginInit() {
g_Module.ScriptInfo.SetAuthor("incognico");
g_Module.ScriptInfo.SetContactInfo("https://discord.gg/qfZxWAd");
g_Hooks.RegisterHook(Hooks::Player::ClientPutInServer, @ClientPutInServer);
}
CClientCommand g_ReportMetahookPlugin("mh_reportplugin", "ReportPluginInfo", @ReportPluginInfo);
HookReturnCode ClientPutInServer( CBasePlayer@ plr ) {
g_Scheduler.SetTimeout("RequestPlugins", 6.66f, EHandle(plr));
return HOOK_CONTINUE;
}
void ReportPluginInfo(const CCommand@ args) {
CBasePlayer@ plr = g_ConCommandSystem.GetCurrentPlayer();
g_EngineFuncs.ServerPrint( "[MetaHookPlugins " + plr.pev.netname + "] #" + args[1] + " :: apiver: " + args[2] + " :: name: " + args[3] + " :: ver: " + args[4] + "\n" );
}
void RequestPlugins( EHandle eplr ) {
if (!eplr) return;
CBasePlayer@ plr = cast<CBasePlayer@>(eplr.GetEntity());
NetworkMessage message( MSG_ONE, NetworkMessages::NetworkMessageType(51), plr.edict() ); // 58 = svc_sendcvarvalue2
message.WriteLong(100); //MetaHookSv
message.WriteLong(1); //Query plugin list
message.End();
}
Using 58 / svc_sendcvarvalue2
results in svc_bad
with client disconnect - not working.
Using 51 / svc_director
results in other random errors with the client also disconnecting:
Seeing weird stuff like Host_Error: CL_Parse_Version: Server is protocol 2015367138 instead of 48
or Host_Error: DispatchUserMsg: User Msg PrtlUpdt/129 sent too much data (28714 bytes), 512 bytes max.
Those really look random.
From the client .mh_reportplugin
is working (manually).
Maybe those messages don't work in sven, or have other undocumented arguments? Could use something else like TE_STREAK_SPLASH with no-op args (0 count, 1337 speed) which do nothing but act as a secret message to metahook.
Would a simple detection work via a custom setinfo
? MH client could do setinfo _metahook <version>
, that should theoretically be possible to read from the server via KeyValueBuffer::GetValue()
. It won't report single plugins but it would be a way to detect MetaHook.
Would a simple detection work via a custom
setinfo
? MH client could dosetinfo _metahook <version>
, that should theoretically be possible to read from the server viaKeyValueBuffer::GetValue()
. It won't report single plugins but it would be a way to detect MetaHook.
setinfo has a limitation of 512 bytes (or 256?), and it leaves key there even when metahook is completed removed.
Maybe those messages don't work in sven, or have other undocumented arguments? Could use something else like TE_STREAK_SPLASH with no-op args (0 count, 1337 speed) which do nothing but act as a secret message to metahook.
svc_sendcvarvalue
and svc_sendcvarvalue2
are still there in Sven
This is my test result :
Test plugin : https://github.com/hzqst/metamod-fallguys/tree/main/querycvar Hook : https://github.com/hzqst/metamod-fallguys/blob/94e77ebb3e3c12cadafb834b2c2d908b00e012d4/querycvar/dllapi.cpp#L119
The svc_director seems to be removed from SvEngine
svc_hltv too
You can register your own usermsg :
HookReturnCode ClientPutInServer(CBasePlayer@ pPlayer)
{
//svc_newusermsg = 39
NetworkMessage message( MSG_ONE, NetworkMessages::NetworkMessageType(39), pPlayer.edict() );
message.WriteByte(146);//64 ~ 145 = SelAmmo ~ VModelPos, all of them are reserved or used by Sven Co-op
message.WriteByte(255);//255 = variable length
message.WriteLong(0x6174654D);//`ateM`
message.WriteLong(0x6B6F6F48);//`kooH`
message.WriteLong(0);
message.WriteLong(0);
message.End();
return HOOK_CONTINUE;
}
Players connected without usermsg MetaHook
registered will do nothing more than reporting UserMsg: No pfn MetaHook 146
to the console (only when developer
is non-zero).
I want to be able to detect clients who use metahooksv from the server side via AngelScript. This would allow me to enable several dlight stuff for metahooksv players without destroying the performance for players who use the vanilla client for example.
Maybe it could add a custom networked Userinfo key https://github.com/dreamstalker/rehlds/wiki/Userinfo-keys
_metahook true
or something, that way it could work.Additionally, because this could be also used to ban metahooksv players, a client config variable to hide the userinfo key could be added, so a player can prefer not to send this variable to be stealth. But it should be sent by default, otherwise it would be useless for my intentional use.