Skip to content

Commit 6443f05

Browse files
Synchronize changes from 1.6 master branch [ci skip]
7ebcf59 Simplify ACL request refresh detection (improves #4409) (#4483) 8d41e19 Resolve Event Context Loss in Nested Event Cacnellation (#4529)
2 parents df57fc2 + 7ebcf59 commit 6443f05

File tree

8 files changed

+123
-99
lines changed

8 files changed

+123
-99
lines changed

Server/mods/deathmatch/logic/CElement.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -438,10 +438,11 @@ bool CElement::CallEvent(const char* szName, const CLuaArguments& Arguments, CPl
438438
if (!g_pGame->GetDebugHookManager()->OnPreEvent(szName, Arguments, this, pCaller))
439439
return false;
440440

441-
CEvents* pEvents = g_pGame->GetEvents();
441+
CEvents* pEvents = g_pGame->GetEvents();
442+
CEventContext eventContext;
442443

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

446447
// Call the event on our parents/us first
447448
CallParentEvent(szName, Arguments, this, pCaller);
@@ -450,12 +451,12 @@ bool CElement::CallEvent(const char* szName, const CLuaArguments& Arguments, CPl
450451
CallEventNoParent(szName, Arguments, this, pCaller);
451452

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

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

457458
// Return whether our event was cancelled or not
458-
return (!pEvents->WasEventCancelled());
459+
return !eventContext.IsCancelled();
459460
}
460461

461462
bool CElement::DeleteEvent(CLuaMain* pLuaMain, const char* szName, const CLuaFunctionRef& iLuaFunction)

Server/mods/deathmatch/logic/CEvents.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,38 +123,68 @@ void CEvents::RemoveAllEvents()
123123
m_EventHashMap.clear();
124124
}
125125

126-
void CEvents::PreEventPulse()
126+
void CEvents::PreEventPulse(CEventContext* pContext)
127127
{
128+
assert(pContext);
129+
128130
m_CancelledList.push_back(m_bEventCancelled);
131+
m_ContextStack.push_back(pContext);
132+
133+
pContext->Reset();
134+
129135
m_bEventCancelled = false;
130136
m_bWasEventCancelled = false;
131137
m_strLastError = "";
132138
}
133139

134-
void CEvents::PostEventPulse()
140+
void CEvents::PostEventPulse(CEventContext* pContext)
135141
{
136-
m_bWasEventCancelled = m_bEventCancelled;
142+
assert(pContext);
143+
assert(!m_ContextStack.empty());
144+
assert(m_ContextStack.back() == pContext);
145+
146+
m_bWasEventCancelled = pContext->IsCancelled();
137147
m_bEventCancelled = m_CancelledList.back() ? true : false;
138148
m_CancelledList.pop_back();
149+
m_ContextStack.pop_back();
139150
}
140151

141152
void CEvents::CancelEvent(bool bCancelled)
142153
{
143-
m_bEventCancelled = bCancelled;
154+
CancelEvent(bCancelled, nullptr);
144155
}
145156

146157
void CEvents::CancelEvent(bool bCancelled, const char* szReason)
147158
{
159+
// ALWAYS set the old global variable for backward compatibility
148160
m_bEventCancelled = bCancelled;
149-
m_strLastError = SStringX(szReason);
161+
162+
// Also update context if it exists
163+
if (!m_ContextStack.empty())
164+
{
165+
CEventContext* pCurrentContext = m_ContextStack.back();
166+
if (bCancelled)
167+
pCurrentContext->Cancel(szReason);
168+
else
169+
pCurrentContext->Reset();
170+
}
171+
172+
if (szReason)
173+
m_strLastError = szReason;
150174
}
151175

152176
bool CEvents::WasEventCancelled()
153177
{
154-
return m_bWasEventCancelled;
178+
if (!m_ContextStack.empty())
179+
return m_ContextStack.back()->IsCancelled();
180+
181+
return m_bEventCancelled || m_bWasEventCancelled;
155182
}
156183

157184
const char* CEvents::GetLastError()
158185
{
186+
if (!m_ContextStack.empty())
187+
return m_ContextStack.back()->GetCancelReason().c_str();
188+
159189
return m_strLastError;
160190
}

Server/mods/deathmatch/logic/CEvents.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <string>
1515
#include <list>
1616
#include <vector>
17+
#include "CEventContext.h"
1718

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

43-
void PreEventPulse();
44-
void PostEventPulse();
44+
void PreEventPulse(CEventContext* pContext);
45+
void PostEventPulse(CEventContext* pContext);
4546

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

5455
CFastHashMap<SString, SEvent*> m_EventHashMap;
5556

56-
std::vector<int> m_CancelledList;
57-
bool m_bEventCancelled;
58-
bool m_bWasEventCancelled;
57+
std::vector<int> m_CancelledList;
58+
bool m_bEventCancelled;
59+
bool m_bWasEventCancelled;
60+
SString m_strLastError;
5961

60-
SString m_strLastError;
62+
std::vector<CEventContext*> m_ContextStack;
6163
};

