1.1 --- a/core/NextMap.cpp Sat Jul 12 22:28:10 2008 +0000
1.2 +++ b/core/NextMap.cpp Sun Jul 13 05:13:37 2008 +0000
1.3 @@ -33,13 +33,26 @@
1.4 #include "Logger.h"
1.5 #include "sourcemm_api.h"
1.6 #include "sm_stringutil.h"
1.7 +#include "sourcehook.h"
1.8 +#include "sm_srvcmds.h"
1.9
1.10 NextMapManager g_NextMap;
1.11
1.12 SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *);
1.13
1.14 +#if defined ORANGEBOX_BUILD
1.15 +SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
1.16 +#else
1.17 +extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
1.18 +extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
1.19 +#endif
1.20 +
1.21 +ConCommand *changeLevelCmd = NULL;
1.22 +
1.23 ConVar sm_nextmap("sm_nextmap", "", FCVAR_NOTIFY);
1.24
1.25 +bool g_forcedChange = false;
1.26 +
1.27 void NextMapManager::OnSourceModAllInitialized_Post()
1.28 {
1.29 #if defined ORANGEBOX_BUILD
1.30 @@ -47,6 +60,30 @@
1.31 #else
1.32 SH_ADD_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
1.33 #endif
1.34 +
1.35 + ConCommandBase *pBase = icvar->GetCommands();
1.36 + ConCommand *pCmd = NULL;
1.37 + while (pBase)
1.38 + {
1.39 + if (strcmp(pBase->GetName(), "changelevel") == 0)
1.40 + {
1.41 + /* Don't want to return convar with same name */
1.42 + if (!pBase->IsCommand())
1.43 + {
1.44 + break;
1.45 + }
1.46 +
1.47 + pCmd = (ConCommand *)pBase;
1.48 + break;
1.49 + }
1.50 + pBase = const_cast<ConCommandBase *>(pBase->GetNext());
1.51 + }
1.52 +
1.53 + if (pCmd != NULL)
1.54 + {
1.55 + SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CmdChangeLevelCallback, false);
1.56 + changeLevelCmd = pCmd;
1.57 + }
1.58 }
1.59
1.60 void NextMapManager::OnSourceModShutdown()
1.61 @@ -56,6 +93,20 @@
1.62 #else
1.63 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
1.64 #endif
1.65 +
1.66 + if (changeLevelCmd != NULL)
1.67 + {
1.68 + SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, changeLevelCmd, CmdChangeLevelCallback, false);
1.69 + }
1.70 +
1.71 + SourceHook::List<MapChangeData *>::iterator iter;
1.72 + iter = m_mapHistory.begin();
1.73 +
1.74 + while (iter != m_mapHistory.end())
1.75 + {
1.76 + delete (MapChangeData *)*iter;
1.77 + iter = m_mapHistory.erase(iter);
1.78 + }
1.79 }
1.80
1.81 const char *NextMapManager::GetNextMap()
1.82 @@ -77,6 +128,12 @@
1.83
1.84 void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
1.85 {
1.86 + if (g_forcedChange)
1.87 + {
1.88 + g_Logger.LogMessage("[SM] Changed map to \"%s\"", map);
1.89 + RETURN_META(MRES_IGNORED);
1.90 + }
1.91 +
1.92 const char *newmap = sm_nextmap.GetString();
1.93
1.94 if (newmap[0] == 0 || !engine->IsMapValid(newmap))
1.95 @@ -86,5 +143,83 @@
1.96
1.97 g_Logger.LogMessage("[SM] Changed map to \"%s\"", newmap);
1.98
1.99 + UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
1.100 + UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
1.101 +
1.102 RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown));
1.103 }
1.104 +
1.105 +void NextMapManager::OnSourceModLevelChange( const char *mapName )
1.106 +{
1.107 + /* Skip the first 'mapchange' when the server starts up */
1.108 + if (m_tempChangeInfo.startTime != 0)
1.109 + {
1.110 + if (strcmp(mapName, m_tempChangeInfo.m_mapName) == 0)
1.111 + {
1.112 + /* The map change was as we expected */
1.113 + m_mapHistory.push_back(new MapChangeData(lastMap, m_tempChangeInfo.m_changeReason, m_tempChangeInfo.startTime));
1.114 + }
1.115 + else
1.116 + {
1.117 + /* Something intercepted the mapchange */
1.118 + char newReason[255];
1.119 + UTIL_Format(newReason, sizeof(newReason), "%s (Map overridden)", m_tempChangeInfo.m_changeReason);
1.120 + m_mapHistory.push_back(new MapChangeData(lastMap, newReason, m_tempChangeInfo.startTime));
1.121 + }
1.122 +
1.123 + /* TODO: Should this be customizable? */
1.124 + if (m_mapHistory.size() > 20)
1.125 + {
1.126 + SourceHook::List<MapChangeData *>::iterator iter;
1.127 + iter = m_mapHistory.begin();
1.128 +
1.129 + delete (MapChangeData *)*iter;
1.130 +
1.131 + m_mapHistory.erase(iter);
1.132 + }
1.133 + }
1.134 +
1.135 + m_tempChangeInfo.m_mapName[0] ='\0';
1.136 + m_tempChangeInfo.m_changeReason[0] = '\0';
1.137 + m_tempChangeInfo.startTime = time(NULL);
1.138 + UTIL_Format(lastMap, sizeof(lastMap), mapName);
1.139 +}
1.140 +
1.141 +void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
1.142 +{
1.143 + /* Store the mapname and reason */
1.144 + UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), mapName);
1.145 + UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), changeReason);
1.146 +
1.147 + /* Change level and skip our hook */
1.148 + g_forcedChange = true;
1.149 + engine->ChangeLevel(mapName, NULL);
1.150 + g_forcedChange = false;
1.151 +}
1.152 +
1.153 +NextMapManager::NextMapManager()
1.154 +{
1.155 + m_tempChangeInfo = MapChangeData();
1.156 + m_mapHistory = SourceHook::List<MapChangeData *>();
1.157 +}
1.158 +
1.159 +#if defined ORANGEBOX_BUILD
1.160 +void CmdChangeLevelCallback(const CCommand &command)
1.161 +{
1.162 +#else
1.163 +void CmdChangeLevelCallback()
1.164 +{
1.165 + CCommand command;
1.166 +#endif
1.167 +
1.168 + if (command.ArgC() < 2)
1.169 + {
1.170 + return;
1.171 + }
1.172 +
1.173 + if (g_NextMap.m_tempChangeInfo.m_mapName[0] == '\0')
1.174 + {
1.175 + UTIL_Format(g_NextMap.m_tempChangeInfo.m_mapName, sizeof(g_NextMap.m_tempChangeInfo.m_mapName), command.Arg(1));
1.176 + UTIL_Format(g_NextMap.m_tempChangeInfo.m_changeReason, sizeof(g_NextMap.m_tempChangeInfo.m_changeReason), "changelevel Command");
1.177 + }
1.178 +}
1.179 \ No newline at end of file