Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List maps #1086

Closed
wants to merge 12 commits into from
14 changes: 13 additions & 1 deletion src/engine/client/client.cpp
Expand Up @@ -1156,6 +1156,18 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(Unpacker.Error() == 0)
m_pConsole->DeregisterTemp(pName);
}
else if(Msg == NETMSG_MAPLIST_ENTRY_ADD)
{
const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
if(Unpacker.Error() == 0)
m_pConsole->RegisterTempMap(pName);
}
else if(Msg == NETMSG_MAPLIST_ENTRY_REM)
{
const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
if(Unpacker.Error() == 0)
m_pConsole->DeregisterTempMap(pName);
}
else if(Msg == NETMSG_RCON_AUTH_ON)
{
m_RconAuthed = 1;
Expand All @@ -1166,7 +1178,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_RconAuthed = 0;
if(m_UseTempRconCommands)
m_pConsole->DeregisterTempAll();
m_UseTempRconCommands = 0;
m_pConsole->DeregisterTempMapAll();
}
else if(Msg == NETMSG_RCON_LINE)
{
Expand Down
6 changes: 6 additions & 0 deletions src/engine/console.h
Expand Up @@ -24,6 +24,8 @@ class IConsole : public IInterface
TEMPCMD_HELP_LENGTH=96,
TEMPCMD_PARAMS_LENGTH=16,

TEMPMAP_NAME_LENGTH=32,

MAX_PRINT_CB=4,
};

Expand Down Expand Up @@ -67,12 +69,16 @@ class IConsole : public IInterface
virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const = 0;
virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp) = 0;
virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) = 0;
virtual void PossibleMaps(const char *pStr, FPossibleCallback pfnCallback, void *pUser) = 0;
virtual void ParseArguments(int NumArgs, const char **ppArguments) = 0;

virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0;
virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) = 0;
virtual void DeregisterTemp(const char *pName) = 0;
virtual void DeregisterTempAll() = 0;
virtual void RegisterTempMap(const char *pName) = 0;
virtual void DeregisterTempMap(const char *pName) = 0;
virtual void DeregisterTempMapAll() = 0;
virtual void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser) = 0;
virtual void StoreCommands(bool Store) = 0;

Expand Down
137 changes: 135 additions & 2 deletions src/engine/server/server.cpp
@@ -1,8 +1,8 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */

#include <base/math.h>
#include <base/system.h>
#include <base/tl/sorted_array.h>

#include <engine/config.h>
#include <engine/console.h>
Expand Down Expand Up @@ -281,6 +281,10 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
m_pCurrentMapData = 0;
m_CurrentMapSize = 0;

m_NumMapEntries = 0;
m_pFirstMapEntry = 0;
m_pLastMapEntry = 0;

m_MapReload = 0;

m_RconClientID = IServer::RCON_CID_SERV;
Expand Down Expand Up @@ -692,6 +696,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser)
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].m_Quitting = false;
pThis->m_aClients[ClientID].m_pMapListEntryToSend = 0;
pThis->m_aClients[ClientID].Reset();
return 0;
}
Expand Down Expand Up @@ -721,6 +726,7 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].m_Quitting = false;
pThis->m_aClients[ClientID].m_pMapListEntryToSend = 0;
pThis->m_aClients[ClientID].m_Snapshots.PurgeAll();
return 0;
}
Expand Down Expand Up @@ -798,6 +804,35 @@ void CServer::UpdateClientRconCommands()
}
}

void CServer::SendMapListEntryAdd(const MapListEntry *pMapListEntry, int ClientID)
{
CMsgPacker Msg(NETMSG_MAPLIST_ENTRY_ADD, true);
Msg.AddString(pMapListEntry->m_aName, 256);
SendMsg(&Msg, MSGFLAG_VITAL, ClientID);
}

void CServer::SendMapListEntryRem(const MapListEntry *pMapListEntry, int ClientID)
{
CMsgPacker Msg(NETMSG_MAPLIST_ENTRY_REM, true);
Msg.AddString(pMapListEntry->m_aName, 256);
SendMsg(&Msg, MSGFLAG_VITAL, ClientID);
}


void CServer::UpdateClientMapListEntries()
{
int ClientID = Tick() % MAX_CLIENTS;

if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed)
{
for(int i = 0; i < MAX_MAPLISTENTRY_SEND && m_aClients[ClientID].m_pMapListEntryToSend; ++i)
{
SendMapListEntryAdd(m_aClients[ClientID].m_pMapListEntryToSend, ClientID);
m_aClients[ClientID].m_pMapListEntryToSend = m_aClients[ClientID].m_pMapListEntryToSend->m_pNext;
}
}
}