Server/mods/deathmatch/logic/CResource.AclRequest.cpp

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -369,51 +369,3 @@ bool CResource::FindAclRequest(SAclRequest& result)
369369

370370
return pAclRight->GetAttributeValue("pending") != "";
371371
}
372-
373-
std::string CResource::CalculateACLRequestFingerprint()
374-
{
375-
std::string strPath;
376-
if (!GetFilePath("meta.xml", strPath))
377-
return {};
378-
379-
std::unique_ptr<CXMLFile> metaFile(g_pServerInterface->GetXML()->CreateXML(strPath.c_str()));
380-
if (!metaFile || !metaFile->Parse())
381-
{
382-
return {};
383-
}
384-
385-
CXMLNode* root = metaFile->GetRootNode();
386-
if (!root)
387-
{
388-
return {};
389-
}
390-
391-
std::ostringstream fingerprint;
392-
CXMLNode* nodeAclRequest = root->FindSubNode("aclrequest", 0);
393-
394-
if (nodeAclRequest)
395-
{
396-
for (std::uint8_t uiIndex = 0; true; uiIndex++)
397-
{
398-
CXMLNode* nodeRight = nodeAclRequest->FindSubNode("right", uiIndex);
399-
if (!nodeRight)
400-
break;
401-
402-
std::string strName = nodeRight->GetAttributeValue("name");
403-
std::string strAccess = nodeRight->GetAttributeValue("access");
404-
405-
if (uiIndex > 0)
406-
fingerprint << ";";
407-
408-
fingerprint << strName << ":" << strAccess;
409-
}
410-
}
411-
412-
return fingerprint.str();
413-
}
414-
415-
bool CResource::HasACLRequestsChanged()
416-
{
417-
std::string strCurrentFingerprint = CalculateACLRequestFingerprint();
418-
return strCurrentFingerprint != m_strACLRequestFingerprint;
419-
}

Server/mods/deathmatch/logic/CResource.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ bool CResource::Load()
196196
else
197197
RemoveAutoPermissions();
198198

199-
m_strACLRequestFingerprint = CalculateACLRequestFingerprint();
200-
201199
// Find any map sync option
202200
m_bSyncMapElementData = true;
203201
m_bSyncMapElementDataDefined = false;
@@ -353,7 +351,6 @@ bool CResource::Unload()
353351
m_strResourceZip = "";
354352
m_strResourceCachePath = "";
355353
m_strResourceDirectoryPath = "";
356-
m_strACLRequestFingerprint.clear();
357354
m_eState = EResourceState::None;
358355

359356
return true;
@@ -405,8 +402,6 @@ CResource::~CResource()
405402

406403
void CResource::TidyUp()
407404
{
408-
RemoveAutoPermissions();
409-
410405
// Close the zipfile stuff
411406
if (m_zipfile)
412407
unzClose(m_zipfile);
@@ -700,11 +695,6 @@ bool CResource::HasResourceChanged()
700695
return true;
701696
}
702697

703-
if (HasACLRequestsChanged())
704-
{
705-
return true;
706-
}
707-
708698
return false;
709699
}
710700

@@ -1222,9 +1212,6 @@ bool CResource::Stop(bool bManualStop)
12221212
// Clear the list of players where this resource is running
12231213
std::exchange(m_isRunningForPlayer, {});
12241214

1225-
// Remove ACL permissions when stopping
1226-
RemoveAutoPermissions();
1227-
12281215
OnResourceStateChange("loaded");
12291216
m_eState = EResourceState::Loaded;
12301217
return true;

