rewrite of user messages
authorBorja Ferrer <faluco@alliedmods.net>
Sun Mar 11 03:04:39 2007 +0000 (2007-03-11)
changeset 593507e74843261
parent 592 c2a2c38f1331
child 594 a9e75c1b8efa
rewrite of user messages
fixed possible iterator corruption
core/CellRecipientFilter.h
core/UserMessages.cpp
core/UserMessages.h
core/msvc8/sourcemod_mm.vcproj
core/smn_usermsgs.cpp
core/smn_usermsgs.h
core/sourcemod.cpp
     1.1 --- a/core/CellRecipientFilter.h	Sat Mar 10 21:26:04 2007 +0000
     1.2 +++ b/core/CellRecipientFilter.h	Sun Mar 11 03:04:39 2007 +0000
     1.3 @@ -21,7 +21,7 @@
     1.4  class CellRecipientFilter : public IRecipientFilter
     1.5  {
     1.6  public:
     1.7 -	CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0) {}
     1.8 +	CellRecipientFilter() : m_IsReliable(false), m_IsInitMessage(false), m_Size(0) {}
     1.9  	~CellRecipientFilter() {}
    1.10  public: //IRecipientFilter
    1.11  	bool IsReliable() const;
    1.12 @@ -29,32 +29,32 @@
    1.13  	int GetRecipientCount() const;
    1.14  	int GetRecipientIndex(int slot) const;
    1.15  public:
    1.16 -	void SetRecipientPtr(cell_t *ptr, size_t count);
    1.17 -	void SetReliable(bool isreliable);
    1.18 -	void SetInitMessage(bool isinitmsg);
    1.19 -	void ResetFilter();
    1.20 +	void Initialize(cell_t *ptr, size_t count);
    1.21 +	void SetToReliable(bool isreliable);
    1.22 +	void SetToInit(bool isinitmsg);
    1.23 +	void Reset();
    1.24  private:
    1.25 -	cell_t m_CellRecipients[255];
    1.26 -	bool m_Reliable;
    1.27 -	bool m_InitMessage;
    1.28 +	cell_t m_Players[255];
    1.29 +	bool m_IsReliable;
    1.30 +	bool m_IsInitMessage;
    1.31  	size_t m_Size;
    1.32  };
    1.33  
    1.34 -inline void CellRecipientFilter::ResetFilter()
    1.35 +inline void CellRecipientFilter::Reset()
    1.36  {
    1.37 -	m_Reliable = false;
    1.38 -	m_InitMessage = false;
    1.39 +	m_IsReliable = false;
    1.40 +	m_IsInitMessage = false;
    1.41  	m_Size = 0;
    1.42  }
    1.43  
    1.44  inline bool CellRecipientFilter::IsReliable() const
    1.45  {
    1.46 -	return m_Reliable;
    1.47 +	return m_IsReliable;
    1.48  }
    1.49  
    1.50  inline bool CellRecipientFilter::IsInitMessage() const
    1.51  {
    1.52 -	return m_InitMessage;
    1.53 +	return m_IsInitMessage;
    1.54  }
    1.55  
    1.56  inline int CellRecipientFilter::GetRecipientCount() const
    1.57 @@ -68,22 +68,22 @@
    1.58  	{
    1.59  		return -1;
    1.60  	}
    1.61 -	return static_cast<int>(m_CellRecipients[slot]);
    1.62 +	return static_cast<int>(m_Players[slot]);
    1.63  }
    1.64  
    1.65 -inline void CellRecipientFilter::SetInitMessage(bool isinitmsg)
    1.66 +inline void CellRecipientFilter::SetToInit(bool isinitmsg)
    1.67  {
    1.68 -	m_InitMessage = isinitmsg;
    1.69 +	m_IsInitMessage = isinitmsg;
    1.70  }
    1.71  
    1.72 -inline void CellRecipientFilter::SetReliable(bool isreliable)
    1.73 +inline void CellRecipientFilter::SetToReliable(bool isreliable)
    1.74  {
    1.75 -	m_Reliable = isreliable;
    1.76 +	m_IsReliable = isreliable;
    1.77  }
    1.78  
    1.79 -inline void CellRecipientFilter::SetRecipientPtr(cell_t *ptr, size_t count)
    1.80 +inline void CellRecipientFilter::Initialize(cell_t *ptr, size_t count)
    1.81  {
    1.82 -	memcpy(m_CellRecipients, ptr, count * sizeof(cell_t));
    1.83 +	memcpy(m_Players, ptr, count * sizeof(cell_t));
    1.84  	m_Size = count;
    1.85  }
    1.86  
     2.1 --- a/core/UserMessages.cpp	Sat Mar 10 21:26:04 2007 +0000
     2.2 +++ b/core/UserMessages.cpp	Sun Mar 11 03:04:39 2007 +0000
     2.3 @@ -88,8 +88,8 @@
     2.4  bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
     2.5  {
     2.6  	bf_write *buffer;
     2.7 -	
     2.8 -	if (m_InExec)
     2.9 +
    2.10 +	if (m_InExec || m_InHook)
    2.11  	{
    2.12  		return NULL;
    2.13  	}
    2.14 @@ -98,16 +98,16 @@
    2.15  		return NULL;
    2.16  	}
    2.17  
    2.18 -	m_CellRecFilter.SetRecipientPtr(players, playersNum);
    2.19 +	m_CellRecFilter.Initialize(players, playersNum);
    2.20  
    2.21  	m_CurFlags = flags;
    2.22  	if (m_CurFlags & USERMSG_INITMSG)
    2.23  	{
    2.24 -		m_CellRecFilter.SetInitMessage(true);
    2.25 +		m_CellRecFilter.SetToInit(true);
    2.26  	}
    2.27  	if (m_CurFlags & USERMSG_RELIABLE)
    2.28  	{
    2.29 -		m_CellRecFilter.SetReliable(true);
    2.30 +		m_CellRecFilter.SetToReliable(true);
    2.31  	}
    2.32  
    2.33  	m_InExec = true;
    2.34 @@ -138,7 +138,7 @@
    2.35  
    2.36  	m_InExec = false;
    2.37  	m_CurFlags = 0;
    2.38 -	m_CellRecFilter.ResetFilter();
    2.39 +	m_CellRecFilter.Reset();
    2.40  
    2.41  	return true;
    2.42  }
    2.43 @@ -150,6 +150,19 @@
    2.44  		return false;
    2.45  	}
    2.46  
    2.47 +	ListenerInfo *pInfo;
    2.48 +	if (m_FreeListeners.empty())
    2.49 +	{
    2.50 +		pInfo = new ListenerInfo;
    2.51 +	} else {
    2.52 +		pInfo = m_FreeListeners.front();
    2.53 +		m_FreeListeners.pop();
    2.54 +	}
    2.55 +
    2.56 +	pInfo->Callback = pListener;
    2.57 +	pInfo->IsHooked = false;
    2.58 +	pInfo->KillMe = false;
    2.59 +
    2.60  	if (!m_HookCount++)
    2.61  	{
    2.62  		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
    2.63 @@ -160,20 +173,19 @@
    2.64  
    2.65  	if (intercept)
    2.66  	{
    2.67 -		m_msgIntercepts[msg_id].push_back(pListener);
    2.68 +		m_msgIntercepts[msg_id].push_back(pInfo);
    2.69  	} else {
    2.70 -		m_msgHooks[msg_id].push_back(pListener);
    2.71 +		m_msgHooks[msg_id].push_back(pInfo);
    2.72  	}
    2.73  
    2.74  	return true;
    2.75  }
    2.76  
    2.77  bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
    2.78 -{
    2.79 -	//:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess
    2.80 -	List<IUserMessageListener *> *lst;
    2.81 -	IUserMessageListener *listener;
    2.82 +{	
    2.83 +	MsgList *pList;
    2.84  	MsgIter iter;
    2.85 +	ListenerInfo *pInfo;
    2.86  	bool deleted = false;
    2.87  
    2.88  	if (msg_id < 0 || msg_id >= 255)
    2.89 @@ -181,27 +193,40 @@
    2.90  		return false;
    2.91  	}
    2.92  
    2.93 -	lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
    2.94 -	for (iter=lst->begin(); iter!=lst->end(); iter++)
    2.95 +	pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
    2.96 +	for (iter=pList->begin(); iter!=pList->end(); iter++)
    2.97  	{
    2.98 -		listener = (*iter);
    2.99 -		if (listener == pListener)
   2.100 +		pInfo = (*iter);
   2.101 +		if (pInfo->Callback == pListener)
   2.102  		{
   2.103 -			lst->erase(iter);
   2.104 +			if (pInfo->IsHooked)
   2.105 +			{
   2.106 +				pInfo->KillMe = true;
   2.107 +				return true;
   2.108 +			}
   2.109 +			pList->erase(iter);
   2.110  			deleted = true;
   2.111  			break;
   2.112  		}
   2.113  	}
   2.114  
   2.115 -	if (deleted && !(--m_HookCount))
   2.116 +	if (deleted)
   2.117 +	{
   2.118 +		_DecRefCounter();
   2.119 +	}
   2.120 +
   2.121 +	return deleted;
   2.122 +}
   2.123 +
   2.124 +void CUserMessages::_DecRefCounter()
   2.125 +{
   2.126 +	if (--m_HookCount == 0)
   2.127  	{
   2.128  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
   2.129  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
   2.130  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
   2.131  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
   2.132  	}
   2.133 -
   2.134 -	return (deleted) ? true : false;
   2.135  }
   2.136  
   2.137  bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
   2.138 @@ -209,13 +234,8 @@
   2.139  	bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
   2.140  	bool is_hook_empty = m_msgHooks[msg_type].empty();
   2.141  
   2.142 -	if (is_intercept_empty && is_hook_empty)
   2.143 -	{
   2.144 -		m_InHook = false;
   2.145 -		RETURN_META_VALUE(MRES_IGNORED, NULL);
   2.146 -	}
   2.147 -
   2.148 -	if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL))
   2.149 +	if ((is_intercept_empty && is_hook_empty)
   2.150 +		|| (m_InExec && !(m_CurFlags & USERMSG_PASSTHRU_ALL)))
   2.151  	{
   2.152  		m_InHook = false;
   2.153  		RETURN_META_VALUE(MRES_IGNORED, NULL);
   2.154 @@ -223,11 +243,11 @@
   2.155  
   2.156  	m_CurId = msg_type;
   2.157  	m_CurRecFilter = filter;
   2.158 -	m_InterceptBuffer.Reset();
   2.159  	m_InHook = true;
   2.160  
   2.161  	if (!is_intercept_empty)
   2.162  	{
   2.163 +		m_InterceptBuffer.Reset();
   2.164  		RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
   2.165  	}
   2.166  
   2.167 @@ -253,23 +273,48 @@
   2.168  		RETURN_META(MRES_IGNORED);
   2.169  	}
   2.170  
   2.171 -	List<IUserMessageListener *> *lst;
   2.172 -	IUserMessageListener *listener;
   2.173 +	MsgList *pList;
   2.174  	MsgIter iter;
   2.175 +	ListenerInfo *pInfo;
   2.176 +
   2.177 +	pList = &m_msgIntercepts[m_CurId];
   2.178 +	for (iter=pList->begin(); iter!=pList->end(); )
   2.179 +	{
   2.180 +		pInfo = (*iter);
   2.181 +		pInfo->IsHooked = true;
   2.182 +		pInfo->Callback->OnUserMessageSent(m_CurId);
   2.183  
   2.184 -	lst = &m_msgIntercepts[m_CurId];
   2.185 -	for (iter=lst->begin(); iter!=lst->end(); iter++)
   2.186 -	{
   2.187 -		listener = (*iter);
   2.188 -		listener->OnUserMessageSent(m_CurId);
   2.189 +		if (pInfo->KillMe)
   2.190 +		{
   2.191 +			iter = pList->erase(iter);
   2.192 +			m_FreeListeners.push(pInfo);
   2.193 +			_DecRefCounter();
   2.194 +			continue;
   2.195 +		}
   2.196 +
   2.197 +		pInfo->IsHooked = false;
   2.198 +		iter++;
   2.199  	}
   2.200  
   2.201 -	lst = &m_msgHooks[m_CurId];
   2.202 -	for (iter=lst->begin(); iter!=lst->end(); iter++)
   2.203 +	pList = &m_msgHooks[m_CurId];
   2.204 +	for (iter=pList->begin(); iter!=pList->end(); iter++)
   2.205  	{
   2.206 -		listener = (*iter);
   2.207 -		listener->OnUserMessageSent(m_CurId);
   2.208 +		pInfo = (*iter);
   2.209 +		pInfo->Callback->OnUserMessageSent(m_CurId);
   2.210 +
   2.211 +		if (pInfo->KillMe)
   2.212 +		{
   2.213 +			iter = pList->erase(iter);
   2.214 +			m_FreeListeners.push(pInfo);
   2.215 +			_DecRefCounter();
   2.216 +			continue;
   2.217 +		}
   2.218 +
   2.219 +		pInfo->IsHooked = false;
   2.220 +		iter++;
   2.221  	}
   2.222 +
   2.223 +	m_InHook = false;
   2.224  }
   2.225  
   2.226  void CUserMessages::OnMessageEnd_Pre()
   2.227 @@ -279,26 +324,61 @@
   2.228  		RETURN_META(MRES_IGNORED);
   2.229  	}
   2.230  
   2.231 -	List<IUserMessageListener *> *lst;
   2.232 -	IUserMessageListener *listener;
   2.233 -	bf_write *engine_bfw;
   2.234 +	MsgList *pList;
   2.235  	MsgIter iter;
   2.236 +	ListenerInfo *pInfo;
   2.237 +
   2.238  	ResultType res;
   2.239  	bool intercepted = false;
   2.240  	bool handled = false;
   2.241  
   2.242 -	lst = &m_msgIntercepts[m_CurId];
   2.243 -	for (iter=lst->begin(); iter!=lst->end(); iter++)
   2.244 +	pList = &m_msgIntercepts[m_CurId];
   2.245 +	for (iter=pList->begin(); iter!=pList->end(); )
   2.246  	{
   2.247 -		listener = (*iter);
   2.248 -		res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
   2.249 -		if (res == Pl_Stop)
   2.250 +		pInfo = (*iter);
   2.251 +		pInfo->IsHooked = true;
   2.252 +		res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
   2.253 +
   2.254 +		switch (res)
   2.255  		{
   2.256 -			goto supercede;
   2.257 -		} else if (res == Pl_Handled) {
   2.258 -			handled = true;
   2.259 +		case Pl_Stop:
   2.260 +			{
   2.261 +				if (pInfo->KillMe)
   2.262 +				{
   2.263 +					pList->erase(iter);
   2.264 +					m_FreeListeners.push(pInfo);
   2.265 +					_DecRefCounter();
   2.266 +					goto supercede;
   2.267 +				}
   2.268 +				pInfo->IsHooked = false;
   2.269 +				goto supercede;
   2.270 +			}
   2.271 +		case Pl_Handled:
   2.272 +			{
   2.273 +				handled = true;
   2.274 +				if (pInfo->KillMe)
   2.275 +				{
   2.276 +					iter = pList->erase(iter);
   2.277 +					m_FreeListeners.push(pInfo);
   2.278 +					_DecRefCounter();
   2.279 +					continue;
   2.280 +				}
   2.281 +				break;
   2.282 +			}
   2.283 +		default:
   2.284 +			{
   2.285 +				if (pInfo->KillMe)
   2.286 +				{
   2.287 +					iter = pList->erase(iter);
   2.288 +					m_FreeListeners.push(pInfo);
   2.289 +					_DecRefCounter();
   2.290 +					continue;
   2.291 +				}
   2.292 +			}
   2.293  		}
   2.294 +		pInfo->IsHooked = false;
   2.295  		intercepted = true;
   2.296 +		iter++;
   2.297  	}
   2.298  
   2.299  	if (handled)
   2.300 @@ -308,21 +388,36 @@
   2.301  
   2.302  	if (intercepted)
   2.303  	{
   2.304 +		bf_write *engine_bfw;
   2.305 +
   2.306  		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
   2.307  		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
   2.308  		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
   2.309  		ENGINE_CALL(MessageEnd)();
   2.310 +
   2.311  		goto supercede;
   2.312  	}
   2.313  
   2.314 -	lst = &m_msgHooks[m_CurId];
   2.315 -	for (iter=lst->begin(); iter!=lst->end(); iter++)
   2.316 +	pList = &m_msgHooks[m_CurId];
   2.317 +	for (iter=pList->begin(); iter!=pList->end(); )
   2.318  	{
   2.319 -		listener = (*iter);
   2.320 -		listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
   2.321 +		pInfo = (*iter);
   2.322 +		pInfo->IsHooked = true;
   2.323 +		pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
   2.324 +
   2.325 +		if (pInfo->KillMe)
   2.326 +		{
   2.327 +			iter = pList->erase(iter);
   2.328 +			m_FreeListeners.push(pInfo);
   2.329 +			_DecRefCounter();
   2.330 +			continue;
   2.331 +		}
   2.332 +
   2.333 +		iter++;
   2.334  	}
   2.335  
   2.336  	RETURN_META(MRES_IGNORED);
   2.337  supercede:
   2.338 +	m_InHook = false;
   2.339  	RETURN_META(MRES_SUPERCEDE);
   2.340  }
     3.1 --- a/core/UserMessages.h	Sat Mar 10 21:26:04 2007 +0000
     3.2 +++ b/core/UserMessages.h	Sun Mar 11 03:04:39 2007 +0000
     3.3 @@ -26,7 +26,15 @@
     3.4  
     3.5  #define INVALID_MESSAGE_ID -1
     3.6  
     3.7 -typedef List<IUserMessageListener *>::iterator MsgIter;
     3.8 +struct ListenerInfo
     3.9 +{
    3.10 +	IUserMessageListener *Callback;
    3.11 +	bool IsHooked;
    3.12 +	bool KillMe;
    3.13 +};
    3.14 +
    3.15 +typedef List<ListenerInfo *> MsgList;
    3.16 +typedef List<ListenerInfo *>::iterator MsgIter;
    3.17  
    3.18  class CUserMessages : 
    3.19  	public IUserMessages,
    3.20 @@ -51,8 +59,11 @@
    3.21  	void OnMessageEnd_Pre();
    3.22  	void OnMessageEnd_Post();
    3.23  private:
    3.24 -	List<IUserMessageListener *> m_msgHooks[255];
    3.25 -	List<IUserMessageListener *> m_msgIntercepts[255];
    3.26 +	void _DecRefCounter();
    3.27 +private:
    3.28 +	List<ListenerInfo *> m_msgHooks[255];
    3.29 +	List<ListenerInfo *> m_msgIntercepts[255];
    3.30 +	CStack<ListenerInfo *> m_FreeListeners;
    3.31  	unsigned char m_pBase[2500];
    3.32  	IRecipientFilter *m_CurRecFilter;
    3.33  	bf_write m_InterceptBuffer;
     4.1 --- a/core/msvc8/sourcemod_mm.vcproj	Sat Mar 10 21:26:04 2007 +0000
     4.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Sun Mar 11 03:04:39 2007 +0000
     4.3 @@ -1,7 +1,7 @@
     4.4  <?xml version="1.0" encoding="Windows-1252"?>
     4.5  <VisualStudioProject
     4.6  	ProjectType="Visual C++"
     4.7 -	Version="8.00"
     4.8 +	Version="8,00"
     4.9  	Name="sourcemod_mm"
    4.10  	ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
    4.11  	RootNamespace="sourcemod_mm"
     5.1 --- a/core/smn_usermsgs.cpp	Sat Mar 10 21:26:04 2007 +0000
     5.2 +++ b/core/smn_usermsgs.cpp	Sun Mar 11 03:04:39 2007 +0000
     5.3 @@ -22,6 +22,9 @@
     5.4  int g_MsgPlayers[256];
     5.5  bool g_IsMsgInExec = false;
     5.6  
     5.7 +typedef List<MsgListenerWrapper *> MsgWrapperList;
     5.8 +typedef List<MsgListenerWrapper *>::iterator MsgWrapperIter;
     5.9 +
    5.10  class UsrMessageNatives :
    5.11  	public SMGlobalClass,
    5.12  	public IHandleTypeDispatch,
    5.13 @@ -33,9 +36,9 @@
    5.14  	void OnHandleDestroy(HandleType_t type, void *object);
    5.15  	void OnPluginUnloaded(IPlugin *plugin);
    5.16  public:
    5.17 -	MsgListenerWrapper *GetNewListener(IPluginContext *pCtx);
    5.18 -	MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
    5.19 -	bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept);
    5.20 +	MsgListenerWrapper *CreateListener(IPluginContext *pCtx);
    5.21 +	MsgWrapperIter FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
    5.22 +	bool DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter);
    5.23  private:
    5.24  	CStack<MsgListenerWrapper *> m_FreeListeners;
    5.25  };
    5.26 @@ -59,92 +62,91 @@
    5.27  
    5.28  void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
    5.29  {
    5.30 -	List<MsgListenerWrapper *> *wrapper_list;
    5.31 +	MsgWrapperList *pList;
    5.32  
    5.33 -	if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list), true))
    5.34 +	if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList), true))
    5.35  	{
    5.36 -		List<MsgListenerWrapper *>::iterator iter;
    5.37 -		MsgListenerWrapper *listener;
    5.38 +		MsgWrapperIter iter;
    5.39 +		MsgListenerWrapper *pListener;
    5.40  
    5.41 -		for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
    5.42 +		for (iter=pList->begin(); iter!=pList->end(); iter++)
    5.43  		{
    5.44 -			listener = (*iter);
    5.45 -			if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook()))
    5.46 +			pListener = (*iter);
    5.47 +			if (g_UserMsgs.UnhookUserMessage(pListener->GetMessageId(), pListener, pListener->IsInterceptHook()))
    5.48  			{
    5.49 -				m_FreeListeners.push(listener);
    5.50 +				m_FreeListeners.push(pListener);
    5.51  			}
    5.52  		}
    5.53  
    5.54 -		delete wrapper_list;
    5.55 +		delete pList;
    5.56  	}
    5.57  }
    5.58  
    5.59 -MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx)
    5.60 +MsgListenerWrapper *UsrMessageNatives::CreateListener(IPluginContext *pCtx)
    5.61  {
    5.62 -	MsgListenerWrapper *listener_wrapper;
    5.63 +	MsgWrapperList *pList;
    5.64 +	MsgListenerWrapper *pListener;
    5.65 +	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
    5.66  
    5.67  	if (m_FreeListeners.empty())
    5.68  	{
    5.69 -		listener_wrapper = new MsgListenerWrapper;
    5.70 +		pListener = new MsgListenerWrapper;
    5.71  	} else {
    5.72 -		listener_wrapper = m_FreeListeners.front();
    5.73 +		pListener = m_FreeListeners.front();
    5.74  		m_FreeListeners.pop();
    5.75  	}
    5.76  
    5.77 -	List<MsgListenerWrapper *> *wrapper_list;
    5.78 -	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
    5.79 -
    5.80 -	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
    5.81 +	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
    5.82  	{
    5.83 -		wrapper_list = new List<MsgListenerWrapper *>;
    5.84 -		pl->SetProperty("MsgListeners", wrapper_list);
    5.85 +		pList = new List<MsgListenerWrapper *>;
    5.86 +		pl->SetProperty("MsgListeners", pList);
    5.87  	}
    5.88  
    5.89 -	wrapper_list->push_back(listener_wrapper);
    5.90 +	pList->push_back(pListener);
    5.91  
    5.92 -	return listener_wrapper;
    5.93 +	return pListener;
    5.94  }
    5.95  
    5.96 -MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
    5.97 +MsgWrapperIter UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
    5.98  {
    5.99 -	MsgListenerWrapper *listener;
   5.100 -	List<MsgListenerWrapper *> *wrapper_list;
   5.101 -	List<MsgListenerWrapper *>::iterator iter;
   5.102 +	MsgWrapperList *pList;
   5.103 +	MsgWrapperIter iter;
   5.104 +	MsgListenerWrapper *pListener;
   5.105  	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   5.106 -	bool found = false;
   5.107  
   5.108 -	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
   5.109 +	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
   5.110  	{
   5.111  		return NULL;
   5.112  	}
   5.113  
   5.114 -	for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
   5.115 +	for (iter=pList->begin(); iter!=pList->end(); iter++)
   5.116  	{
   5.117 -		listener = (*iter);
   5.118 -		if ((msgid == listener->GetMessageId()) 
   5.119 -			&& (intercept == listener->IsInterceptHook()) 
   5.120 -			&& (pHook == listener->GetHookedFunction()))
   5.121 +		pListener = (*iter);
   5.122 +		if ((msgid == pListener->GetMessageId()) 
   5.123 +			&& (intercept == pListener->IsInterceptHook()) 
   5.124 +			&& (pHook == pListener->GetHookedFunction()))
   5.125  		{
   5.126 -			found = true;
   5.127 -			break;
   5.128 +			return iter;
   5.129  		}
   5.130  	}
   5.131  
   5.132 -	return (found) ? listener : NULL;
   5.133 +	return NULL;
   5.134  }
   5.135  
   5.136 -bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept)
   5.137 +bool UsrMessageNatives::DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter)
   5.138  {
   5.139 -	List<MsgListenerWrapper *> *wrapper_list;
   5.140 +	MsgWrapperList *pList;
   5.141 +	MsgListenerWrapper *pListener;
   5.142  	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   5.143  
   5.144 -	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
   5.145 +	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
   5.146  	{
   5.147  		return false;
   5.148  	}
   5.149  
   5.150 -	wrapper_list->remove(listener);
   5.151 -	m_FreeListeners.push(listener);
   5.152 +	pListener = (*iter);
   5.153 +	pList->erase(iter);
   5.154 +	m_FreeListeners.push(pListener);
   5.155  
   5.156  	return true;
   5.157  }
   5.158 @@ -155,7 +157,29 @@
   5.159   *                                     *
   5.160   ***************************************/
   5.161  
   5.162 -size_t MsgListenerWrapper::PreparePlArray(int *pl_array, IRecipientFilter *pFilter)
   5.163 +void MsgListenerWrapper::Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept)
   5.164 +{
   5.165 +	if (intercept)
   5.166 +	{
   5.167 +		m_Intercept = hook;
   5.168 +		m_Hook = NULL;
   5.169 +	} else {
   5.170 +		m_Hook = hook;
   5.171 +		m_Intercept = NULL;
   5.172 +	}
   5.173 +
   5.174 +	if (notify)
   5.175 +	{
   5.176 +		m_Notify = notify;
   5.177 +	} else {
   5.178 +		m_Notify = NULL;
   5.179 +	}
   5.180 +
   5.181 +	m_MsgId = msgid;
   5.182 +	m_IsInterceptHook = intercept;
   5.183 +}
   5.184 +
   5.185 +size_t MsgListenerWrapper::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
   5.186  {
   5.187  	size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
   5.188  
   5.189 @@ -192,32 +216,10 @@
   5.190  	return m_Notify;
   5.191  }
   5.192  
   5.193 -void MsgListenerWrapper::InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept)
   5.194 -{
   5.195 -	if (intercept)
   5.196 -	{
   5.197 -		m_Intercept = hook;
   5.198 -		m_Hook = NULL;
   5.199 -	} else {
   5.200 -		m_Hook = hook;
   5.201 -		m_Intercept = NULL;
   5.202 -	}
   5.203 -
   5.204 -	if (notify)
   5.205 -	{
   5.206 -		m_Notify = notify;
   5.207 -	} else {
   5.208 -		m_Notify = NULL;
   5.209 -	}
   5.210 -
   5.211 -	m_MsgId = msgid;
   5.212 -	m_IsInterceptHook = intercept;
   5.213 -}
   5.214 -
   5.215  void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
   5.216  {
   5.217  	cell_t res;
   5.218 -	size_t size = PreparePlArray(g_MsgPlayers, pFilter);
   5.219 +	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
   5.220  
   5.221  	m_Hook->PushCell(msg_id);
   5.222  	m_Hook->PushCell(0); //:TODO: push handle!
   5.223 @@ -231,7 +233,7 @@
   5.224  ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
   5.225  {
   5.226  	cell_t res = static_cast<cell_t>(Pl_Continue);
   5.227 -	size_t size = PreparePlArray(g_MsgPlayers, pFilter);
   5.228 +	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
   5.229  
   5.230  	m_Intercept->PushCell(msg_id);
   5.231  	m_Intercept->PushCell(0); //:TODO: push handle!
   5.232 @@ -246,13 +248,12 @@
   5.233  
   5.234  void MsgListenerWrapper::OnUserMessageSent(int msg_id)
   5.235  {
   5.236 -	cell_t res;
   5.237 -
   5.238  	if (!m_Notify)
   5.239  	{
   5.240  		return;
   5.241  	}
   5.242  
   5.243 +	cell_t res;
   5.244  	m_Notify->PushCell(msg_id);
   5.245  	m_Notify->Execute(&res);
   5.246  }
   5.247 @@ -319,6 +320,10 @@
   5.248  	pCtx->LocalToPhysAddr(params[2], &cl_array);
   5.249  
   5.250  	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   5.251 +	if (!pBitBuf)
   5.252 +	{
   5.253 +		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
   5.254 +	}
   5.255  
   5.256  	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   5.257  	g_IsMsgInExec = true;
   5.258 @@ -345,6 +350,10 @@
   5.259  	pCtx->LocalToPhysAddr(params[2], &cl_array);
   5.260  
   5.261  	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   5.262 +	if (!pBitBuf)
   5.263 +	{
   5.264 +		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
   5.265 +	}
   5.266  
   5.267  	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   5.268  	g_IsMsgInExec = true;
   5.269 @@ -375,7 +384,7 @@
   5.270  static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
   5.271  {
   5.272  	IPluginFunction *pHook, *pNotify;
   5.273 -	MsgListenerWrapper *listener;
   5.274 +	MsgListenerWrapper *pListener;
   5.275  	bool intercept;
   5.276  	int msgid = params[1];
   5.277  
   5.278 @@ -390,12 +399,12 @@
   5.279  		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   5.280  	}
   5.281  	pNotify = pCtx->GetFunctionById(params[4]);
   5.282 +	intercept = (params[3]) ? true : false;
   5.283  
   5.284 -	intercept = (params[3]) ? true : false;
   5.285 -	listener = s_UsrMessageNatives.GetNewListener(pCtx);
   5.286 -	listener->InitListener(msgid, pHook, pNotify, intercept);
   5.287 +	pListener = s_UsrMessageNatives.CreateListener(pCtx);
   5.288 +	pListener->Initialize(msgid, pHook, pNotify, intercept);
   5.289  
   5.290 -	g_UserMsgs.HookUserMessage(msgid, listener, intercept);
   5.291 +	g_UserMsgs.HookUserMessage(msgid, pListener, intercept);
   5.292  
   5.293  	return 1;
   5.294  }
   5.295 @@ -403,7 +412,8 @@
   5.296  static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
   5.297  {
   5.298  	IPluginFunction *pFunc;
   5.299 -	MsgListenerWrapper *listener;
   5.300 +	MsgListenerWrapper *pListener;
   5.301 +	MsgWrapperIter iter;
   5.302  	bool intercept;
   5.303  	int msgid = params[1];
   5.304  
   5.305 @@ -417,20 +427,21 @@
   5.306  	{
   5.307  		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   5.308  	}
   5.309 +	intercept = (params[3]) ? true : false;
   5.310  
   5.311 -	intercept = (params[3]) ? true : false;
   5.312 -	listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
   5.313 -	if (!listener)
   5.314 +	iter = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
   5.315 +	if (iter == NULL)
   5.316  	{
   5.317  		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   5.318  	}
   5.319  
   5.320 -	if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept))
   5.321 +	pListener = (*iter);
   5.322 +	if (!g_UserMsgs.UnhookUserMessage(msgid, pListener, intercept))
   5.323  	{
   5.324  		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   5.325  	}
   5.326  
   5.327 -	s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept);
   5.328 +	s_UsrMessageNatives.DeleteListener(pCtx, iter);
   5.329  
   5.330  	return 1;
   5.331  }
     6.1 --- a/core/smn_usermsgs.h	Sat Mar 10 21:26:04 2007 +0000
     6.2 +++ b/core/smn_usermsgs.h	Sun Mar 11 03:04:39 2007 +0000
     6.3 @@ -20,7 +20,7 @@
     6.4  class MsgListenerWrapper : public IUserMessageListener
     6.5  {
     6.6  public:
     6.7 -	void InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept);
     6.8 +	void Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept);
     6.9  	bool IsInterceptHook() const;
    6.10  	int GetMessageId() const;
    6.11  	IPluginFunction *GetHookedFunction() const;
    6.12 @@ -30,7 +30,7 @@
    6.13  	ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
    6.14  	void OnUserMessageSent(int msg_id);
    6.15  private:
    6.16 -	size_t PreparePlArray(int *pl_array, IRecipientFilter *pFilter);
    6.17 +	size_t _FillInPlayers(int *pl_array, IRecipientFilter *pFilter);
    6.18  private:
    6.19  	IPluginFunction *m_Hook;
    6.20  	IPluginFunction *m_Intercept;
     7.1 --- a/core/sourcemod.cpp	Sat Mar 10 21:26:04 2007 +0000
     7.2 +++ b/core/sourcemod.cpp	Sun Mar 11 03:04:39 2007 +0000
     7.3 @@ -26,7 +26,7 @@
     7.4  #include "PlayerManager.h"
     7.5  #include "Translator.h"
     7.6  #include "ForwardSys.h"
     7.7 -#include "CTimerSys.h"
     7.8 +#include "TimerSys.h"
     7.9  
    7.10  SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
    7.11  SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);