2012-06-14 13:06:06 +00:00
// ReDucTor is an awesome guy who helped me a lot
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 22:09:57 +00:00
# include "Server.h"
# include "ClientHandle.h"
2012-09-23 20:53:08 +00:00
# include "Mobs/Monster.h"
2012-09-23 22:09:57 +00:00
# include "Root.h"
# include "World.h"
2012-06-14 13:06:06 +00:00
# include "ChunkDef.h"
2013-12-08 11:17:54 +00:00
# include "Bindings/PluginManager.h"
2012-09-23 22:09:57 +00:00
# include "ChatColor.h"
2013-08-19 09:39:13 +00:00
# include "Entities/Player.h"
2012-09-23 22:09:57 +00:00
# include "Inventory.h"
# include "Item.h"
# include "FurnaceRecipe.h"
# include "WebAdmin.h"
2012-09-23 20:03:26 +00:00
# include "Protocol/ProtocolRecognizer.h"
2013-06-29 15:30:05 +00:00
# include "CommandOutput.h"
2012-06-14 13:06:06 +00:00
2014-10-23 13:15:10 +00:00
# include "IniFile.h"
2014-03-11 14:01:17 +00:00
# include "Vector3.h"
2012-06-14 13:06:06 +00:00
# include <fstream>
# include <sstream>
# include <iostream>
2014-07-19 13:23:40 +00:00
extern " C "
{
2013-11-27 07:40:59 +00:00
# include "zlib/zlib.h"
2012-06-14 13:06:06 +00:00
}
2012-10-19 20:51:46 +00:00
2015-07-31 14:49:10 +00:00
/** Enable the memory leak finder - needed for the "dumpmem" server command:
Synchronize this with main . cpp - the leak finder needs initialization before it can be used to dump memory
_X 2014 _02_20 : Disabled for canon repo , it makes the debug version too slow in MSVC2013
and we haven ' t had a memory leak for over a year anyway . */
2014-02-20 19:11:17 +00:00
// #define ENABLE_LEAK_FINDER
2012-10-19 22:09:33 +00:00
# if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
# pragma warning(push)
# pragma warning(disable:4100)
# include "LeakFinder.h"
# pragma warning(pop)
# endif
2012-06-14 13:06:06 +00:00
typedef std : : list < cClientHandle * > ClientList ;
2015-01-24 19:17:00 +00:00
////////////////////////////////////////////////////////////////////////////////
// cServerListenCallbacks:
class cServerListenCallbacks :
public cNetwork : : cListenCallbacks
{
cServer & m_Server ;
UInt16 m_Port ;
virtual cTCPLink : : cCallbacksPtr OnIncomingConnection ( const AString & a_RemoteIPAddress , UInt16 a_RemotePort ) override
{
return m_Server . OnConnectionAccepted ( a_RemoteIPAddress ) ;
}
virtual void OnAccepted ( cTCPLink & a_Link ) override { }
2015-05-23 11:56:08 +00:00
virtual void OnError ( int a_ErrorCode , const AString & a_ErrorMsg ) override
2015-01-24 19:17:00 +00:00
{
LOGWARNING ( " Cannot listen on port %d: %d (%s). " , m_Port , a_ErrorCode , a_ErrorMsg . c_str ( ) ) ;
}
public :
cServerListenCallbacks ( cServer & a_Server , UInt16 a_Port ) :
m_Server ( a_Server ) ,
m_Port ( a_Port )
{
}
} ;
2014-07-17 20:15:34 +00:00
////////////////////////////////////////////////////////////////////////////////
2013-08-11 17:46:27 +00:00
// cServer::cTickThread:
cServer : : cTickThread : : cTickThread ( cServer & a_Server ) :
super ( " ServerTickThread " ) ,
m_Server ( a_Server )
{
}
void cServer : : cTickThread : : Execute ( void )
2012-06-14 13:06:06 +00:00
{
2014-10-20 17:59:40 +00:00
auto LastTime = std : : chrono : : steady_clock : : now ( ) ;
static const auto msPerTick = std : : chrono : : milliseconds ( 50 ) ;
2013-08-11 17:46:27 +00:00
while ( ! m_ShouldTerminate )
{
2014-10-20 17:59:40 +00:00
auto NowTime = std : : chrono : : steady_clock : : now ( ) ;
2014-12-07 14:46:27 +00:00
auto msec = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( NowTime - LastTime ) . count ( ) ;
m_ShouldTerminate = ! m_Server . Tick ( static_cast < float > ( msec ) ) ;
2014-10-20 17:59:40 +00:00
auto TickTime = std : : chrono : : steady_clock : : now ( ) - NowTime ;
2015-04-29 16:24:14 +00:00
2013-08-11 17:46:27 +00:00
if ( TickTime < msPerTick )
{
// Stretch tick time until it's at least msPerTick
2014-10-21 13:17:36 +00:00
std : : this_thread : : sleep_for ( msPerTick - TickTime ) ;
2013-08-11 17:46:27 +00:00
}
2012-06-14 13:06:06 +00:00
2013-08-11 17:46:27 +00:00
LastTime = NowTime ;
}
}
2012-06-14 13:06:06 +00:00
2014-07-17 20:15:34 +00:00
////////////////////////////////////////////////////////////////////////////////
2013-08-11 17:18:06 +00:00
// cServer:
cServer : : cServer ( void ) :
2014-05-19 12:34:34 +00:00
m_PlayerCount ( 0 ) ,
m_PlayerCountDiff ( 0 ) ,
m_ClientViewDistance ( 0 ) ,
2013-08-11 17:18:06 +00:00
m_bIsConnected ( false ) ,
m_bRestarting ( false ) ,
2013-08-11 17:46:27 +00:00
m_RCONServer ( * this ) ,
2014-05-19 12:34:34 +00:00
m_MaxPlayers ( 0 ) ,
m_bIsHardcore ( false ) ,
m_TickThread ( * this ) ,
2014-08-21 20:39:53 +00:00
m_ShouldAuthenticate ( false ) ,
m_ShouldLoadOfflinePlayerData ( false ) ,
m_ShouldLoadNamedPlayerData ( true )
2013-08-11 17:18:06 +00:00
{
2015-09-28 19:30:31 +00:00
// Initialize the LuaStateTracker singleton before the app goes multithreaded:
cLuaStateTracker : : GetStats ( ) ;
2013-08-11 17:18:06 +00:00
}
2013-08-12 06:35:13 +00:00
void cServer : : ClientMovedToWorld ( const cClientHandle * a_Client )
{
cCSLock Lock ( m_CSClients ) ;
2013-08-13 20:45:29 +00:00
m_ClientsToRemove . push_back ( const_cast < cClientHandle * > ( a_Client ) ) ;
2013-08-12 06:35:13 +00:00
}
2013-08-14 08:24:34 +00:00
void cServer : : PlayerCreated ( const cPlayer * a_Player )
{
2013-12-22 14:42:17 +00:00
UNUSED ( a_Player ) ;
2013-08-14 08:24:34 +00:00
// To avoid deadlocks, the player count is not handled directly, but rather posted onto the tick thread
cCSLock Lock ( m_CSPlayerCountDiff ) ;
m_PlayerCountDiff + = 1 ;
}
2013-08-14 17:11:54 +00:00
void cServer : : PlayerDestroying ( const cPlayer * a_Player )
2013-08-14 08:24:34 +00:00
{
2013-12-22 14:42:17 +00:00
UNUSED ( a_Player ) ;
2013-08-14 08:24:34 +00:00
// To avoid deadlocks, the player count is not handled directly, but rather posted onto the tick thread
cCSLock Lock ( m_CSPlayerCountDiff ) ;
m_PlayerCountDiff - = 1 ;
}
2015-05-14 14:47:51 +00:00
bool cServer : : InitServer ( cSettingsRepositoryInterface & a_Settings , bool a_ShouldAuth )
2012-06-14 13:06:06 +00:00
{
2015-11-22 14:30:33 +00:00
m_Description = a_Settings . GetValueSet ( " Server " , " Description " , " Cuberite - in C++! " ) ;
2015-05-14 14:47:51 +00:00
m_MaxPlayers = a_Settings . GetValueSetI ( " Server " , " MaxPlayers " , 100 ) ;
m_bIsHardcore = a_Settings . GetValueSetB ( " Server " , " HardcoreEnabled " , false ) ;
m_bAllowMultiLogin = a_Settings . GetValueSetB ( " Server " , " AllowMultiLogin " , false ) ;
2013-08-14 08:24:34 +00:00
m_PlayerCount = 0 ;
m_PlayerCountDiff = 0 ;
2013-08-11 17:18:06 +00:00
2014-07-17 17:13:23 +00:00
m_FaviconData = Base64Encode ( cFile : : ReadWholeFile ( FILE_IO_PREFIX + AString ( " favicon.png " ) ) ) ; // Will return empty string if file nonexistant; client doesn't mind
2014-01-07 15:31:06 +00:00
2012-11-11 14:23:47 +00:00
if ( m_bIsConnected )
2012-06-14 13:06:06 +00:00
{
LOGERROR ( " ERROR: Trying to initialize server while server is already running! " ) ;
return false ;
}
2013-08-03 17:29:49 +00:00
LOGINFO ( " Compatible clients: %s " , MCS_CLIENT_VERSIONS ) ;
LOGINFO ( " Compatible protocol versions %s " , MCS_PROTOCOL_VERSIONS ) ;
2012-06-14 13:06:06 +00:00
2015-05-14 14:47:51 +00:00
m_Ports = ReadUpgradeIniPorts ( a_Settings , " Server " , " Ports " , " Port " , " PortsIPv6 " , " 25565 " ) ;
2015-04-29 16:24:14 +00:00
2015-05-14 14:47:51 +00:00
m_RCONServer . Initialize ( a_Settings ) ;
2013-06-27 15:14:20 +00:00
2012-06-14 13:06:06 +00:00
m_bIsConnected = true ;
2013-08-11 17:46:27 +00:00
m_ServerID = " - " ;
2014-10-17 11:57:18 +00:00
m_ShouldAuthenticate = a_ShouldAuth ;
2014-01-28 22:53:07 +00:00
if ( m_ShouldAuthenticate )
2012-11-11 14:23:47 +00:00
{
MTRand mtrand1 ;
2013-08-11 17:46:27 +00:00
unsigned int r1 = ( mtrand1 . randInt ( ) % 1147483647 ) + 1000000000 ;
unsigned int r2 = ( mtrand1 . randInt ( ) % 1147483647 ) + 1000000000 ;
2012-11-11 14:23:47 +00:00
std : : ostringstream sid ;
sid < < std : : hex < < r1 ;
sid < < std : : hex < < r2 ;
2013-08-11 17:46:27 +00:00
m_ServerID = sid . str ( ) ;
m_ServerID . resize ( 16 , ' 0 ' ) ;
2012-11-11 14:23:47 +00:00
}
2014-09-17 18:55:46 +00:00
// Check if both BungeeCord and online mode are on, if so, warn the admin:
2015-05-14 14:47:51 +00:00
m_ShouldAllowBungeeCord = a_Settings . GetValueSetB ( " Authentication " , " AllowBungeeCord " , false ) ;
2014-09-17 18:55:46 +00:00
if ( m_ShouldAllowBungeeCord & & m_ShouldAuthenticate )
{
LOGWARNING ( " WARNING: BungeeCord is allowed and server set to online mode. This is unsafe and will not work properly. Disable either authentication or BungeeCord in settings.ini. " ) ;
}
2015-04-29 16:24:14 +00:00
2015-05-14 14:47:51 +00:00
m_ShouldLoadOfflinePlayerData = a_Settings . GetValueSetB ( " PlayerData " , " LoadOfflinePlayerData " , false ) ;
m_ShouldLoadNamedPlayerData = a_Settings . GetValueSetB ( " PlayerData " , " LoadNamedPlayerData " , true ) ;
2015-04-29 16:24:14 +00:00
2015-05-14 14:47:51 +00:00
m_ClientViewDistance = a_Settings . GetValueSetI ( " Server " , " DefaultViewDistance " , cClientHandle : : DEFAULT_VIEW_DISTANCE ) ;
2012-11-11 14:23:47 +00:00
if ( m_ClientViewDistance < cClientHandle : : MIN_VIEW_DISTANCE )
{
m_ClientViewDistance = cClientHandle : : MIN_VIEW_DISTANCE ;
LOGINFO ( " Setting default viewdistance to the minimum of %d " , m_ClientViewDistance ) ;
}
if ( m_ClientViewDistance > cClientHandle : : MAX_VIEW_DISTANCE )
2012-06-14 13:06:06 +00:00
{
2012-11-11 14:23:47 +00:00
m_ClientViewDistance = cClientHandle : : MAX_VIEW_DISTANCE ;
LOGINFO ( " Setting default viewdistance to the maximum of %d " , m_ClientViewDistance ) ;
2012-06-14 13:06:06 +00:00
}
2015-04-29 16:24:14 +00:00
2012-08-30 21:06:13 +00:00
PrepareKeys ( ) ;
2015-04-29 16:24:14 +00:00
2012-06-14 13:06:06 +00:00
return true ;
}
2014-04-19 15:53:02 +00:00
int cServer : : GetNumPlayers ( void ) const
2013-08-14 08:24:34 +00:00
{
cCSLock Lock ( m_CSPlayerCount ) ;
return m_PlayerCount ;
}
2014-12-08 08:45:29 +00:00
bool cServer : : IsPlayerInQueue ( AString a_Username )
2014-11-29 08:36:15 +00:00
{
cCSLock Lock ( m_CSClients ) ;
2014-12-07 20:41:42 +00:00
for ( auto client : m_Clients )
2014-11-29 08:36:15 +00:00
{
2014-12-08 08:45:29 +00:00
if ( ( client - > GetUsername ( ) ) . compare ( a_Username ) = = 0 )
{
return true ;
}
2014-11-29 08:36:15 +00:00
}
2014-12-08 08:45:29 +00:00
return false ;
2014-11-29 08:36:15 +00:00
}
2012-08-30 21:06:13 +00:00
void cServer : : PrepareKeys ( void )
{
2013-09-28 19:36:01 +00:00
LOGD ( " Generating protocol encryption keypair... " ) ;
2014-01-23 22:35:23 +00:00
VERIFY ( m_PrivateKey . Generate ( 1024 ) ) ;
m_PublicKeyDER = m_PrivateKey . GetPubKeyDER ( ) ;
2012-08-30 21:06:13 +00:00
}
2015-01-24 19:17:00 +00:00
cTCPLink : : cCallbacksPtr cServer : : OnConnectionAccepted ( const AString & a_RemoteIPAddress )
2012-06-14 13:06:06 +00:00
{
2015-01-24 19:17:00 +00:00
LOGD ( " Client \" %s \" connected! " , a_RemoteIPAddress . c_str ( ) ) ;
cClientHandlePtr NewHandle = std : : make_shared < cClientHandle > ( a_RemoteIPAddress , m_ClientViewDistance ) ;
NewHandle - > SetSelf ( NewHandle ) ;
2012-06-14 13:06:06 +00:00
cCSLock Lock ( m_CSClients ) ;
2013-03-04 21:13:08 +00:00
m_Clients . push_back ( NewHandle ) ;
2015-01-24 19:17:00 +00:00
return NewHandle ;
2013-03-04 21:13:08 +00:00
}
2012-06-14 13:06:06 +00:00
bool cServer : : Tick ( float a_Dt )
{
2013-08-14 08:24:34 +00:00
// Apply the queued playercount adjustments (postponed to avoid deadlocks)
int PlayerCountDiff = 0 ;
{
cCSLock Lock ( m_CSPlayerCountDiff ) ;
std : : swap ( PlayerCountDiff , m_PlayerCountDiff ) ;
}
{
cCSLock Lock ( m_CSPlayerCount ) ;
m_PlayerCount + = PlayerCountDiff ;
}
2015-04-29 16:24:14 +00:00
2013-08-17 21:45:58 +00:00
// Send the tick to the plugins, as well as let the plugin manager reload, if asked to (issue #102):
cPluginManager : : Get ( ) - > Tick ( a_Dt ) ;
2015-04-29 16:24:14 +00:00
2013-08-17 21:45:58 +00:00
// Let the Root process all the queued commands:
2013-08-11 18:16:41 +00:00
cRoot : : Get ( ) - > TickCommands ( ) ;
2015-04-29 16:24:14 +00:00
2013-08-17 21:45:58 +00:00
// Tick all clients not yet assigned to a world:
2013-08-13 20:45:29 +00:00
TickClients ( a_Dt ) ;
if ( ! m_bRestarting )
{
return true ;
}
else
{
m_bRestarting = false ;
m_RestartEvent . Set ( ) ;
return false ;
}
}
void cServer : : TickClients ( float a_Dt )
{
2015-01-24 19:17:00 +00:00
cClientHandlePtrs RemoveClients ;
2012-06-14 13:06:06 +00:00
{
cCSLock Lock ( m_CSClients ) ;
2015-04-29 16:24:14 +00:00
2013-08-13 20:45:29 +00:00
// Remove clients that have moved to a world (the world will be ticking them from now on)
2015-01-24 19:17:00 +00:00
for ( auto itr = m_ClientsToRemove . begin ( ) , end = m_ClientsToRemove . end ( ) ; itr ! = end ; + + itr )
2013-08-13 20:45:29 +00:00
{
2015-01-24 19:17:00 +00:00
for ( auto itrC = m_Clients . begin ( ) , endC = m_Clients . end ( ) ; itrC ! = endC ; + + itrC )
{
if ( itrC - > get ( ) = = * itr )
{
m_Clients . erase ( itrC ) ;
break ;
}
}
2013-08-13 20:45:29 +00:00
} // for itr - m_ClientsToRemove[]
m_ClientsToRemove . clear ( ) ;
2015-04-29 16:24:14 +00:00
2013-08-13 20:45:29 +00:00
// Tick the remaining clients, take out those that have been destroyed into RemoveClients
2015-01-24 19:17:00 +00:00
for ( auto itr = m_Clients . begin ( ) ; itr ! = m_Clients . end ( ) ; )
2012-06-14 13:06:06 +00:00
{
if ( ( * itr ) - > IsDestroyed ( ) )
{
2015-01-24 19:17:00 +00:00
// Delete the client later, when CS is not held, to avoid deadlock: http://forum.mc-server.org/showthread.php?tid=374
2013-08-13 20:45:29 +00:00
RemoveClients . push_back ( * itr ) ;
2012-06-14 13:06:06 +00:00
itr = m_Clients . erase ( itr ) ;
continue ;
}
2013-12-16 09:41:35 +00:00
( * itr ) - > ServerTick ( a_Dt ) ;
2012-06-14 13:06:06 +00:00
+ + itr ;
} // for itr - m_Clients[]
}
2015-04-29 16:24:14 +00:00
2013-08-13 20:45:29 +00:00
// Delete the clients that have been destroyed
2015-01-24 19:17:00 +00:00
RemoveClients . clear ( ) ;
2012-06-14 13:06:06 +00:00
}
2013-03-04 21:13:08 +00:00
bool cServer : : Start ( void )
2012-06-14 13:06:06 +00:00
{
2015-01-24 19:17:00 +00:00
for ( auto port : m_Ports )
2013-03-05 09:53:29 +00:00
{
2015-01-25 15:25:15 +00:00
UInt16 PortNum ;
if ( ! StringToInteger ( port , PortNum ) )
2015-01-24 19:17:00 +00:00
{
LOGWARNING ( " Invalid port specified for server: \" %s \" . Ignoring. " , port . c_str ( ) ) ;
continue ;
}
auto Handle = cNetwork : : Listen ( PortNum , std : : make_shared < cServerListenCallbacks > ( * this , PortNum ) ) ;
if ( Handle - > IsListening ( ) )
{
m_ServerHandles . push_back ( Handle ) ;
}
} // for port - Ports[]
if ( m_ServerHandles . empty ( ) )
2013-03-04 21:13:08 +00:00
{
2015-01-24 19:17:00 +00:00
LOGERROR ( " Couldn't open any ports. Aborting the server " ) ;
2013-03-04 21:13:08 +00:00
return false ;
}
2013-08-11 17:46:27 +00:00
if ( ! m_TickThread . Start ( ) )
{
return false ;
}
2013-03-04 21:13:08 +00:00
return true ;
2012-06-14 13:06:06 +00:00
}
2013-06-22 19:08:34 +00:00
bool cServer : : Command ( cClientHandle & a_Client , AString & a_Cmd )
2012-06-14 13:06:06 +00:00
{
2014-10-15 17:01:55 +00:00
return cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHookChat ( * ( a_Client . GetPlayer ( ) ) , a_Cmd ) ;
2012-06-14 13:06:06 +00:00
}
2013-06-29 15:30:05 +00:00
void cServer : : ExecuteConsoleCommand ( const AString & a_Cmd , cCommandOutputCallback & a_Output )
2012-06-14 13:06:06 +00:00
{
2012-08-18 10:38:15 +00:00
AStringVector split = StringSplit ( a_Cmd , " " ) ;
if ( split . empty ( ) )
2012-06-14 13:06:06 +00:00
{
return ;
}
2014-01-18 14:59:33 +00:00
2014-08-29 13:43:49 +00:00
// "stop" and "restart" are handled in cRoot::ExecuteConsoleCommand, our caller, due to its access to controlling variables
2015-04-29 16:24:14 +00:00
2013-11-13 14:56:40 +00:00
// "help" and "reload" are to be handled by MCS, so that they work no matter what
if ( split [ 0 ] = = " help " )
{
PrintHelp ( split , a_Output ) ;
2014-08-29 13:43:49 +00:00
a_Output . Finished ( ) ;
2013-11-13 14:56:40 +00:00
return ;
}
2014-08-21 13:29:54 +00:00
else if ( split [ 0 ] = = " reload " )
2014-02-08 23:13:25 +00:00
{
cPluginManager : : Get ( ) - > ReloadPlugins ( ) ;
2014-08-29 13:43:49 +00:00
a_Output . Finished ( ) ;
2014-02-08 23:13:25 +00:00
return ;
}
2014-08-21 13:29:54 +00:00
else if ( split [ 0 ] = = " reloadplugins " )
2013-11-13 14:56:40 +00:00
{
cPluginManager : : Get ( ) - > ReloadPlugins ( ) ;
2014-08-29 13:43:49 +00:00
a_Output . Out ( " Plugins reloaded " ) ;
a_Output . Finished ( ) ;
2013-11-13 14:56:40 +00:00
return ;
}
2014-08-21 13:29:54 +00:00
else if ( split [ 0 ] = = " load " )
2014-05-17 16:38:33 +00:00
{
2014-05-17 17:39:16 +00:00
if ( split . size ( ) > 1 )
{
2015-04-19 15:25:48 +00:00
cPluginManager : : Get ( ) - > RefreshPluginList ( ) ; // Refresh the plugin list, so that if the plugin was added just now, it is loadable
2014-08-29 13:43:49 +00:00
a_Output . Out ( cPluginManager : : Get ( ) - > LoadPlugin ( split [ 1 ] ) ? " Plugin loaded " : " Error occurred loading plugin " ) ;
2014-05-17 17:39:16 +00:00
}
else
{
2015-04-19 08:57:41 +00:00
a_Output . Out ( " Usage: load <PluginFolder> " ) ;
2014-05-17 17:39:16 +00:00
}
2014-08-29 13:43:49 +00:00
a_Output . Finished ( ) ;
return ;
2014-05-17 16:38:33 +00:00
}
2014-08-21 13:29:54 +00:00
else if ( split [ 0 ] = = " unload " )
2014-05-17 17:39:16 +00:00
{
if ( split . size ( ) > 1 )
{
2015-04-19 08:57:41 +00:00
cPluginManager : : Get ( ) - > UnloadPlugin ( split [ 1 ] ) ;
a_Output . Out ( " Plugin unload scheduled " ) ;
2014-05-17 17:39:16 +00:00
}
else
{
2015-04-19 08:57:41 +00:00
a_Output . Out ( " Usage: unload <PluginFolder> " ) ;
2014-05-17 17:39:16 +00:00
}
2014-08-29 13:43:49 +00:00
a_Output . Finished ( ) ;
return ;
}
if ( split [ 0 ] = = " destroyentities " )
{
class WorldCallback : public cWorldListCallback
{
virtual bool Item ( cWorld * a_World ) override
{
class EntityCallback : public cEntityCallback
{
virtual bool Item ( cEntity * a_Entity ) override
{
if ( ! a_Entity - > IsPlayer ( ) )
{
a_Entity - > Destroy ( ) ;
}
return false ;
}
} EC ;
a_World - > ForEachEntity ( EC ) ;
return false ;
}
} WC ;
cRoot : : Get ( ) - > ForEachWorld ( WC ) ;
a_Output . Out ( " Destroyed all entities " ) ;
a_Output . Finished ( ) ;
return ;
2014-05-17 17:39:16 +00:00
}
2014-05-18 15:16:02 +00:00
2013-02-15 13:00:59 +00:00
// There is currently no way a plugin can do these (and probably won't ever be):
2014-08-21 13:29:54 +00:00
else if ( split [ 0 ] . compare ( " chunkstats " ) = = 0 )
2012-06-14 13:06:06 +00:00
{
2013-06-29 15:30:05 +00:00
cRoot : : Get ( ) - > LogChunkStats ( a_Output ) ;
a_Output . Finished ( ) ;
2012-06-14 13:06:06 +00:00
return ;
}
2015-09-28 19:30:31 +00:00
else if ( split [ 0 ] . compare ( " luastats " ) = = 0 )
{
a_Output . Out ( cLuaStateTracker : : GetStats ( ) ) ;
a_Output . Finished ( ) ;
return ;
}
2012-10-19 22:09:33 +00:00
# if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
2014-08-21 13:29:54 +00:00
else if ( split [ 0 ] . compare ( " dumpmem " ) = = 0 )
2012-10-19 22:09:33 +00:00
{
LeakFinderXmlOutput Output ( " memdump.xml " ) ;
DumpUsedMemory ( & Output ) ;
return ;
}
2015-04-29 16:24:14 +00:00
2014-08-21 13:29:54 +00:00
else if ( split [ 0 ] . compare ( " killmem " ) = = 0 )
2013-03-23 19:04:39 +00:00
{
2014-01-07 15:00:19 +00:00
for ( ; ; )
2013-03-23 19:04:39 +00:00
{
new char [ 100 * 1024 * 1024 ] ; // Allocate and leak 100 MiB in a loop -> fill memory and kill MCS
}
}
2012-10-19 22:09:33 +00:00
# endif
2014-01-21 13:58:17 +00:00
2015-03-11 03:14:17 +00:00
else if ( cPluginManager : : Get ( ) - > ExecuteConsoleCommand ( split , a_Output , a_Cmd ) )
2012-11-20 21:28:43 +00:00
{
2013-06-29 15:30:05 +00:00
a_Output . Finished ( ) ;
2012-11-20 21:28:43 +00:00
return ;
}
2015-04-29 16:24:14 +00:00
2013-06-29 15:30:05 +00:00
a_Output . Out ( " Unknown command, type 'help' for all commands. " ) ;
a_Output . Finished ( ) ;
2013-02-15 13:00:59 +00:00
}
2013-11-13 14:56:40 +00:00
void cServer : : PrintHelp ( const AStringVector & a_Split , cCommandOutputCallback & a_Output )
{
2013-12-22 14:42:17 +00:00
UNUSED ( a_Split ) ;
2013-11-13 19:40:18 +00:00
typedef std : : pair < AString , AString > AStringPair ;
typedef std : : vector < AStringPair > AStringPairs ;
2015-04-29 16:24:14 +00:00
2013-11-13 19:40:18 +00:00
class cCallback :
public cPluginManager : : cCommandEnumCallback
{
public :
cCallback ( void ) : m_MaxLen ( 0 ) { }
2015-04-29 16:24:14 +00:00
2013-11-13 19:40:18 +00:00
virtual bool Command ( const AString & a_Command , const cPlugin * a_Plugin , const AString & a_Permission , const AString & a_HelpString ) override
{
2013-12-22 14:42:17 +00:00
UNUSED ( a_Plugin ) ;
UNUSED ( a_Permission ) ;
2013-11-13 19:40:18 +00:00
if ( ! a_HelpString . empty ( ) )
{
m_Commands . push_back ( AStringPair ( a_Command , a_HelpString ) ) ;
if ( m_MaxLen < a_Command . length ( ) )
{
m_MaxLen = a_Command . length ( ) ;
}
}
return false ;
}
2015-04-29 16:24:14 +00:00
2013-11-13 19:40:18 +00:00
AStringPairs m_Commands ;
size_t m_MaxLen ;
} Callback ;
cPluginManager : : Get ( ) - > ForEachConsoleCommand ( Callback ) ;
std : : sort ( Callback . m_Commands . begin ( ) , Callback . m_Commands . end ( ) ) ;
for ( AStringPairs : : const_iterator itr = Callback . m_Commands . begin ( ) , end = Callback . m_Commands . end ( ) ; itr ! = end ; + + itr )
{
const AStringPair & cmd = * itr ;
2015-11-23 17:20:37 +00:00
a_Output . Out ( Printf ( " %-*s - %s \n " , static_cast < int > ( Callback . m_MaxLen ) , cmd . first . c_str ( ) , cmd . second . c_str ( ) ) ) ;
2013-11-13 19:40:18 +00:00
} // for itr - Callback.m_Commands[]
2013-11-13 14:56:40 +00:00
}
2013-02-15 13:00:59 +00:00
void cServer : : BindBuiltInConsoleCommands ( void )
{
cPluginManager * PlgMgr = cPluginManager : : Get ( ) ;
2015-11-22 22:57:53 +00:00
PlgMgr - > BindConsoleCommand ( " help " , nullptr , " Shows the available commands " ) ;
PlgMgr - > BindConsoleCommand ( " reload " , nullptr , " Reloads all plugins " ) ;
PlgMgr - > BindConsoleCommand ( " restart " , nullptr , " Restarts the server cleanly " ) ;
PlgMgr - > BindConsoleCommand ( " stop " , nullptr , " Stops the server cleanly " ) ;
PlgMgr - > BindConsoleCommand ( " chunkstats " , nullptr , " Displays detailed chunk memory statistics " ) ;
PlgMgr - > BindConsoleCommand ( " load <pluginname> " , nullptr , " Adds and enables the specified plugin " ) ;
PlgMgr - > BindConsoleCommand ( " unload <pluginname> " , nullptr , " Disables the specified plugin " ) ;
PlgMgr - > BindConsoleCommand ( " destroyentities " , nullptr , " Destroys all entities in all worlds " ) ;
2014-05-17 17:39:16 +00:00
2013-02-15 13:00:59 +00:00
# if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
2014-10-20 20:55:07 +00:00
PlgMgr - > BindConsoleCommand ( " dumpmem " , nullptr , " - Dumps all used memory blocks together with their callstacks into memdump.xml " ) ;
2013-11-04 21:51:24 +00:00
# endif
2012-06-14 13:06:06 +00:00
}
2013-08-11 17:46:27 +00:00
void cServer : : Shutdown ( void )
2012-06-14 13:06:06 +00:00
{
2015-01-24 19:17:00 +00:00
// Stop listening on all sockets:
for ( auto srv : m_ServerHandles )
{
srv - > Close ( ) ;
}
m_ServerHandles . clear ( ) ;
2015-04-29 16:24:14 +00:00
2015-01-24 19:17:00 +00:00
// Notify the tick thread and wait for it to terminate:
2012-06-14 13:06:06 +00:00
m_bRestarting = true ;
2013-08-11 17:46:27 +00:00
m_RestartEvent . Wait ( ) ;
2012-06-14 13:06:06 +00:00
cRoot : : Get ( ) - > SaveAllChunks ( ) ;
2015-01-24 19:17:00 +00:00
// Remove all clients:
2012-06-14 13:06:06 +00:00
cCSLock Lock ( m_CSClients ) ;
2015-01-24 19:17:00 +00:00
for ( auto itr = m_Clients . begin ( ) ; itr ! = m_Clients . end ( ) ; + + itr )
2012-06-14 13:06:06 +00:00
{
2012-06-19 17:34:22 +00:00
( * itr ) - > Destroy ( ) ;
2012-06-14 13:06:06 +00:00
}
m_Clients . clear ( ) ;
}
void cServer : : KickUser ( int a_ClientID , const AString & a_Reason )
{
cCSLock Lock ( m_CSClients ) ;
2015-01-24 19:17:00 +00:00
for ( auto itr = m_Clients . begin ( ) ; itr ! = m_Clients . end ( ) ; + + itr )
2012-06-14 13:06:06 +00:00
{
if ( ( * itr ) - > GetUniqueID ( ) = = a_ClientID )
{
( * itr ) - > Kick ( a_Reason ) ;
}
} // for itr - m_Clients[]
}
2014-07-15 23:03:47 +00:00
void cServer : : AuthenticateUser ( int a_ClientID , const AString & a_Name , const AString & a_UUID , const Json : : Value & a_Properties )
2012-06-14 13:06:06 +00:00
{
cCSLock Lock ( m_CSClients ) ;
2015-01-24 19:17:00 +00:00
for ( auto itr = m_Clients . begin ( ) ; itr ! = m_Clients . end ( ) ; + + itr )
2012-06-14 13:06:06 +00:00
{
if ( ( * itr ) - > GetUniqueID ( ) = = a_ClientID )
{
2014-07-14 18:49:31 +00:00
( * itr ) - > Authenticate ( a_Name , a_UUID , a_Properties ) ;
2013-08-13 20:45:29 +00:00
return ;
2012-06-14 13:06:06 +00:00
}
} // for itr - m_Clients[]
}