Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions Server/mods/deathmatch/logic/CElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,10 +438,11 @@ bool CElement::CallEvent(const char* szName, const CLuaArguments& Arguments, CPl
if (!g_pGame->GetDebugHookManager()->OnPreEvent(szName, Arguments, this, pCaller))
return false;

CEvents* pEvents = g_pGame->GetEvents();
CEvents* pEvents = g_pGame->GetEvents();
CEventContext eventContext;

// Make sure our event-manager knows we're about to call an event
pEvents->PreEventPulse();
pEvents->PreEventPulse(&eventContext);

// Call the event on our parents/us first
CallParentEvent(szName, Arguments, this, pCaller);
Expand All @@ -450,15 +451,13 @@ bool CElement::CallEvent(const char* szName, const CLuaArguments& Arguments, CPl
CallEventNoParent(szName, Arguments, this, pCaller);

// Tell the event manager that we're done calling the event
pEvents->PostEventPulse();
pEvents->PostEventPulse(&eventContext);

g_pGame->GetDebugHookManager()->OnPostEvent(szName, Arguments, this, pCaller);

// Return whether our event was cancelled or not
return (!pEvents->WasEventCancelled());
}

bool CElement::DeleteEvent(CLuaMain* pLuaMain, const char* szName, const CLuaFunctionRef& iLuaFunction)
return !eventContext.IsCancelled();
}bool CElement::DeleteEvent(CLuaMain* pLuaMain, const char* szName, const CLuaFunctionRef& iLuaFunction)
{
return m_pEventManager->Delete(pLuaMain, szName, iLuaFunction);
}
Expand Down
42 changes: 36 additions & 6 deletions Server/mods/deathmatch/logic/CEvents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,38 +123,68 @@ void CEvents::RemoveAllEvents()
m_EventHashMap.clear();
}

void CEvents::PreEventPulse()
void CEvents::PreEventPulse(CEventContext* pContext)
{
assert(pContext);

m_CancelledList.push_back(m_bEventCancelled);
m_ContextStack.push_back(pContext);

pContext->Reset();

m_bEventCancelled = false;
m_bWasEventCancelled = false;
m_strLastError = "";
}

void CEvents::PostEventPulse()
void CEvents::PostEventPulse(CEventContext* pContext)
{
m_bWasEventCancelled = m_bEventCancelled;
assert(pContext);
assert(!m_ContextStack.empty());
assert(m_ContextStack.back() == pContext);

m_bWasEventCancelled = pContext->IsCancelled();
m_bEventCancelled = m_CancelledList.back() ? true : false;
m_CancelledList.pop_back();
m_ContextStack.pop_back();
}

void CEvents::CancelEvent(bool bCancelled)
{
m_bEventCancelled = bCancelled;
CancelEvent(bCancelled, nullptr);
}

void CEvents::CancelEvent(bool bCancelled, const char* szReason)
{
// ALWAYS set the old global variable for backward compatibility
m_bEventCancelled = bCancelled;
m_strLastError = SStringX(szReason);

// Also update context if it exists
if (!m_ContextStack.empty())
{
CEventContext* pCurrentContext = m_ContextStack.back();
if (bCancelled)
pCurrentContext->Cancel(szReason);
else
pCurrentContext->Reset();
}

if (szReason)
m_strLastError = szReason;
}

bool CEvents::WasEventCancelled()
{
return m_bWasEventCancelled;
if (!m_ContextStack.empty())
return m_ContextStack.back()->IsCancelled();

return m_bEventCancelled || m_bWasEventCancelled;
}

const char* CEvents::GetLastError()
{
if (!m_ContextStack.empty())
return m_ContextStack.back()->GetCancelReason().c_str();

return m_strLastError;
}
14 changes: 8 additions & 6 deletions Server/mods/deathmatch/logic/CEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <string>
#include <list>
#include <vector>
#include "CEventContext.h"

struct SEvent
{
Expand All @@ -40,8 +41,8 @@ class CEvents
CFastHashMap<SString, SEvent*>::const_iterator IterBegin() { return m_EventHashMap.begin(); };
CFastHashMap<SString, SEvent*>::const_iterator IterEnd() { return m_EventHashMap.end(); };

void PreEventPulse();
void PostEventPulse();
void PreEventPulse(CEventContext* pContext);
void PostEventPulse(CEventContext* pContext);

void CancelEvent(bool bCancelled = true);
void CancelEvent(bool bCancelled, const char* szReason);
Expand All @@ -53,9 +54,10 @@ class CEvents

CFastHashMap<SString, SEvent*> m_EventHashMap;

std::vector<int> m_CancelledList;
bool m_bEventCancelled;
bool m_bWasEventCancelled;
std::vector<int> m_CancelledList;
bool m_bEventCancelled;
bool m_bWasEventCancelled;
SString m_strLastError;

SString m_strLastError;
std::vector<CEventContext*> m_ContextStack;
};
40 changes: 40 additions & 0 deletions Shared/mods/deathmatch/logic/CEventContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: Shared/mods/deathmatch/logic/CEventContext.h
* PURPOSE: Per-event context for event dispatch and cancellation
*
* Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/

#pragma once

#include <string>

class CEventContext
{
public:
CEventContext() noexcept : m_isCancelled(false) {}

void Cancel(const char* reason = nullptr) noexcept
{
m_isCancelled = true;
if (reason)
m_cancelReason = reason;
}

bool IsCancelled() const noexcept { return m_isCancelled; }
const std::string& GetCancelReason() const noexcept { return m_cancelReason; }

void Reset() noexcept
{
m_isCancelled = false;
m_cancelReason.clear();
}

private:
bool m_isCancelled;
std::string m_cancelReason;
};