- Added ForceChangeLevel and Map History to nextmap api
- Changed base plugins to use new api - Added sm_maphistory command to nextmap.sp --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402413
This commit is contained in:
parent
8126aa6bb8
commit
c75d607a00
135
core/NextMap.cpp
135
core/NextMap.cpp
@ -33,13 +33,26 @@
|
||||
#include "Logger.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcehook.h"
|
||||
#include "sm_srvcmds.h"
|
||||
|
||||
NextMapManager g_NextMap;
|
||||
|
||||
SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *);
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
ConCommand *changeLevelCmd = NULL;
|
||||
|
||||
ConVar sm_nextmap("sm_nextmap", "", FCVAR_NOTIFY);
|
||||
|
||||
bool g_forcedChange = false;
|
||||
|
||||
void NextMapManager::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
#if defined ORANGEBOX_BUILD
|
||||
@ -47,6 +60,30 @@ void NextMapManager::OnSourceModAllInitialized_Post()
|
||||
#else
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
|
||||
#endif
|
||||
|
||||
ConCommandBase *pBase = icvar->GetCommands();
|
||||
ConCommand *pCmd = NULL;
|
||||
while (pBase)
|
||||
{
|
||||
if (strcmp(pBase->GetName(), "changelevel") == 0)
|
||||
{
|
||||
/* Don't want to return convar with same name */
|
||||
if (!pBase->IsCommand())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pCmd = (ConCommand *)pBase;
|
||||
break;
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
if (pCmd != NULL)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CmdChangeLevelCallback, false);
|
||||
changeLevelCmd = pCmd;
|
||||
}
|
||||
}
|
||||
|
||||
void NextMapManager::OnSourceModShutdown()
|
||||
@ -56,6 +93,20 @@ void NextMapManager::OnSourceModShutdown()
|
||||
#else
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
|
||||
#endif
|
||||
|
||||
if (changeLevelCmd != NULL)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, changeLevelCmd, CmdChangeLevelCallback, false);
|
||||
}
|
||||
|
||||
SourceHook::List<MapChangeData *>::iterator iter;
|
||||
iter = m_mapHistory.begin();
|
||||
|
||||
while (iter != m_mapHistory.end())
|
||||
{
|
||||
delete (MapChangeData *)*iter;
|
||||
iter = m_mapHistory.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
const char *NextMapManager::GetNextMap()
|
||||
@ -77,6 +128,12 @@ bool NextMapManager::SetNextMap(const char *map)
|
||||
|
||||
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
|
||||
{
|
||||
if (g_forcedChange)
|
||||
{
|
||||
g_Logger.LogMessage("[SM] Changed map to \"%s\"", map);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
const char *newmap = sm_nextmap.GetString();
|
||||
|
||||
if (newmap[0] == 0 || !engine->IsMapValid(newmap))
|
||||
@ -86,5 +143,83 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
|
||||
|
||||
g_Logger.LogMessage("[SM] Changed map to \"%s\"", newmap);
|
||||
|
||||
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
|
||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
|
||||
|
||||
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown));
|
||||
}
|
||||
|
||||
void NextMapManager::OnSourceModLevelChange( const char *mapName )
|
||||
{
|
||||
/* Skip the first 'mapchange' when the server starts up */
|
||||
if (m_tempChangeInfo.startTime != 0)
|
||||
{
|
||||
if (strcmp(mapName, m_tempChangeInfo.m_mapName) == 0)
|
||||
{
|
||||
/* The map change was as we expected */
|
||||
m_mapHistory.push_back(new MapChangeData(lastMap, m_tempChangeInfo.m_changeReason, m_tempChangeInfo.startTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Something intercepted the mapchange */
|
||||
char newReason[255];
|
||||
UTIL_Format(newReason, sizeof(newReason), "%s (Map overridden)", m_tempChangeInfo.m_changeReason);
|
||||
m_mapHistory.push_back(new MapChangeData(lastMap, newReason, m_tempChangeInfo.startTime));
|
||||
}
|
||||
|
||||
/* TODO: Should this be customizable? */
|
||||
if (m_mapHistory.size() > 20)
|
||||
{
|
||||
SourceHook::List<MapChangeData *>::iterator iter;
|
||||
iter = m_mapHistory.begin();
|
||||
|
||||
delete (MapChangeData *)*iter;
|
||||
|
||||
m_mapHistory.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
m_tempChangeInfo.m_mapName[0] ='\0';
|
||||
m_tempChangeInfo.m_changeReason[0] = '\0';
|
||||
m_tempChangeInfo.startTime = time(NULL);
|
||||
UTIL_Format(lastMap, sizeof(lastMap), mapName);
|
||||
}
|
||||
|
||||
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
|
||||
{
|
||||
/* Store the mapname and reason */
|
||||
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), mapName);
|
||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), changeReason);
|
||||
|
||||
/* Change level and skip our hook */
|
||||
g_forcedChange = true;
|
||||
engine->ChangeLevel(mapName, NULL);
|
||||
g_forcedChange = false;
|
||||
}
|
||||
|
||||
NextMapManager::NextMapManager()
|
||||
{
|
||||
m_tempChangeInfo = MapChangeData();
|
||||
m_mapHistory = SourceHook::List<MapChangeData *>();
|
||||
}
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void CmdChangeLevelCallback(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
void CmdChangeLevelCallback()
|
||||
{
|
||||
CCommand command;
|
||||
#endif
|
||||
|
||||
if (command.ArgC() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_NextMap.m_tempChangeInfo.m_mapName[0] == '\0')
|
||||
{
|
||||
UTIL_Format(g_NextMap.m_tempChangeInfo.m_mapName, sizeof(g_NextMap.m_tempChangeInfo.m_mapName), command.Arg(1));
|
||||
UTIL_Format(g_NextMap.m_tempChangeInfo.m_changeReason, sizeof(g_NextMap.m_tempChangeInfo.m_changeReason), "changelevel Command");
|
||||
}
|
||||
}
|
@ -34,17 +34,58 @@
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "eiface.h"
|
||||
#include "sh_list.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
struct MapChangeData
|
||||
{
|
||||
MapChangeData(const char *mapName, const char *changeReason, time_t time)
|
||||
{
|
||||
UTIL_Format(m_mapName, sizeof(m_mapName), mapName);
|
||||
UTIL_Format(m_changeReason, sizeof(m_changeReason), changeReason);
|
||||
startTime = time;
|
||||
}
|
||||
|
||||
MapChangeData()
|
||||
{
|
||||
m_mapName[0] = '\0';
|
||||
m_changeReason[0] = '\0';
|
||||
startTime = 0;
|
||||
}
|
||||
|
||||
char m_mapName[32];
|
||||
char m_changeReason[100];
|
||||
time_t startTime;
|
||||
};
|
||||
|
||||
class NextMapManager : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
NextMapManager();
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
friend void CmdChangeLevelCallback(const CCommand &command);
|
||||
#else
|
||||
friend void CmdChangeLevelCallback();
|
||||
#endif
|
||||
|
||||
void OnSourceModAllInitialized_Post();
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
|
||||
const char *GetNextMap();
|
||||
bool SetNextMap(const char *map);
|
||||
|
||||
void ForceChangeLevel(const char *mapName, const char* changeReason);
|
||||
|
||||
void HookChangeLevel(const char *map, const char *unknown);
|
||||
|
||||
public:
|
||||
SourceHook::List<MapChangeData *> m_mapHistory;
|
||||
|
||||
private:
|
||||
MapChangeData m_tempChangeInfo;
|
||||
char lastMap[32];
|
||||
};
|
||||
|
||||
extern NextMapManager g_NextMap;
|
||||
|
@ -54,10 +54,58 @@ static cell_t sm_SetNextMap(IPluginContext *pCtx, const cell_t *params)
|
||||
return g_NextMap.SetNextMap(map);
|
||||
}
|
||||
|
||||
static cell_t sm_ForceChangeLevel(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
char *map;
|
||||
char *changeReason;
|
||||
|
||||
pCtx->LocalToString(params[1], &map);
|
||||
pCtx->LocalToString(params[2], &changeReason);
|
||||
|
||||
g_NextMap.ForceChangeLevel(map, changeReason);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t sm_GetMapHistorySize(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
return g_NextMap.m_mapHistory.size();
|
||||
}
|
||||
|
||||
static cell_t sm_GetMapHistory(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
if (params[1] < 0 || params[1] >= (int)g_NextMap.m_mapHistory.size())
|
||||
{
|
||||
return pCtx->ThrowNativeError("Invalid Map History Index");
|
||||
}
|
||||
|
||||
SourceHook::List<MapChangeData *>::iterator iter;
|
||||
iter = g_NextMap.m_mapHistory.end();
|
||||
iter--;
|
||||
|
||||
for (int i=0; i<params[1]; i++)
|
||||
{
|
||||
iter--;
|
||||
}
|
||||
|
||||
MapChangeData *data = (MapChangeData *)*iter;
|
||||
|
||||
pCtx->StringToLocal(params[2], params[3], data->m_mapName);
|
||||
pCtx->StringToLocal(params[4], params[5], data->m_changeReason);
|
||||
|
||||
cell_t *startTime;
|
||||
pCtx->LocalToPhysAddr(params[6], &startTime);
|
||||
*startTime = data->startTime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(nextmapnatives)
|
||||
{
|
||||
{"GetNextMap", sm_GetNextMap},
|
||||
{"SetNextMap", sm_SetNextMap},
|
||||
{NULL, NULL},
|
||||
{"GetNextMap", sm_GetNextMap},
|
||||
{"SetNextMap", sm_SetNextMap},
|
||||
{"ForceChangeLevel", sm_ForceChangeLevel},
|
||||
{"GetMapHistorySize", sm_GetMapHistorySize},
|
||||
{"GetMapHistory", sm_GetMapHistory},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -109,7 +109,7 @@ public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
|
||||
ResetPack(dp);
|
||||
ReadPackString(dp, map, sizeof(map));
|
||||
|
||||
ServerCommand("changelevel \"%s\"", map);
|
||||
ForceChangeLevel(map, "sm_map Command");
|
||||
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ new Handle:g_Cvar_WinLimit = INVALID_HANDLE;
|
||||
new Handle:g_Cvar_FragLimit = INVALID_HANDLE;
|
||||
new Handle:g_Cvar_MaxRounds = INVALID_HANDLE;
|
||||
|
||||
#define TIMELEFT_ALL_ALWAYS 0
|
||||
#define TIMELEFT_ALL_MAYBE 1
|
||||
#define TIMELEFT_ONE 2
|
||||
#define TIMELEFT_ALL_ALWAYS 0 /* Print to all players */
|
||||
#define TIMELEFT_ALL_MAYBE 1 /* Print to all players if sm_trigger_show allows */
|
||||
#define TIMELEFT_ONE 2 /* Print to a single player */
|
||||
|
||||
public OnPluginStart()
|
||||
{
|
||||
|
@ -424,7 +424,7 @@ public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
|
||||
ResetPack(dp);
|
||||
ReadPackString(dp, mapname, sizeof(mapname));
|
||||
|
||||
ServerCommand("changelevel \"%s\"", mapname);
|
||||
ForceChangeLevel(mapname, "sm_votemap Result");
|
||||
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
@ -51,4 +51,34 @@ native bool:SetNextMap(const String:map[]);
|
||||
* @param maxlen Maximum length of the map buffer.
|
||||
* @return True if a Map was found and copied, false if no nextmap is set (map will be unchanged).
|
||||
*/
|
||||
native bool:GetNextMap(String:map[], maxlen);
|
||||
native bool:GetNextMap(String:map[], maxlen);
|
||||
|
||||
/**
|
||||
* Changes the current map and records the reason for the change with maphistory
|
||||
*
|
||||
* @param map Map to change to.
|
||||
* @param reason Reason for change.
|
||||
* @noreturn
|
||||
*/
|
||||
native ForceChangeLevel(const String:map[], const String:reason[]);
|
||||
|
||||
/**
|
||||
* Gets the current number of maps in the map history
|
||||
*
|
||||
* @return Number of maps.
|
||||
*/
|
||||
native GetMapHistorySize();
|
||||
|
||||
/**
|
||||
* Retrieves a map from the map history list.
|
||||
*
|
||||
* @param item Item number. Must be 0 or greater and less than GetMapHistorySize().
|
||||
* @param map Buffer to store the map name.
|
||||
* @param mapLen Length of map buffer.
|
||||
* @param reason Buffer to store the change reason.
|
||||
* @param reasonLen Length of the reason buffer.
|
||||
* @param startTime Time the map started.
|
||||
* @noreturn
|
||||
* @error Invalid item number.
|
||||
*/
|
||||
native GetMapHistory(item, String:map[], mapLen, String:reason[], reasonLen, &startTime);
|
@ -771,7 +771,7 @@ public Action:Timer_ChangeMap(Handle:hTimer, Handle:dp)
|
||||
ReadPackString(dp, map, sizeof(map));
|
||||
}
|
||||
|
||||
ServerCommand("changelevel \"%s\"", map);
|
||||
ForceChangeLevel(map, "Map Vote");
|
||||
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ public Plugin:myinfo =
|
||||
new g_MapPos = -1;
|
||||
new Handle:g_MapList = INVALID_HANDLE;
|
||||
new g_MapListSerial = -1;
|
||||
|
||||
new g_CurrentMapStartTime;
|
||||
|
||||
public OnPluginStart()
|
||||
{
|
||||
@ -65,6 +67,7 @@ public OnPluginStart()
|
||||
RegConsoleCmd("nextmap", Command_Nextmap);
|
||||
|
||||
RegAdminCmd("sm_setnextmap", Command_SetNextmap, ADMFLAG_CHANGEMAP, "sm_setnextmap <map>");
|
||||
RegAdminCmd("sm_maphistory", Command_MapHistory, ADMFLAG_CHANGEMAP, "Shows the most recent maps played");
|
||||
RegConsoleCmd("listmaps", Command_List);
|
||||
|
||||
// Set to the current map so OnMapStart() will know what to do
|
||||
@ -72,6 +75,11 @@ public OnPluginStart()
|
||||
GetCurrentMap(currentMap, 64);
|
||||
SetNextMap(currentMap);
|
||||
}
|
||||
|
||||
public OnMapStart()
|
||||
{
|
||||
g_CurrentMapStartTime = GetTime();
|
||||
}
|
||||
|
||||
public OnConfigsExecuted()
|
||||
{
|
||||
@ -228,3 +236,59 @@ FindAndSetNextMap()
|
||||
GetArrayString(g_MapList, g_MapPos, mapName, sizeof(mapName));
|
||||
SetNextMap(mapName);
|
||||
}
|
||||
|
||||
public Action:Command_MapHistory(client, args)
|
||||
{
|
||||
new mapCount = GetMapHistorySize();
|
||||
|
||||
decl String:mapName[32];
|
||||
decl String:changeReason[100];
|
||||
decl String:timeString[100];
|
||||
decl String:playedTime[100];
|
||||
new startTime;
|
||||
|
||||
new lastMapStartTime = g_CurrentMapStartTime;
|
||||
|
||||
PrintToConsole(client, "Map History:\n");
|
||||
PrintToConsole(client, "Map : Started : Played Time : Reason for ending");
|
||||
|
||||
GetCurrentMap(mapName, sizeof(mapName));
|
||||
PrintToConsole(client, "%02i. %s (Current Map)", 0, mapName);
|
||||
|
||||
for (new i=0; i<mapCount; i++)
|
||||
{
|
||||
GetMapHistory(i, mapName, sizeof(mapName), changeReason, sizeof(changeReason), startTime);
|
||||
|
||||
FormatTimeDuration(timeString, sizeof(timeString), GetTime() - startTime);
|
||||
FormatTimeDuration(playedTime, sizeof(playedTime), lastMapStartTime - startTime);
|
||||
|
||||
PrintToConsole(client, "%02i. %s : %s ago : %s : %s", i+1, mapName, timeString, playedTime, changeReason);
|
||||
|
||||
lastMapStartTime = startTime;
|
||||
}
|
||||
}
|
||||
|
||||
FormatTimeDuration(String:buffer[], maxlen, time)
|
||||
{
|
||||
new days = time / 86400;
|
||||
new hours = (time / 3600) % 24;
|
||||
new minutes = (time / 60) % 60;
|
||||
new seconds = time % 60;
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
Format(buffer, maxlen, "%id %ih %im", days, hours, (seconds >= 30) ? minutes+1 : minutes);
|
||||
}
|
||||
else if (hours > 0)
|
||||
{
|
||||
Format(buffer, maxlen, "%ih %im", hours, (seconds >= 30) ? minutes+1 : minutes);
|
||||
}
|
||||
else if (minutes > 0)
|
||||
{
|
||||
Format(buffer, maxlen, "%im", (seconds >= 30) ? minutes+1 : minutes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Format(buffer, maxlen, "%is", seconds);
|
||||
}
|
||||
}
|
@ -298,7 +298,7 @@ public Action:Timer_ChangeMap(Handle:hTimer)
|
||||
new String:map[65];
|
||||
if (GetNextMap(map, sizeof(map)))
|
||||
{
|
||||
ServerCommand("changelevel \"%s\"", map);
|
||||
ForceChangeLevel(map, "RTV after mapvote");
|
||||
}
|
||||
|
||||
return Plugin_Stop;
|
||||
|
Loading…
Reference in New Issue
Block a user