void CServer::ProcessClientPacket(CNetChunk *pPacket)
{
int ClientID = pPacket->m_ClientID;
Expand Down Expand Up @@ -991,6 +1026,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)

m_aClients[ClientID].m_Authed = AUTHED_ADMIN;
m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_ADMIN, CFGFLAG_SERVER);
m_aClients[ClientID].m_pMapListEntryToSend = m_pFirstMapEntry;
SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted.");
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID);
Expand All @@ -1004,6 +1040,9 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
m_aClients[ClientID].m_Authed = AUTHED_MOD;
m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_MOD, CFGFLAG_SERVER);
SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted.");
const IConsole::CCommandInfo *pInfo = Console()->GetCommandInfo("sv_map", CFGFLAG_SERVER, false);
if(Unpacker.Error() == 0 && pInfo->GetAccessLevel() == IConsole::ACCESS_LEVEL_MOD)
m_aClients[ClientID].m_pMapListEntryToSend = m_pFirstMapEntry;
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
Expand Down Expand Up @@ -1233,6 +1272,13 @@ int CServer::Run()
//
m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this);

// list maps
m_pMapListHeap= new CHeap();
SubdirCallbackUserdata Userdata;
Userdata.m_pServer = this;
str_copy(Userdata.m_aName, "", sizeof(Userdata.m_aName));
m_pStorage->ListDirectory(IStorage::TYPE_ALL, "maps/", MapListEntryCallback, &Userdata);

// load map
if(!LoadMap(g_Config.m_SvMap))
{
Expand Down Expand Up @@ -1362,6 +1408,7 @@ int CServer::Run()
DoSnapshot();

UpdateClientRconCommands();
UpdateClientMapListEntries();
}

// master server stuff
Expand Down Expand Up @@ -1415,6 +1462,57 @@ int CServer::Run()
return 0;
}

int CServer::MapListEntryCallback(const char *pFilename, int IsDir, int DirType, void *pUser)
{
SubdirCallbackUserdata *pUserdata = (SubdirCallbackUserdata *)pUser;
CServer *pThis = pUserdata->m_pServer;

if(pFilename[0] == '.') // hidden files
return 0;

char aFilename[512];
if(pUserdata->m_aName[0])
str_format(aFilename, sizeof(aFilename), "%s/%s", pUserdata->m_aName, pFilename);
else
str_format(aFilename, sizeof(aFilename), "%s", pFilename);

unsigned Length = str_length(aFilename);

if(IsDir)
{
SubdirCallbackUserdata Userdata;
Userdata.m_pServer = pThis;
str_copy(Userdata.m_aName, aFilename, sizeof(Userdata.m_aName));
char FindPath[512];
str_format(FindPath, sizeof(FindPath), "maps/%s/", aFilename);
pThis->m_pStorage->ListDirectory(IStorage::TYPE_ALL, FindPath, MapListEntryCallback, &Userdata);
return 0;
}
else
{
if(Length < 5 || str_comp(&aFilename[Length-4], ".map") != 0) // not ending with .map
return 0;
}

MapListEntry *pEntry;
pEntry = (MapListEntry *)pThis->m_pMapListHeap->Allocate(sizeof(MapListEntry));
pThis->m_NumMapEntries++;
pEntry->m_pNext = 0;
pEntry->m_pPrev = pThis->m_pLastMapEntry;
if(pEntry->m_pPrev)
pEntry->m_pPrev->m_pNext = pEntry;
pThis->m_pLastMapEntry = pEntry;
if(!pThis->m_pFirstMapEntry)
pThis->m_pFirstMapEntry = pEntry;

str_copy(pEntry->m_aName, aFilename, sizeof(pEntry->m_aName));

if(!IsDir)
pEntry->m_aName[Length - 4] = 0;

return 0;
}

void CServer::ConKick(IConsole::IResult *pResult, void *pUser)
{
if(pResult->NumArguments() > 1)
Expand Down Expand Up @@ -1447,7 +1545,7 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
}
else
str_format(aBuf, sizeof(aBuf), "id=%d addr=%s connecting", i, aAddrStr);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
}
}
Expand Down Expand Up @@ -1502,6 +1600,39 @@ void CServer::ConStopRecord(IConsole::IResult *pResult, void *pUser)
((CServer *)pUser)->m_DemoRecorder.Stop();
}

