2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 18:09:57 -04:00
# include "Root.h"
# include "Server.h"
# include "World.h"
# include "WebAdmin.h"
# include "FurnaceRecipe.h"
2012-06-14 09:06:06 -04:00
# include "CraftingRecipes.h"
2013-12-08 06:17:54 -05:00
# include "Bindings/PluginManager.h"
2012-09-23 18:09:57 -04:00
# include "MonsterConfig.h"
2013-08-19 05:39:13 -04:00
# include "Entities/Player.h"
2012-09-29 09:59:32 -04:00
# include "Blocks/BlockHandler.h"
# include "Items/ItemHandler.h"
2012-09-23 18:09:57 -04:00
# include "Chunk.h"
2012-10-31 15:54:42 -04:00
# include "Protocol/ProtocolRecognizer.h" // for protocol version constants
2013-06-29 11:30:05 -04:00
# include "CommandOutput.h"
2013-08-14 16:39:12 -04:00
# include "DeadlockDetect.h"
2014-08-12 11:05:04 -04:00
# include "LoggerListeners.h"
2014-09-10 11:07:00 -04:00
# include "BuildInfo.h"
2014-10-23 09:15:10 -04:00
# include "IniFile.h"
2012-06-14 09:06:06 -04:00
2013-10-08 14:12:34 -04:00
# ifdef _WIN32
2014-10-23 09:15:10 -04:00
# include <conio.h>
2013-10-08 14:12:34 -04:00
# include <psapi.h>
# elif defined(__linux__)
# include <fstream>
# elif defined(__APPLE__)
# include <mach/mach.h>
# endif
2012-06-14 09:06:06 -04:00
2015-04-05 11:07:10 -04:00
cRoot * cRoot : : s_Root = nullptr ;
bool cRoot : : m_ShouldStop = false ;
2012-06-14 09:06:06 -04:00
2013-12-20 13:10:07 -05:00
cRoot : : cRoot ( void ) :
2014-10-20 16:55:07 -04:00
m_pDefaultWorld ( nullptr ) ,
m_Server ( nullptr ) ,
m_MonsterConfig ( nullptr ) ,
m_CraftingRecipes ( nullptr ) ,
m_FurnaceRecipe ( nullptr ) ,
m_WebAdmin ( nullptr ) ,
m_PluginManager ( nullptr ) ,
2014-12-22 19:41:46 -05:00
m_MojangAPI ( nullptr ) ,
2013-12-20 13:10:07 -05:00
m_bRestart ( false )
2012-06-14 09:06:06 -04:00
{
s_Root = this ;
}
cRoot : : ~ cRoot ( )
{
s_Root = 0 ;
}
2014-10-19 09:10:18 -04:00
void cRoot : : InputThread ( cRoot & a_Params )
2012-06-14 09:06:06 -04:00
{
2013-06-29 11:30:05 -04:00
cLogCommandOutputCallback Output ;
2015-04-05 11:07:10 -04:00
while ( ! cRoot : : m_ShouldStop & & ! a_Params . m_bRestart & & ! m_TerminateEventRaised & & std : : cin . good ( ) )
2012-06-14 09:06:06 -04:00
{
2013-12-07 17:35:24 -05:00
AString Command ;
2012-06-14 09:06:06 -04:00
std : : getline ( std : : cin , Command ) ;
2013-07-24 16:25:27 -04:00
if ( ! Command . empty ( ) )
2014-07-17 10:33:09 -04:00
{
2014-10-19 09:10:18 -04:00
a_Params . ExecuteConsoleCommand ( TrimString ( Command ) , Output ) ;
2013-07-24 16:25:27 -04:00
}
}
2013-12-22 15:03:58 -05:00
2014-07-19 18:44:19 -04:00
if ( m_TerminateEventRaised | | ! std : : cin . good ( ) )
2013-07-24 16:25:27 -04:00
{
2015-04-05 11:07:10 -04:00
// We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running
// Stop the server:
if ( ! m_RunAsService ) // Dont kill if running as a service
2015-03-31 09:50:03 -04:00
{
2015-04-05 11:07:10 -04:00
a_Params . m_ShouldStop = true ;
2015-03-31 09:50:03 -04:00
}
2012-06-14 09:06:06 -04:00
}
}
2012-11-11 09:15:59 -05:00
void cRoot : : Start ( void )
2012-06-14 09:06:06 -04:00
{
2013-12-22 15:03:58 -05:00
# ifdef _WIN32
HWND hwnd = GetConsoleWindow ( ) ;
HMENU hmenu = GetSystemMenu ( hwnd , FALSE ) ;
2014-07-17 13:13:23 -04:00
EnableMenuItem ( hmenu , SC_CLOSE , MF_GRAYED ) ; // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
2013-12-22 15:03:58 -05:00
# endif
2014-08-10 14:34:11 -04:00
2014-08-12 11:05:04 -04:00
cLogger : : cListener * consoleLogListener = MakeConsoleListener ( ) ;
cLogger : : cListener * fileLogListener = new cFileListener ( ) ;
cLogger : : GetInstance ( ) . AttachListener ( consoleLogListener ) ;
cLogger : : GetInstance ( ) . AttachListener ( fileLogListener ) ;
2014-08-10 14:34:11 -04:00
LOG ( " --- Started Log --- \n " ) ;
2013-12-22 15:03:58 -05:00
2014-09-10 11:07:00 -04:00
# ifdef BUILD_ID
2014-09-17 17:32:14 -04:00
LOG ( " MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID ) ;
LOG ( " from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME ) ;
2014-09-10 11:07:00 -04:00
# endif
2013-08-14 16:39:12 -04:00
cDeadlockDetect dd ;
2012-06-14 09:06:06 -04:00
2015-04-05 11:07:10 -04:00
m_ShouldStop = false ;
while ( ! m_ShouldStop )
2012-06-14 09:06:06 -04:00
{
2014-12-04 16:07:04 -05:00
auto BeginTime = std : : chrono : : steady_clock : : now ( ) ;
2012-06-14 09:06:06 -04:00
m_bRestart = false ;
LoadGlobalSettings ( ) ;
LOG ( " Creating new server instance... " ) ;
m_Server = new cServer ( ) ;
2012-11-11 09:23:47 -05:00
LOG ( " Reading server config... " ) ;
2013-10-25 05:15:44 -04:00
cIniFile IniFile ;
if ( ! IniFile . ReadFile ( " settings.ini " ) )
2012-11-10 10:13:09 -05:00
{
2013-11-04 16:51:24 -05:00
LOGWARN ( " Regenerating settings.ini, all settings will be reset " ) ;
IniFile . AddHeaderComment ( " This is the main server configuration " ) ;
IniFile . AddHeaderComment ( " Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini " ) ;
2014-02-07 06:07:22 -05:00
IniFile . AddHeaderComment ( " See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help " ) ;
2012-11-10 10:13:09 -05:00
}
2013-11-04 16:51:24 -05:00
2012-11-11 09:23:47 -05:00
LOG ( " Starting server... " ) ;
2014-12-21 09:31:20 -05:00
m_MojangAPI = new cMojangAPI ;
2014-10-17 07:57:18 -04:00
bool ShouldAuthenticate = IniFile . GetValueSetB ( " Authentication " , " Authenticate " , true ) ;
2014-12-21 09:31:20 -05:00
m_MojangAPI - > Start ( IniFile , ShouldAuthenticate ) ; // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
2014-10-17 07:57:18 -04:00
if ( ! m_Server - > InitServer ( IniFile , ShouldAuthenticate ) )
2012-06-14 09:06:06 -04:00
{
2014-09-08 12:45:23 -04:00
IniFile . WriteFile ( " settings.ini " ) ;
2013-09-28 15:36:01 -04:00
LOGERROR ( " Failure starting server, aborting... " ) ;
2012-06-14 09:06:06 -04:00
return ;
}
2013-10-05 17:08:16 -04:00
m_WebAdmin = new cWebAdmin ( ) ;
m_WebAdmin - > Init ( ) ;
2012-06-14 09:06:06 -04:00
2013-09-28 15:36:01 -04:00
LOGD ( " Loading settings... " ) ;
2014-11-26 05:00:46 -05:00
m_RankManager . reset ( new cRankManager ( ) ) ;
2014-12-21 09:31:20 -05:00
m_RankManager - > Initialize ( * m_MojangAPI ) ;
2012-06-14 09:06:06 -04:00
m_CraftingRecipes = new cCraftingRecipes ;
2013-08-05 09:24:23 -04:00
m_FurnaceRecipe = new cFurnaceRecipe ( ) ;
2012-06-14 09:06:06 -04:00
2013-09-28 15:36:01 -04:00
LOGD ( " Loading worlds... " ) ;
2013-10-26 11:08:28 -04:00
LoadWorlds ( IniFile ) ;
2012-06-14 09:06:06 -04:00
2013-09-28 15:36:01 -04:00
LOGD ( " Loading plugin manager... " ) ;
2013-02-15 08:00:59 -05:00
m_PluginManager = new cPluginManager ( ) ;
2013-11-04 16:51:24 -05:00
m_PluginManager - > ReloadPluginsNow ( IniFile ) ;
2012-06-14 09:06:06 -04:00
2013-09-28 15:36:01 -04:00
LOGD ( " Loading MonsterConfig... " ) ;
2012-06-14 09:06:06 -04:00
m_MonsterConfig = new cMonsterConfig ;
// This sets stuff in motion
2013-09-28 15:36:01 -04:00
LOGD ( " Starting Authenticator... " ) ;
2013-10-26 11:08:28 -04:00
m_Authenticator . Start ( IniFile ) ;
2012-06-14 09:06:06 -04:00
2013-09-28 15:36:01 -04:00
LOGD ( " Starting worlds... " ) ;
2012-06-14 09:06:06 -04:00
StartWorlds ( ) ;
2013-11-30 16:14:47 -05:00
if ( IniFile . GetValueSetB ( " DeadlockDetect " , " Enabled " , true ) )
{
LOGD ( " Starting deadlock detector... " ) ;
dd . Start ( IniFile . GetValueSetI ( " DeadlockDetect " , " IntervalSec " , 20 ) ) ;
}
2013-08-14 16:39:12 -04:00
2013-11-30 16:14:47 -05:00
IniFile . WriteFile ( " settings.ini " ) ;
2013-09-28 15:36:01 -04:00
LOGD ( " Finalising startup... " ) ;
2015-01-27 07:57:35 -05:00
if ( m_Server - > Start ( ) )
2014-10-18 19:29:34 -04:00
{
2015-01-27 07:57:35 -05:00
m_WebAdmin - > Start ( ) ;
# if !defined(ANDROID_NDK)
LOGD ( " Starting InputThread... " ) ;
try
{
m_InputThread = std : : thread ( InputThread , std : : ref ( * this ) ) ;
m_InputThread . detach ( ) ;
}
catch ( std : : system_error & a_Exception )
{
LOGERROR ( " cRoot::Start (std::thread) error %i: could not construct input thread; %s " , a_Exception . code ( ) . value ( ) , a_Exception . what ( ) ) ;
}
# endif
LOG ( " Startup complete, took %ldms! " , static_cast < long int > ( std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : steady_clock : : now ( ) - BeginTime ) . count ( ) ) ) ;
# ifdef _WIN32
EnableMenuItem ( hmenu , SC_CLOSE , MF_ENABLED ) ; // Re-enable close button
# endif
2015-04-05 11:07:10 -04:00
while ( ! m_ShouldStop & & ! m_bRestart & & ! m_TerminateEventRaised ) // These are modified by external threads
2015-01-27 07:57:35 -05:00
{
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
}
if ( m_TerminateEventRaised )
{
2015-04-05 11:07:10 -04:00
m_ShouldStop = true ;
2015-01-27 07:57:35 -05:00
}
// Stop the server:
m_WebAdmin - > Stop ( ) ;
LOG ( " Shutting down server... " ) ;
m_Server - > Shutdown ( ) ;
} // if (m_Server->Start())
else
2013-12-22 15:03:58 -05:00
{
2015-04-05 11:07:10 -04:00
m_ShouldStop = true ;
2013-12-22 15:03:58 -05:00
}
2014-12-21 09:31:20 -05:00
delete m_MojangAPI ; m_MojangAPI = nullptr ;
2013-09-28 15:36:01 -04:00
LOGD ( " Shutting down deadlock detector... " ) ;
2013-08-14 16:39:12 -04:00
dd . Stop ( ) ;
2014-12-21 09:31:20 -05:00
2013-09-28 15:36:01 -04:00
LOGD ( " Stopping world threads... " ) ;
2012-07-15 16:07:38 -04:00
StopWorlds ( ) ;
2014-12-21 09:31:20 -05:00
2013-09-28 15:36:01 -04:00
LOGD ( " Stopping authenticator... " ) ;
2012-06-14 09:06:06 -04:00
m_Authenticator . Stop ( ) ;
2012-07-15 16:36:34 -04:00
2013-09-28 15:36:01 -04:00
LOGD ( " Freeing MonsterConfig... " ) ;
2014-10-20 16:55:07 -04:00
delete m_MonsterConfig ; m_MonsterConfig = nullptr ;
delete m_WebAdmin ; m_WebAdmin = nullptr ;
2014-12-21 09:31:20 -05:00
2013-09-28 15:36:01 -04:00
LOGD ( " Unloading recipes... " ) ;
2014-10-20 16:55:07 -04:00
delete m_FurnaceRecipe ; m_FurnaceRecipe = nullptr ;
delete m_CraftingRecipes ; m_CraftingRecipes = nullptr ;
2014-12-21 09:31:20 -05:00
2013-09-28 15:36:01 -04:00
LOGD ( " Unloading worlds... " ) ;
2012-06-14 09:06:06 -04:00
UnloadWorlds ( ) ;
2012-07-15 16:36:34 -04:00
2013-09-28 15:36:01 -04:00
LOGD ( " Stopping plugin manager... " ) ;
2014-10-20 16:55:07 -04:00
delete m_PluginManager ; m_PluginManager = nullptr ;
2013-02-05 14:57:22 -05:00
2012-07-15 16:36:34 -04:00
cItemHandler : : Deinit ( ) ;
2013-09-28 15:36:01 -04:00
LOG ( " Cleaning up... " ) ;
2014-10-20 16:55:07 -04:00
delete m_Server ; m_Server = nullptr ;
2014-12-21 09:31:20 -05:00
2013-09-28 15:36:01 -04:00
LOG ( " Shutdown successful! " ) ;
2012-06-14 09:06:06 -04:00
}
2014-08-10 14:34:11 -04:00
LOG ( " --- Stopped Log --- " ) ;
2014-08-12 11:05:04 -04:00
cLogger : : GetInstance ( ) . DetachListener ( consoleLogListener ) ;
2014-08-10 14:34:11 -04:00
delete consoleLogListener ;
2014-08-12 11:05:04 -04:00
cLogger : : GetInstance ( ) . DetachListener ( fileLogListener ) ;
2014-08-10 14:34:11 -04:00
delete fileLogListener ;
2012-06-14 09:06:06 -04:00
}
void cRoot : : LoadGlobalSettings ( )
{
2012-10-06 16:04:58 -04:00
// Nothing needed yet
2012-06-14 09:06:06 -04:00
}
2013-10-26 13:47:12 -04:00
void cRoot : : LoadWorlds ( cIniFile & IniFile )
2012-06-14 09:06:06 -04:00
{
// First get the default world
AString DefaultWorldName = IniFile . GetValueSet ( " Worlds " , " DefaultWorld " , " world " ) ;
2014-07-26 18:39:39 -04:00
m_pDefaultWorld = new cWorld ( DefaultWorldName . c_str ( ) ) ;
2012-08-22 07:22:26 -04:00
m_WorldsByName [ DefaultWorldName ] = m_pDefaultWorld ;
2012-06-14 09:06:06 -04:00
// Then load the other worlds
2014-08-10 14:34:11 -04:00
int KeyNum = IniFile . FindKey ( " Worlds " ) ;
int NumWorlds = IniFile . GetNumValues ( KeyNum ) ;
2012-06-14 09:06:06 -04:00
if ( NumWorlds < = 0 )
{
return ;
}
2013-11-04 16:51:24 -05:00
bool FoundAdditionalWorlds = false ;
2014-08-10 14:34:11 -04:00
for ( int i = 0 ; i < NumWorlds ; i + + )
2012-06-14 09:06:06 -04:00
{
2014-07-21 09:19:48 -04:00
AString ValueName = IniFile . GetValueName ( KeyNum , i ) ;
2012-06-14 09:06:06 -04:00
if ( ValueName . compare ( " World " ) ! = 0 )
{
continue ;
}
2014-07-21 09:19:48 -04:00
AString WorldName = IniFile . GetValue ( KeyNum , i ) ;
2012-06-14 09:06:06 -04:00
if ( WorldName . empty ( ) )
{
continue ;
}
2013-11-04 16:51:24 -05:00
FoundAdditionalWorlds = true ;
2014-07-21 09:19:48 -04:00
cWorld * NewWorld = new cWorld ( WorldName . c_str ( ) ) ;
2012-08-22 07:22:26 -04:00
m_WorldsByName [ WorldName ] = NewWorld ;
2012-06-14 09:06:06 -04:00
} // for i - Worlds
2013-11-04 16:51:24 -05:00
if ( ! FoundAdditionalWorlds )
{
2013-11-07 17:33:46 -05:00
if ( IniFile . GetKeyComment ( " Worlds " , 0 ) ! = " World=secondworld " )
{
2014-03-28 19:07:50 -04:00
IniFile . DeleteKeyComment ( " Worlds " , 0 ) ;
2013-11-07 17:33:46 -05:00
IniFile . AddKeyComment ( " Worlds " , " World=secondworld " ) ;
}
2013-11-04 16:51:24 -05:00
}
2012-06-14 09:06:06 -04:00
}
2014-06-10 15:43:27 -04:00
cWorld * cRoot : : CreateAndInitializeWorld ( const AString & a_WorldName , eDimension a_Dimension , const AString & a_OverworldName )
2013-12-11 06:39:13 -05:00
{
2014-07-22 12:26:48 -04:00
cWorld * World = m_WorldsByName [ a_WorldName ] ;
2014-10-20 16:55:07 -04:00
if ( World ! = nullptr )
2013-12-11 06:39:13 -05:00
{
2014-07-22 12:26:48 -04:00
return World ;
2013-12-11 06:39:13 -05:00
}
2014-07-22 12:26:48 -04:00
2014-06-10 15:43:27 -04:00
cWorld * NewWorld = new cWorld ( a_WorldName . c_str ( ) , a_Dimension , a_OverworldName ) ;
2013-12-11 06:39:13 -05:00
m_WorldsByName [ a_WorldName ] = NewWorld ;
NewWorld - > Start ( ) ;
NewWorld - > InitializeSpawn ( ) ;
2013-12-11 10:19:38 -05:00
m_PluginManager - > CallHookWorldStarted ( * NewWorld ) ;
2013-12-11 06:39:13 -05:00
return NewWorld ;
}
2012-06-14 09:06:06 -04:00
void cRoot : : StartWorlds ( void )
{
2013-08-11 14:16:41 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) ; itr ! = m_WorldsByName . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2013-08-11 14:16:41 -04:00
itr - > second - > Start ( ) ;
2012-06-14 09:06:06 -04:00
itr - > second - > InitializeSpawn ( ) ;
2013-12-11 06:39:13 -05:00
m_PluginManager - > CallHookWorldStarted ( * itr - > second ) ;
2012-06-14 09:06:06 -04:00
}
}
2012-07-15 16:07:38 -04:00
void cRoot : : StopWorlds ( void )
{
2013-08-11 14:16:41 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) ; itr ! = m_WorldsByName . end ( ) ; + + itr )
2012-07-15 16:07:38 -04:00
{
2013-08-11 14:16:41 -04:00
itr - > second - > Stop ( ) ;
2012-07-15 16:07:38 -04:00
}
}
2012-06-14 09:06:06 -04:00
void cRoot : : UnloadWorlds ( void )
{
2014-10-20 16:55:07 -04:00
m_pDefaultWorld = nullptr ;
2014-07-21 09:19:48 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) ; itr ! = m_WorldsByName . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
delete itr - > second ;
}
2012-08-22 07:22:26 -04:00
m_WorldsByName . clear ( ) ;
2012-06-14 09:06:06 -04:00
}
2014-05-31 17:28:51 -04:00
cWorld * cRoot : : GetDefaultWorld ( )
2012-06-14 09:06:06 -04:00
{
2012-08-22 07:22:26 -04:00
return m_pDefaultWorld ;
2012-06-14 09:06:06 -04:00
}
2014-07-20 05:46:45 -04:00
cWorld * cRoot : : GetWorld ( const AString & a_WorldName , bool a_SearchForFolder )
2012-06-14 09:06:06 -04:00
{
2014-05-31 17:28:51 -04:00
WorldMap : : iterator itr = m_WorldsByName . find ( a_WorldName ) ;
2014-07-21 09:19:48 -04:00
if ( itr ! = m_WorldsByName . end ( ) )
2014-05-31 17:28:51 -04:00
{
2012-06-14 09:06:06 -04:00
return itr - > second ;
2014-05-31 17:28:51 -04:00
}
2014-07-20 05:46:45 -04:00
if ( a_SearchForFolder & & cFile : : IsFolder ( FILE_IO_PREFIX + a_WorldName ) )
{
return CreateAndInitializeWorld ( a_WorldName ) ;
}
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-06-14 09:06:06 -04:00
}
bool cRoot : : ForEachWorld ( cWorldListCallback & a_Callback )
{
2012-08-22 07:22:26 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) , itr2 = itr ; itr ! = m_WorldsByName . end ( ) ; itr = itr2 )
2012-06-14 09:06:06 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2014-10-20 16:55:07 -04:00
if ( itr - > second ! = nullptr )
2012-06-14 09:06:06 -04:00
{
2014-05-31 17:28:51 -04:00
if ( a_Callback . Item ( itr - > second ) )
{
return false ;
}
2012-06-14 09:06:06 -04:00
}
}
return true ;
}
2013-08-11 14:16:41 -04:00
void cRoot : : TickCommands ( void )
2012-06-14 09:06:06 -04:00
{
2013-04-27 17:05:34 -04:00
// Execute any pending commands:
2013-06-29 11:30:05 -04:00
cCommandQueue PendingCommands ;
2013-04-27 17:05:34 -04:00
{
cCSLock Lock ( m_CSPendingCommands ) ;
std : : swap ( PendingCommands , m_PendingCommands ) ;
}
2013-06-29 11:30:05 -04:00
for ( cCommandQueue : : iterator itr = PendingCommands . begin ( ) , end = PendingCommands . end ( ) ; itr ! = end ; + + itr )
2013-04-27 17:05:34 -04:00
{
2013-06-29 11:30:05 -04:00
ExecuteConsoleCommand ( itr - > m_Command , * ( itr - > m_Output ) ) ;
2013-04-27 17:05:34 -04:00
}
2012-06-14 09:06:06 -04:00
}
2013-06-29 11:30:05 -04:00
void cRoot : : QueueExecuteConsoleCommand ( const AString & a_Cmd , cCommandOutputCallback & a_Output )
{
// Some commands are built-in:
if ( a_Cmd = = " stop " )
{
2015-04-05 11:07:10 -04:00
m_ShouldStop = true ;
2013-06-29 11:30:05 -04:00
}
else if ( a_Cmd = = " restart " )
{
m_bRestart = true ;
}
// Put the command into a queue (Alleviates FS #363):
cCSLock Lock ( m_CSPendingCommands ) ;
m_PendingCommands . push_back ( cCommand ( a_Cmd , & a_Output ) ) ;
}
void cRoot : : QueueExecuteConsoleCommand ( const AString & a_Cmd )
2013-04-27 17:05:34 -04:00
{
// Put the command into a queue (Alleviates FS #363):
cCSLock Lock ( m_CSPendingCommands ) ;
2013-06-29 11:30:05 -04:00
m_PendingCommands . push_back ( cCommand ( a_Cmd , new cLogCommandDeleteSelfOutputCallback ) ) ;
2013-04-27 17:05:34 -04:00
}
2013-06-29 11:30:05 -04:00
void cRoot : : ExecuteConsoleCommand ( const AString & a_Cmd , cCommandOutputCallback & a_Output )
2012-06-14 09:06:06 -04:00
{
2014-08-29 09:43:49 -04:00
// cRoot handles stopping and restarting due to our access to controlling variables
2013-06-29 11:30:05 -04:00
if ( a_Cmd = = " stop " )
{
2015-04-05 11:07:10 -04:00
m_ShouldStop = true ;
2014-08-29 09:43:49 -04:00
return ;
2013-06-29 11:30:05 -04:00
}
else if ( a_Cmd = = " restart " )
{
m_bRestart = true ;
2014-08-29 09:43:49 -04:00
return ;
2013-06-29 11:30:05 -04:00
}
2013-02-15 08:00:59 -05:00
LOG ( " Executing console command: \" %s \" " , a_Cmd . c_str ( ) ) ;
2013-06-29 11:30:05 -04:00
m_Server - > ExecuteConsoleCommand ( a_Cmd , a_Output ) ;
2012-06-14 09:06:06 -04:00
}
void cRoot : : KickUser ( int a_ClientID , const AString & a_Reason )
{
m_Server - > KickUser ( a_ClientID , a_Reason ) ;
}
2014-07-15 19:03:47 -04:00
void cRoot : : AuthenticateUser ( int a_ClientID , const AString & a_Name , const AString & a_UUID , const Json : : Value & a_Properties )
2012-06-14 09:06:06 -04:00
{
2014-07-14 14:49:31 -04:00
m_Server - > AuthenticateUser ( a_ClientID , a_Name , a_UUID , a_Properties ) ;
2012-06-14 09:06:06 -04:00
}
int cRoot : : GetTotalChunkCount ( void )
{
int res = 0 ;
2014-07-21 09:19:48 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) ; itr ! = m_WorldsByName . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
res + = itr - > second - > GetNumChunks ( ) ;
}
return res ;
}
void cRoot : : SaveAllChunks ( void )
{
2012-08-22 07:22:26 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) ; itr ! = m_WorldsByName . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2013-11-15 04:13:32 -05:00
itr - > second - > QueueSaveAllChunks ( ) ;
2012-06-14 09:06:06 -04:00
}
}
2014-02-15 17:26:19 -05:00
void cRoot : : BroadcastChat ( const AString & a_Message , eMessageType a_ChatPrefix )
2013-08-17 17:58:37 -04:00
{
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) , end = m_WorldsByName . end ( ) ; itr ! = end ; + + itr )
{
2014-10-20 16:55:07 -04:00
itr - > second - > BroadcastChat ( a_Message , nullptr , a_ChatPrefix ) ;
2013-08-17 17:58:37 -04:00
} // for itr - m_WorldsByName[]
2014-02-15 17:16:44 -05:00
}
void cRoot : : BroadcastChat ( const cCompositeChat & a_Message )
{
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) , end = m_WorldsByName . end ( ) ; itr ! = end ; + + itr )
{
itr - > second - > BroadcastChat ( a_Message ) ;
} // for itr - m_WorldsByName[]
2013-08-17 17:58:37 -04:00
}
2012-06-14 09:06:06 -04:00
bool cRoot : : ForEachPlayer ( cPlayerListCallback & a_Callback )
{
2012-08-22 07:22:26 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) , itr2 = itr ; itr ! = m_WorldsByName . end ( ) ; itr = itr2 )
2012-06-14 09:06:06 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2012-06-14 09:06:06 -04:00
if ( ! itr - > second - > ForEachPlayer ( a_Callback ) )
{
return false ;
}
}
return true ;
}
2012-08-15 08:08:11 -04:00
2012-08-22 19:05:12 -04:00
bool cRoot : : FindAndDoWithPlayer ( const AString & a_PlayerName , cPlayerListCallback & a_Callback )
{
class cCallback : public cPlayerListCallback
{
2014-05-08 14:16:35 -04:00
size_t m_BestRating ;
size_t m_NameLength ;
2013-12-20 13:10:07 -05:00
const AString m_PlayerName ;
2012-08-22 19:05:12 -04:00
virtual bool Item ( cPlayer * a_pPlayer )
{
2014-05-08 14:16:35 -04:00
size_t Rating = RateCompareString ( m_PlayerName , a_pPlayer - > GetName ( ) ) ;
2013-12-20 13:10:07 -05:00
if ( ( Rating > 0 ) & & ( Rating > = m_BestRating ) )
2012-08-22 19:05:12 -04:00
{
2015-04-24 07:45:44 -04:00
m_BestMatch = a_pPlayer - > GetName ( ) ;
2013-12-20 13:10:07 -05:00
if ( Rating > m_BestRating )
{
m_NumMatches = 0 ;
}
m_BestRating = Rating ;
+ + m_NumMatches ;
2012-08-22 19:05:12 -04:00
}
2014-07-17 13:13:23 -04:00
if ( Rating = = m_NameLength ) // Perfect match
2012-08-22 19:05:12 -04:00
{
2013-11-10 16:58:14 -05:00
return true ;
2012-08-22 19:05:12 -04:00
}
2013-11-10 16:58:14 -05:00
return false ;
2012-08-22 19:05:12 -04:00
}
public :
2014-03-08 11:33:38 -05:00
cCallback ( const AString & a_PlayerName ) :
2013-12-20 13:10:07 -05:00
m_BestRating ( 0 ) ,
m_NameLength ( a_PlayerName . length ( ) ) ,
m_PlayerName ( a_PlayerName ) ,
2015-04-24 07:45:44 -04:00
m_BestMatch ( ) ,
2013-12-20 13:10:07 -05:00
m_NumMatches ( 0 )
2012-08-22 19:05:12 -04:00
{ }
2015-04-24 07:45:44 -04:00
AString m_BestMatch ;
2013-12-20 13:10:07 -05:00
unsigned m_NumMatches ;
2014-03-08 11:33:38 -05:00
} Callback ( a_PlayerName ) ;
2014-05-08 14:16:35 -04:00
ForEachPlayer ( Callback ) ;
2012-08-22 19:05:12 -04:00
2013-12-20 13:10:07 -05:00
if ( Callback . m_NumMatches = = 1 )
2012-08-22 19:05:12 -04:00
{
2015-04-24 07:45:44 -04:00
return DoWithPlayer ( Callback . m_BestMatch , a_Callback ) ;
2012-08-22 19:05:12 -04:00
}
return false ;
}
2014-11-05 15:57:38 -05:00
bool cRoot : : DoWithPlayerByUUID ( const AString & a_PlayerUUID , cPlayerListCallback & a_Callback )
2014-11-12 15:59:42 -05:00
{
2015-01-17 08:00:12 -05:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) ; itr ! = m_WorldsByName . end ( ) ; + + itr )
2014-11-02 15:01:23 -05:00
{
2014-11-05 15:57:38 -05:00
if ( itr - > second - > DoWithPlayerByUUID ( a_PlayerUUID , a_Callback ) )
2014-11-02 15:01:23 -05:00
{
return true ;
}
}
return false ;
}
2014-12-08 03:45:29 -05:00
bool cRoot : : DoWithPlayer ( const AString & a_PlayerName , cPlayerListCallback & a_Callback )
2014-12-08 03:12:48 -05:00
{
2014-12-08 18:58:46 -05:00
for ( auto World : m_WorldsByName )
2014-12-08 03:57:46 -05:00
{
2014-12-08 18:58:46 -05:00
if ( World . second - > DoWithPlayer ( a_PlayerName , a_Callback ) )
2014-12-08 03:57:46 -05:00
{
return true ;
}
}
return false ;
2014-12-08 03:12:48 -05:00
}
2013-02-15 08:00:59 -05:00
AString cRoot : : GetProtocolVersionTextFromInt ( int a_ProtocolVersion )
{
return cProtocolRecognizer : : GetVersionTextFromInt ( a_ProtocolVersion ) ;
}
2013-10-08 14:12:34 -04:00
int cRoot : : GetVirtualRAMUsage ( void )
{
# ifdef _WIN32
PROCESS_MEMORY_COUNTERS_EX pmc ;
if ( GetProcessMemoryInfo ( GetCurrentProcess ( ) , ( PROCESS_MEMORY_COUNTERS * ) & pmc , sizeof ( pmc ) ) )
{
return ( int ) ( pmc . PrivateUsage / 1024 ) ;
}
return - 1 ;
# elif defined(__linux__)
// Code adapted from http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
std : : ifstream StatFile ( " /proc/self/status " ) ;
if ( ! StatFile . good ( ) )
{
return - 1 ;
}
while ( StatFile . good ( ) )
{
AString Line ;
std : : getline ( StatFile , Line ) ;
if ( strncmp ( Line . c_str ( ) , " VmSize: " , 7 ) = = 0 )
{
int res = atoi ( Line . c_str ( ) + 8 ) ;
return ( res = = 0 ) ? - 1 : res ; // If parsing failed, return -1
}
}
return - 1 ;
# elif defined (__APPLE__)
// Code adapted from http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
struct task_basic_info t_info ;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT ;
if ( KERN_SUCCESS = = task_info (
mach_task_self ( ) ,
TASK_BASIC_INFO ,
( task_info_t ) & t_info ,
& t_info_count
) )
{
2014-07-17 10:33:09 -04:00
return ( int ) ( t_info . virtual_size / 1024 ) ;
2013-10-08 14:12:34 -04:00
}
return - 1 ;
# else
LOGINFO ( " %s: Unknown platform, cannot query memory usage " , __FUNCTION__ ) ;
return - 1 ;
# endif
}
int cRoot : : GetPhysicalRAMUsage ( void )
{
# ifdef _WIN32
PROCESS_MEMORY_COUNTERS pmc ;
if ( GetProcessMemoryInfo ( GetCurrentProcess ( ) , & pmc , sizeof ( pmc ) ) )
{
return ( int ) ( pmc . WorkingSetSize / 1024 ) ;
}
return - 1 ;
# elif defined(__linux__)
// Code adapted from http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
std : : ifstream StatFile ( " /proc/self/status " ) ;
if ( ! StatFile . good ( ) )
{
return - 1 ;
}
while ( StatFile . good ( ) )
{
AString Line ;
std : : getline ( StatFile , Line ) ;
2014-01-01 04:18:56 -05:00
if ( strncmp ( Line . c_str ( ) , " VmRSS: " , 6 ) = = 0 )
2013-10-08 14:12:34 -04:00
{
2014-01-01 04:18:56 -05:00
int res = atoi ( Line . c_str ( ) + 7 ) ;
2013-10-08 14:12:34 -04:00
return ( res = = 0 ) ? - 1 : res ; // If parsing failed, return -1
}
}
return - 1 ;
# elif defined (__APPLE__)
// Code adapted from http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
struct task_basic_info t_info ;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT ;
if ( KERN_SUCCESS = = task_info (
mach_task_self ( ) ,
TASK_BASIC_INFO ,
( task_info_t ) & t_info ,
& t_info_count
) )
{
2014-07-17 10:33:09 -04:00
return ( int ) ( t_info . resident_size / 1024 ) ;
2013-10-08 14:12:34 -04:00
}
return - 1 ;
# else
LOGINFO ( " %s: Unknown platform, cannot query memory usage " , __FUNCTION__ ) ;
return - 1 ;
# endif
}
2013-06-29 11:30:05 -04:00
void cRoot : : LogChunkStats ( cCommandOutputCallback & a_Output )
2012-08-15 08:08:11 -04:00
{
int SumNumValid = 0 ;
int SumNumDirty = 0 ;
int SumNumInLighting = 0 ;
int SumNumInGenerator = 0 ;
int SumMem = 0 ;
2012-08-22 07:22:26 -04:00
for ( WorldMap : : iterator itr = m_WorldsByName . begin ( ) , end = m_WorldsByName . end ( ) ; itr ! = end ; + + itr )
2012-08-15 08:08:11 -04:00
{
cWorld * World = itr - > second ;
int NumInGenerator = World - > GetGeneratorQueueLength ( ) ;
2014-05-08 14:16:35 -04:00
int NumInSaveQueue = ( int ) World - > GetStorageSaveQueueLength ( ) ;
int NumInLoadQueue = ( int ) World - > GetStorageLoadQueueLength ( ) ;
2012-08-15 08:08:11 -04:00
int NumValid = 0 ;
int NumDirty = 0 ;
int NumInLighting = 0 ;
World - > GetChunkStats ( NumValid , NumDirty , NumInLighting ) ;
2013-06-29 11:30:05 -04:00
a_Output . Out ( " World %s: " , World - > GetName ( ) . c_str ( ) ) ;
a_Output . Out ( " Num loaded chunks: %d " , NumValid ) ;
a_Output . Out ( " Num dirty chunks: %d " , NumDirty ) ;
a_Output . Out ( " Num chunks in lighting queue: %d " , NumInLighting ) ;
a_Output . Out ( " Num chunks in generator queue: %d " , NumInGenerator ) ;
a_Output . Out ( " Num chunks in storage load queue: %d " , NumInLoadQueue ) ;
a_Output . Out ( " Num chunks in storage save queue: %d " , NumInSaveQueue ) ;
2012-08-15 08:08:11 -04:00
int Mem = NumValid * sizeof ( cChunk ) ;
2013-06-29 11:30:05 -04:00
a_Output . Out ( " Memory used by chunks: %d KiB (%d MiB) " , ( Mem + 1023 ) / 1024 , ( Mem + 1024 * 1024 - 1 ) / ( 1024 * 1024 ) ) ;
a_Output . Out ( " Per-chunk memory size breakdown: " ) ;
2014-03-12 13:34:50 -04:00
a_Output . Out ( " block types: " SIZE_T_FMT_PRECISION ( 6 ) " bytes ( " SIZE_T_FMT_PRECISION ( 3 ) " KiB) " , sizeof ( cChunkDef : : BlockTypes ) , ( sizeof ( cChunkDef : : BlockTypes ) + 1023 ) / 1024 ) ;
a_Output . Out ( " block metadata: " SIZE_T_FMT_PRECISION ( 6 ) " bytes ( " SIZE_T_FMT_PRECISION ( 3 ) " KiB) " , sizeof ( cChunkDef : : BlockNibbles ) , ( sizeof ( cChunkDef : : BlockNibbles ) + 1023 ) / 1024 ) ;
a_Output . Out ( " block lighting: " SIZE_T_FMT_PRECISION ( 6 ) " bytes ( " SIZE_T_FMT_PRECISION ( 3 ) " KiB) " , 2 * sizeof ( cChunkDef : : BlockNibbles ) , ( 2 * sizeof ( cChunkDef : : BlockNibbles ) + 1023 ) / 1024 ) ;
a_Output . Out ( " heightmap: " SIZE_T_FMT_PRECISION ( 6 ) " bytes ( " SIZE_T_FMT_PRECISION ( 3 ) " KiB) " , sizeof ( cChunkDef : : HeightMap ) , ( sizeof ( cChunkDef : : HeightMap ) + 1023 ) / 1024 ) ;
a_Output . Out ( " biomemap: " SIZE_T_FMT_PRECISION ( 6 ) " bytes ( " SIZE_T_FMT_PRECISION ( 3 ) " KiB) " , sizeof ( cChunkDef : : BiomeMap ) , ( sizeof ( cChunkDef : : BiomeMap ) + 1023 ) / 1024 ) ;
2012-08-15 08:08:11 -04:00
SumNumValid + = NumValid ;
SumNumDirty + = NumDirty ;
SumNumInLighting + = NumInLighting ;
SumNumInGenerator + = NumInGenerator ;
SumMem + = Mem ;
}
2013-06-29 11:30:05 -04:00
a_Output . Out ( " Totals: " ) ;
a_Output . Out ( " Num loaded chunks: %d " , SumNumValid ) ;
a_Output . Out ( " Num dirty chunks: %d " , SumNumDirty ) ;
a_Output . Out ( " Num chunks in lighting queue: %d " , SumNumInLighting ) ;
a_Output . Out ( " Num chunks in generator queue: %d " , SumNumInGenerator ) ;
a_Output . Out ( " Memory used by chunks: %d KiB (%d MiB) " , ( SumMem + 1023 ) / 1024 , ( SumMem + 1024 * 1024 - 1 ) / ( 1024 * 1024 ) ) ;
2012-08-15 08:08:11 -04:00
}
2013-11-22 10:50:03 -05:00
int cRoot : : GetFurnaceFuelBurnTime ( const cItem & a_Fuel )
{
cFurnaceRecipe * FR = Get ( ) - > GetFurnaceRecipe ( ) ;
return FR - > GetBurnTime ( a_Fuel ) ;
}