Server/mods/deathmatch/logic/CResource.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ enum class EResourceState : unsigned char
136136
// It's a process-like environment for scripts, maps, images and other files.
137137
class CResource : public EHS
138138
{
139+
friend class CResourceManager; // Allow CResourceManager access to protected members
139140
using KeyValueMap = CFastHashMap<SString, SString>;
140141

141142
public:
@@ -349,9 +350,6 @@ class CResource : public EHS
349350
void CommitAclRequest(const SAclRequest& request);
350351
bool FindAclRequest(SAclRequest& result);
351352

352-
std::string CalculateACLRequestFingerprint();
353-
bool HasACLRequestsChanged();
354-
355353
private:
356354
bool CheckState(); // if the resource has no Dependents, stop it, if it has, start it. returns true if the resource is started.
357355
bool ReadIncludedResources(CXMLNode* pRoot);
@@ -453,7 +451,6 @@ class CResource : public EHS
453451
SString m_strMinServerReason;
454452

455453
CChecksum m_metaChecksum; // Checksum of meta.xml last time this was loaded, generated in GenerateChecksums()
456-
std::string m_strACLRequestFingerprint;
457454

458455
uint m_uiFunctionRightCacheRevision = 0;
459456
CFastHashMap<lua_CFunction, bool> m_FunctionRightCacheMap;

Server/mods/deathmatch/logic/CResourceManager.cpp

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -172,27 +172,42 @@ bool CResourceManager::Refresh(bool bRefreshAll, const SString strJustThisResour
172172
if (!strJustThisResource.empty() && strJustThisResource != info.strName)
173173
continue;
174174

175-
if (!info.bPathIssue)
176-
{
177-
CResource* pResource = GetResource(info.strName);
175+
if (info.bPathIssue)
176+
continue;
178177

179-
if (bRefreshAll || !pResource || !pResource->CheckIfStartable())
180-
{
181-
if (g_pServerInterface->IsRequestingExit())
182-
return false;
178+
auto* pResource = GetResource(info.strName);
183179

184-
// Add the resource
185-
Load(!info.bIsDir, info.strAbsPath, info.strName);
186-
}
187-
else if (bRefreshAll && pResource && pResource->HasResourceChanged())
188-
{
189-
if (g_pServerInterface->IsRequestingExit())
190-
return false;
191-
192-
// Resource exists but has changed, reload it
193-
Load(!info.bIsDir, info.strAbsPath, info.strName);
194-
}
180+
if (bRefreshAll || !pResource || !pResource->CheckIfStartable())
181+
{
182+
if (g_pServerInterface->IsRequestingExit())
183+
return false;
184+
185+
// Add the resource
186+
Load(!info.bIsDir, info.strAbsPath, info.strName);
187+
continue;
195188
}
189+
190+
if (!pResource)
191+
continue;
192+
193+
// For existing resources, refresh ACL permissions without full reload
194+
std::string strPath;
195+
if (!pResource->GetFilePath("meta.xml", strPath))
196+
continue;
197+
198+
std::unique_ptr<CXMLFile> pMetaFile(g_pServerInterface->GetXML()->CreateXML(strPath.c_str()));
199+
if (!pMetaFile || !pMetaFile->Parse())
200+
continue;
201+
202+
CXMLNode* pRoot = pMetaFile->GetRootNode();
203+
if (!pRoot)
204+
continue;
205+
206+
CXMLNode* pNodeAclRequest = pRoot->FindSubNode("aclrequest", 0);
207+
if (pNodeAclRequest)
208+
pResource->RefreshAutoPermissions(pNodeAclRequest);
209+
else
210+
pResource->RemoveAutoPermissions();
196211
}
197212

198213
marker.Set("AddNew");
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: Shared/mods/deathmatch/logic/CEventContext.h
6+
* PURPOSE: Per-event context for event dispatch and cancellation
7+
*
8+
* Multi Theft Auto is available from https://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#pragma once
13+
14+
#include <string>
15+
16+
class CEventContext
17+
{
18+
public:
19+
CEventContext() noexcept : m_isCancelled(false) {}
20+
21+
void Cancel(const char* reason = nullptr) noexcept
22+
{
23+
m_isCancelled = true;
24+
if (reason)
25+
m_cancelReason = reason;
26+
}
27+
28+
bool IsCancelled() const noexcept { return m_isCancelled; }
29+
const std::string& GetCancelReason() const noexcept { return m_cancelReason; }
30+
31+
void Reset() noexcept
32+
{
33+
m_isCancelled = false;
34+
m_cancelReason.clear();
35+
}
36+
37+
private:
38+
bool m_isCancelled;
39+
std::string m_cancelReason;
40+
};

0 commit comments

Comments
 (0)