core/UserMessages.cpp
changeset 592 c2a2c38f1331
child 593 507e74843261
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/core/UserMessages.cpp	Sat Mar 10 21:26:04 2007 +0000
     1.3 @@ -0,0 +1,328 @@
     1.4 +/**
     1.5 +* vim: set ts=4 :
     1.6 +* ===============================================================
     1.7 +* SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     1.8 +* ===============================================================
     1.9 +*
    1.10 +* This file is not open source and may not be copied without explicit
    1.11 +* written permission of AlliedModders LLC.  This file may not be redistributed 
    1.12 +* in whole or significant part.
    1.13 +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    1.14 +*
    1.15 +* Version: $Id$
    1.16 +*/
    1.17 +
    1.18 +#include "UserMessages.h"
    1.19 +
    1.20 +CUserMessages g_UserMsgs;
    1.21 +
    1.22 +SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
    1.23 +SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
    1.24 +
    1.25 +//:TODO: USE NEW MM IFACE TO SEARCH FOR MESSAGE NAMES ETC! faluco--> i'll do this when i have some spare time
    1.26 +
    1.27 +CUserMessages::CUserMessages() : m_InterceptBuffer(m_pBase, 2500)
    1.28 +{
    1.29 +	m_Names = sm_trie_create();
    1.30 +	m_HookCount = 0;
    1.31 +	m_InExec = false;
    1.32 +	m_InHook = false;
    1.33 +	m_CurFlags = 0;
    1.34 +	m_CurId = INVALID_MESSAGE_ID;
    1.35 +}
    1.36 +
    1.37 +CUserMessages::~CUserMessages()
    1.38 +{
    1.39 +	sm_trie_destroy(m_Names);
    1.40 +}
    1.41 +
    1.42 +void CUserMessages::OnSourceModAllInitialized()
    1.43 +{
    1.44 +	g_ShareSys.AddInterface(NULL, this);
    1.45 +}
    1.46 +
    1.47 +void CUserMessages::OnSourceModAllShutdown()
    1.48 +{
    1.49 +	if (m_HookCount)
    1.50 +	{
    1.51 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
    1.52 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
    1.53 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
    1.54 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
    1.55 +	}
    1.56 +	m_HookCount = 0;
    1.57 +}
    1.58 +
    1.59 +int CUserMessages::GetMessageIndex(const char *msg)
    1.60 +{
    1.61 +	int msgid;
    1.62 +	if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
    1.63 +	{
    1.64 +		char buf[255];
    1.65 +		int dummy;
    1.66 +		msgid = 0;
    1.67 +
    1.68 +		while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy))
    1.69 +		{
    1.70 +			if (strcmp(msg, buf) == 0)
    1.71 +			{
    1.72 +				sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
    1.73 +				return msgid;
    1.74 +			}
    1.75 +			msgid++;
    1.76 +		}
    1.77 +
    1.78 +		return INVALID_MESSAGE_ID;
    1.79 +	}
    1.80 +
    1.81 +	return msgid;
    1.82 +}
    1.83 +
    1.84 +bool CUserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const
    1.85 +{
    1.86 +	int dummy;
    1.87 +
    1.88 +	return gamedll->GetUserMessageInfo(msgid, buffer, maxlen, dummy);
    1.89 +}
    1.90 +
    1.91 +bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
    1.92 +{
    1.93 +	bf_write *buffer;
    1.94 +	
    1.95 +	if (m_InExec)
    1.96 +	{
    1.97 +		return NULL;
    1.98 +	}
    1.99 +	if (msg_id < 0 || msg_id >= 255)
   1.100 +	{
   1.101 +		return NULL;
   1.102 +	}
   1.103 +
   1.104 +	m_CellRecFilter.SetRecipientPtr(players, playersNum);
   1.105 +
   1.106 +	m_CurFlags = flags;
   1.107 +	if (m_CurFlags & USERMSG_INITMSG)
   1.108 +	{
   1.109 +		m_CellRecFilter.SetInitMessage(true);
   1.110 +	}
   1.111 +	if (m_CurFlags & USERMSG_RELIABLE)
   1.112 +	{
   1.113 +		m_CellRecFilter.SetReliable(true);
   1.114 +	}
   1.115 +
   1.116 +	m_InExec = true;
   1.117 +
   1.118 +	if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
   1.119 +	{
   1.120 +		buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
   1.121 +	} else {
   1.122 +		buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
   1.123 +	}
   1.124 +
   1.125 +	return buffer;
   1.126 +}
   1.127 +
   1.128 +bool CUserMessages::EndMessage()
   1.129 +{
   1.130 +	if (!m_InExec)
   1.131 +	{
   1.132 +		return false;
   1.133 +	}
   1.134 +
   1.135 +	if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
   1.136 +	{
   1.137 +		engine->MessageEnd();
   1.138 +	} else {
   1.139 +		ENGINE_CALL(MessageEnd)();
   1.140 +	}
   1.141 +
   1.142 +	m_InExec = false;
   1.143 +	m_CurFlags = 0;
   1.144 +	m_CellRecFilter.ResetFilter();
   1.145 +
   1.146 +	return true;
   1.147 +}
   1.148 +
   1.149 +bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
   1.150 +{
   1.151 +	if (msg_id < 0 || msg_id >= 255)
   1.152 +	{
   1.153 +		return false;
   1.154 +	}
   1.155 +
   1.156 +	if (!m_HookCount++)
   1.157 +	{
   1.158 +		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
   1.159 +		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
   1.160 +		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
   1.161 +		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
   1.162 +	}
   1.163 +
   1.164 +	if (intercept)
   1.165 +	{
   1.166 +		m_msgIntercepts[msg_id].push_back(pListener);
   1.167 +	} else {
   1.168 +		m_msgHooks[msg_id].push_back(pListener);
   1.169 +	}
   1.170 +
   1.171 +	return true;
   1.172 +}
   1.173 +
   1.174 +bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
   1.175 +{
   1.176 +	//:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess
   1.177 +	List<IUserMessageListener *> *lst;
   1.178 +	IUserMessageListener *listener;
   1.179 +	MsgIter iter;
   1.180 +	bool deleted = false;
   1.181 +
   1.182 +	if (msg_id < 0 || msg_id >= 255)
   1.183 +	{
   1.184 +		return false;
   1.185 +	}
   1.186 +
   1.187 +	lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
   1.188 +	for (iter=lst->begin(); iter!=lst->end(); iter++)
   1.189 +	{
   1.190 +		listener = (*iter);
   1.191 +		if (listener == pListener)
   1.192 +		{
   1.193 +			lst->erase(iter);
   1.194 +			deleted = true;
   1.195 +			break;
   1.196 +		}
   1.197 +	}
   1.198 +
   1.199 +	if (deleted && !(--m_HookCount))
   1.200 +	{
   1.201 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
   1.202 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
   1.203 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
   1.204 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
   1.205 +	}
   1.206 +
   1.207 +	return (deleted) ? true : false;
   1.208 +}
   1.209 +
   1.210 +bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
   1.211 +{
   1.212 +	bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
   1.213 +	bool is_hook_empty = m_msgHooks[msg_type].empty();
   1.214 +
   1.215 +	if (is_intercept_empty && is_hook_empty)
   1.216 +	{
   1.217 +		m_InHook = false;
   1.218 +		RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.219 +	}
   1.220 +
   1.221 +	if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL))
   1.222 +	{
   1.223 +		m_InHook = false;
   1.224 +		RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.225 +	}
   1.226 +
   1.227 +	m_CurId = msg_type;
   1.228 +	m_CurRecFilter = filter;
   1.229 +	m_InterceptBuffer.Reset();
   1.230 +	m_InHook = true;
   1.231 +
   1.232 +	if (!is_intercept_empty)
   1.233 +	{
   1.234 +		RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
   1.235 +	}
   1.236 +
   1.237 +	RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.238 +}
   1.239 +
   1.240 +bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
   1.241 +{
   1.242 +	if (!m_InHook)
   1.243 +	{
   1.244 +		RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.245 +	}
   1.246 +
   1.247 +	m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
   1.248 +
   1.249 +	RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.250 +}
   1.251 +
   1.252 +void CUserMessages::OnMessageEnd_Post()
   1.253 +{
   1.254 +	if (!m_InHook || (META_RESULT_STATUS == MRES_SUPERCEDE))
   1.255 +	{
   1.256 +		RETURN_META(MRES_IGNORED);
   1.257 +	}
   1.258 +
   1.259 +	List<IUserMessageListener *> *lst;
   1.260 +	IUserMessageListener *listener;
   1.261 +	MsgIter iter;
   1.262 +
   1.263 +	lst = &m_msgIntercepts[m_CurId];
   1.264 +	for (iter=lst->begin(); iter!=lst->end(); iter++)
   1.265 +	{
   1.266 +		listener = (*iter);
   1.267 +		listener->OnUserMessageSent(m_CurId);
   1.268 +	}
   1.269 +
   1.270 +	lst = &m_msgHooks[m_CurId];
   1.271 +	for (iter=lst->begin(); iter!=lst->end(); iter++)
   1.272 +	{
   1.273 +		listener = (*iter);
   1.274 +		listener->OnUserMessageSent(m_CurId);
   1.275 +	}
   1.276 +}
   1.277 +
   1.278 +void CUserMessages::OnMessageEnd_Pre()
   1.279 +{
   1.280 +	if (!m_InHook)
   1.281 +	{
   1.282 +		RETURN_META(MRES_IGNORED);
   1.283 +	}
   1.284 +
   1.285 +	List<IUserMessageListener *> *lst;
   1.286 +	IUserMessageListener *listener;
   1.287 +	bf_write *engine_bfw;
   1.288 +	MsgIter iter;
   1.289 +	ResultType res;
   1.290 +	bool intercepted = false;
   1.291 +	bool handled = false;
   1.292 +
   1.293 +	lst = &m_msgIntercepts[m_CurId];
   1.294 +	for (iter=lst->begin(); iter!=lst->end(); iter++)
   1.295 +	{
   1.296 +		listener = (*iter);
   1.297 +		res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
   1.298 +		if (res == Pl_Stop)
   1.299 +		{
   1.300 +			goto supercede;
   1.301 +		} else if (res == Pl_Handled) {
   1.302 +			handled = true;
   1.303 +		}
   1.304 +		intercepted = true;
   1.305 +	}
   1.306 +
   1.307 +	if (handled)
   1.308 +	{
   1.309 +		goto supercede;
   1.310 +	}
   1.311 +
   1.312 +	if (intercepted)
   1.313 +	{
   1.314 +		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
   1.315 +		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
   1.316 +		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
   1.317 +		ENGINE_CALL(MessageEnd)();
   1.318 +		goto supercede;
   1.319 +	}
   1.320 +
   1.321 +	lst = &m_msgHooks[m_CurId];
   1.322 +	for (iter=lst->begin(); iter!=lst->end(); iter++)
   1.323 +	{
   1.324 +		listener = (*iter);
   1.325 +		listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
   1.326 +	}
   1.327 +
   1.328 +	RETURN_META(MRES_IGNORED);
   1.329 +supercede:
   1.330 +	RETURN_META(MRES_SUPERCEDE);
   1.331 +}