void CServer::ConListMaps(IConsole::IResult *pResult, void *pUser)
{
CServer *pServer = (CServer *)pUser;
char aBuf[260];
mem_zero(aBuf, sizeof(aBuf));
int Used = 0;

for(MapListEntry *pMapEntry = pServer->m_pFirstMapEntry; pMapEntry; pMapEntry = pMapEntry->m_pNext)
{
int Length = str_length(pMapEntry->m_aName);
if(Used + Length + 2 < (int)(sizeof(aBuf)))
{
if(Used > 0)
{
Used += 2;
str_append(aBuf, ", ", sizeof(aBuf));
}
str_append(aBuf, pMapEntry->m_aName, sizeof(aBuf));
Used += Length;
}
else
{
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
mem_zero(aBuf, sizeof(aBuf));
str_copy(aBuf, pMapEntry->m_aName, sizeof(aBuf));
Used = Length;
}
}
if(Used > 0)
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);

}

void CServer::ConMapReload(IConsole::IResult *pResult, void *pUser)
{
((CServer *)pUser)->m_MapReload = 1;
Expand All @@ -1520,6 +1651,7 @@ void CServer::ConLogout(IConsole::IResult *pResult, void *pUser)
pServer->m_aClients[pServer->m_RconClientID].m_Authed = AUTHED_NO;
pServer->m_aClients[pServer->m_RconClientID].m_AuthTries = 0;
pServer->m_aClients[pServer->m_RconClientID].m_pRconCmdToSend = 0;
pServer->m_aClients[pServer->m_RconClientID].m_pMapListEntryToSend = 0;
pServer->SendRconLine(pServer->m_RconClientID, "Logout successful.");
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", pServer->m_RconClientID);
Expand Down Expand Up @@ -1596,6 +1728,7 @@ void CServer::RegisterCommands()
Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "Record to a file");
Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "Stop recording");

Console()->Register("maps", "", CFGFLAG_SERVER, ConListMaps, this, "List all available maps");
Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "Reload the map");

Console()->Chain("sv_name", ConchainSpecialInfoupdate, this);
Expand Down
33 changes: 32 additions & 1 deletion src/engine/server/server.h
Expand Up @@ -4,7 +4,7 @@
#define ENGINE_SERVER_SERVER_H

#include <engine/server.h>

#include <engine/shared/memheap.h>

class CSnapIDPool
{
Expand Down Expand Up @@ -76,8 +76,11 @@ class CServer : public IServer
AUTHED_ADMIN,

MAX_RCONCMD_SEND=16,
MAX_MAPLISTENTRY_SEND=64,
};

struct MapListEntry;

class CClient
{
public:
Expand Down Expand Up @@ -125,6 +128,7 @@ class CServer : public IServer
int m_MapChunk;
bool m_Quitting;
const IConsole::CCommandInfo *m_pRconCmdToSend;
const MapListEntry *m_pMapListEntryToSend;

void Reset();
};
Expand Down Expand Up @@ -156,6 +160,26 @@ class CServer : public IServer
{
MAP_CHUNK_SIZE=NET_MAX_PAYLOAD-NET_MAX_CHUNKHEADERSIZE-4, // msg type
};

//maplist
struct MapListEntry
{
MapListEntry *m_pPrev;
MapListEntry *m_pNext;
char m_aName[IConsole::TEMPMAP_NAME_LENGTH];
};

struct SubdirCallbackUserdata
{
CServer *m_pServer;
char m_aName[IConsole::TEMPMAP_NAME_LENGTH];
};

CHeap *m_pMapListHeap;
MapListEntry *m_pLastMapEntry;
MapListEntry *m_pFirstMapEntry;
int m_NumMapEntries;

char m_aCurrentMap[64];
unsigned m_CurrentMapCrc;
unsigned char *m_pCurrentMapData;
Expand Down Expand Up @@ -213,6 +237,10 @@ class CServer : public IServer
void SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID);
void UpdateClientRconCommands();

void SendMapListEntryAdd(const MapListEntry *pMapListEntry, int ClientID);
void SendMapListEntryRem(const MapListEntry *pMapListEntry, int ClientID);
void UpdateClientMapListEntries();

void ProcessClientPacket(CNetChunk *pPacket);

void SendServerInfo(const NETADDR *pAddr, int Token);
Expand All @@ -226,11 +254,14 @@ class CServer : public IServer
void InitRegister(CNetServer *pNetServer, IEngineMasterServer *pMasterServer, IConsole *pConsole);
int Run();

static int MapListEntryCallback(const char *pFilename, int IsDir, int DirType, void *pUser);

static void ConKick(IConsole::IResult *pResult, void *pUser);
static void ConStatus(IConsole::IResult *pResult, void *pUser);
static void ConShutdown(IConsole::IResult *pResult, void *pUser);
static void ConRecord(IConsole::IResult *pResult, void *pUser);
static void ConStopRecord(IConsole::IResult *pResult, void *pUser);
static void ConListMaps(IConsole::IResult *pResult, void *pUser);
static void ConMapReload(IConsole::IResult *pResult, void *pUser);
static void ConLogout(IConsole::IResult *pResult, void *pUser);
static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
Expand Down