Page 1 of 1

SourceMod extensions in Source.Python?

Posted: Mon Oct 15, 2018 4:45 am
by VinciT
There's a really nasty bug in HL2DM. If an NPC hits whatever the player is holding in their gravity gun, the server will crash. I've found a SourceMod extension that fixes this issue, and I'm wondering if there's a way to do same thing in Source.Python?

Syntax: Select all

#include "extension.h"
#include "CDetour/detours.h"

/**
* Globals
*/
ggfix g_Interface;
SMEXT_LINK(&g_Interface);

CGlobalVars *g_pGlobals;

void *g_pEntityFactoryDictAddr = NULL;
IGameConfig *g_pGameConf = NULL;
IServerGameEnts *gameents = NULL;

CDetour *UTIL_GetLocalPlayer_Detour = NULL;

DETOUR_DECL_MEMBER0(UTIL_GetLocalPlayer, CBaseEntity *)
{
for(int i=1;i<=g_pGlobals->maxClients;i++)
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex(i);
if(pPlayer) {
return pPlayer;
}
}
return NULL;
}

class BaseAccessor : public IConCommandBaseAccessor
{
public:
bool RegisterConCommandBase(ConCommandBase *pCommandBase)
{
return META_REGCVAR(pCommandBase);
}
} s_BaseAccessor;


bool ggfix::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
#if SOURCE_ENGINE >= SE_ORANGEBOX
g_pCVar = icvar;
ConVar_Register(0, &s_BaseAccessor);
#else
ConCommandBaseMgr::OneTimeInit(&s_BaseAccessor);
#endif

char conf_error[255] = "";
if(!gameconfs->LoadGameConfigFile("ggfix", &g_pGameConf, conf_error, sizeof(conf_error)))
{
if(conf_error[0])
snprintf(error, maxlength, "Could not read ggfix.txt: %s", conf_error);

return false;
}

CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);

UTIL_GetLocalPlayer_Detour = DETOUR_CREATE_MEMBER(UTIL_GetLocalPlayer, "UTIL_GetLocalPlayer");

if (UTIL_GetLocalPlayer_Detour != NULL)
{
UTIL_GetLocalPlayer_Detour->EnableDetour();
}
else
{
return false;
}

return true;
}

void ggfix::SDK_OnAllLoaded()
{

}

void ggfix::SDK_OnUnload()
{
if (UTIL_GetLocalPlayer_Detour != NULL)
{
UTIL_GetLocalPlayer_Detour->Destroy();
UTIL_GetLocalPlayer_Detour = NULL;
}

gameconfs->CloseGameConfigFile(g_pGameConf);
}

bool ggfix::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
{
GET_V_IFACE_CURRENT(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS);

g_pGlobals = ismm->GetCGlobals();

return true;
}

It seems like the engine thinks that the player is in single player (UTIL_GetLocalPlayer), and the only way to fix this is to force the engine to use UTIL_PlayerByIndex instead. How would I even begin to do this in SP?

Re: SourceMod extensions in Source.Python?

Posted: Mon Oct 15, 2018 5:52 pm
by Ayuto
Try this:

Syntax: Select all

import core
import memory

from memory import Convention
from memory import DataType
from memory import NULL

from memory.hooks import PreHook

from entities.helpers import pointer_from_edict
from players import PlayerGenerator


server = memory.find_binary('server')

if core.PLATFORM == 'windows':
identifier = b'\xA1\x2A\x2A\x2A\x2A\x8B\x2A\x2A\x83\x2A\x01\x7E\x03\x33\xC0\xC3'
else:
identifier = '_Z19UTIL_GetLocalPlayerv'

UTIL_GetLocalPlayer = server[identifier].make_function(
Convention.CDECL,
[],
DataType.POINTER)

@PreHook(UTIL_GetLocalPlayer)
def pre_get_local_player(args):
for edict in PlayerGenerator():
try:
return pointer_from_edict(edict)
except ValueError:
pass

return NULL

Re: SourceMod extensions in Source.Python?

Posted: Mon Oct 15, 2018 6:31 pm
by VinciT
Holy hell, it works!
You had a small typo here (single equal sign instead of double):

Syntax: Select all

if core.PLATFORM == 'windows':

That extension was the only reason I had to use SM with SP, thanks a lot Ayuto!

Re: SourceMod extensions in Source.Python?

Posted: Mon Oct 15, 2018 6:46 pm
by Ayuto
I have fixed the typo, thanks! I'm glad it's working.