Skip to content

Commit

Permalink
Merge pull request #1 from fakuivan/pawn-think-hooks
Browse files Browse the repository at this point in the history
Adds a flag to RequestFrame to specify a Think hook
  • Loading branch information
fakuivan committed Sep 2, 2016
2 parents 015b9e9 + 7ed842b commit de5b93a
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 3 deletions.
5 changes: 5 additions & 0 deletions core/TimerSys.cpp
Expand Up @@ -242,6 +242,11 @@ void TimerSystem::GameFrame(bool simulating)
}
}

void TimerSystem::Think(bool FinalTick)
{
RunThinkHooks(FinalTick);
}

void TimerSystem::RunFrame()
{
ITimer *pTimer;
Expand Down
1 change: 1 addition & 0 deletions core/TimerSys.h
Expand Up @@ -83,6 +83,7 @@ class TimerSystem :
void RunFrame();
void RemoveMapChangeTimers();
void GameFrame(bool simulating);
void Think(bool FinalTick);
private:
List<ITimer *> m_SingleTimers;
List<ITimer *> m_LoopTimers;
Expand Down
55 changes: 55 additions & 0 deletions core/frame_hooks.cpp
Expand Up @@ -46,6 +46,10 @@ static float g_LastMenuTime = 0.0f;
static float g_LastAuthCheck = 0.0f;
bool g_PendingInternalPush = false;

static IMutex *think_mutex;
static Queue<FrameAction> *think_queue;
static Queue<FrameAction> *think_actions;

class FrameActionInit : public SMGlobalClass
{
public:
Expand All @@ -64,6 +68,24 @@ class FrameActionInit : public SMGlobalClass
}
} s_FrameActionInit;

class ThinkActionInit : public SMGlobalClass
{
public:
void OnSourceModAllInitialized()
{
think_queue = new Queue<FrameAction>();
think_actions = new Queue<FrameAction>();
think_mutex = g_pThreader->MakeMutex();
}

void OnSourceModShutdown()
{
delete think_queue;
delete think_actions;
think_mutex->DestroyThis();
}
} s_ThinkActionInit;

void AddFrameAction(const FrameAction & action)
{
frame_mutex->Lock();
Expand Down Expand Up @@ -120,3 +142,36 @@ void RunFrameHooks(bool simulating)
g_LastAuthCheck = curtime;
}
}



void AddThinkAction(const FrameAction & action)
{
think_mutex->Lock();
think_queue->push(action);
think_mutex->Unlock();
}

void RunThinkHooks(bool FinalTick)
{
/* It's okay if this check races. */
if (think_queue->size())
{
Queue<FrameAction> *temp;

/* Very quick lock to move queue/actions back and forth */
think_mutex->Lock();
temp = think_queue;
think_queue = think_actions;
think_actions = temp;
think_mutex->Unlock();

/* The server will now be adding to the other queue, so we can process events. */
while (!think_actions->empty())
{
FrameAction &item = think_actions->first();
think_actions->pop();
item.action(item.data);
}
}
}
3 changes: 3 additions & 0 deletions core/frame_hooks.h
Expand Up @@ -50,4 +50,7 @@ extern bool g_PendingInternalPush;
void AddFrameAction(const FrameAction & action);
void RunFrameHooks(bool simulating);

void AddThinkAction(const FrameAction & action);
void RunThinkHooks(bool FinalTick);

#endif //_INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
10 changes: 9 additions & 1 deletion core/logic/smn_functions.cpp
Expand Up @@ -645,7 +645,15 @@ static cell_t sm_AddFrameAction(IPluginContext *pContext, const cell_t *params)
pForward->AddFunction(pFunction);

SMFrameActionData *pData = new SMFrameActionData(Handle, pPlugin->GetMyHandle(), params[2]);
g_pSM->AddFrameAction(PawnFrameAction, pData);
if (params[0] >= 3) //for backwards compatibility
{
if (params[3]) { g_pSM->AddThinkAction(PawnFrameAction, pData); }
else { g_pSM->AddFrameAction(PawnFrameAction, pData); }
}
else
{
g_pSM->AddFrameAction(PawnFrameAction, pData);
}
return 1;
}

Expand Down
7 changes: 7 additions & 0 deletions core/sourcemod.cpp
Expand Up @@ -254,6 +254,7 @@ void SourceModBase::StartSourceMod(bool late)
{
SH_ADD_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
SH_ADD_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
SH_ADD_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::Think), false);

enginePatch = SH_GET_CALLCLASS(engine);
gamedllPatch = SH_GET_CALLCLASS(gamedll);
Expand Down Expand Up @@ -543,6 +544,7 @@ void SourceModBase::ShutdownServices()

SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
SH_REMOVE_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::Think), false);
SH_REMOVE_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(logicore.callbacks, &IProviderCallbacks::OnThink), false);
}

Expand Down Expand Up @@ -722,6 +724,11 @@ void SourceModBase::AddFrameAction(FRAMEACTION fn, void *data)
::AddFrameAction(FrameAction(fn, data));
}

void SourceModBase::AddThinkAction(FRAMEACTION fn, void *data)
{
::AddThinkAction(FrameAction(fn, data));
}

const char *SourceModBase::GetCoreConfigValue(const char *key)
{
return g_CoreConfig.GetCoreConfigValue(key);
Expand Down
1 change: 1 addition & 0 deletions core/sourcemod.h
Expand Up @@ -131,6 +131,7 @@ class SourceModBase :
size_t Format(char *buffer, size_t maxlength, const char *fmt, ...);
size_t FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap);
void AddFrameAction(FRAMEACTION fn, void *data);
void AddThinkAction(FRAMEACTION fn, void *data);
const char *GetCoreConfigValue(const char *key);
int GetPluginId();
int GetShApiVersion();
Expand Down
6 changes: 4 additions & 2 deletions plugins/include/functions.inc
Expand Up @@ -500,6 +500,8 @@ typedef RequestFrameCallback = function void (any data);
* Creates a single use Next Frame hook.
*
* @param Function Function to call on the next frame.
* @param data Value to be passed on the invocation of the Function.
* @param data Value to be passed on the invocation of the Function.
* @param HookThink Enable this flag if you want your function to be called
* even if the server is hibernating.
*/
native void RequestFrame(RequestFrameCallback Function, any data=0);
native void RequestFrame(RequestFrameCallback Function, any data=0, bool HookThink=false);
10 changes: 10 additions & 0 deletions public/ISourceMod.h
Expand Up @@ -288,6 +288,16 @@ namespace SourceMod
*/
virtual void AddFrameAction(FRAMEACTION fn, void *data) = 0;

/**
* @brief Adds an action to be executed on the next available think call.
*
* This function is thread safe.
*
* @param fn Function to execute.
* @param data Data to pass to function.
*/
virtual void AddThinkAction(FRAMEACTION fn, void *data) = 0;

/**
* @brief Retrieves a core.cfg configuration value.
*
Expand Down

0 comments on commit de5b93a

Please sign in to comment.