Exemple #1
0
void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
{
	#ifdef _WIN32
	HWND hwnd = GetConsoleWindow();
	HMENU hmenu = GetSystemMenu(hwnd, FALSE);
	EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED);  // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
	#endif

	cLogger::cListener * consoleLogListener = MakeConsoleListener();
	cLogger::cListener * fileLogListener = new cFileListener();
	cLogger::GetInstance().AttachListener(consoleLogListener);
	cLogger::GetInstance().AttachListener(fileLogListener);

	LOG("--- Started Log ---\n");

	#ifdef BUILD_ID
	LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID);
	LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME);
	#endif

	cDeadlockDetect dd;

	m_ShouldStop = false;
	while (!m_ShouldStop)
	{
		auto BeginTime = std::chrono::steady_clock::now();
		m_bRestart = false;

		LoadGlobalSettings();

		LOG("Creating new server instance...");
		m_Server = new cServer();

		LOG("Reading server config...");

		auto IniFile = cpp14::make_unique<cIniFile>();
		if (!IniFile->ReadFile("settings.ini"))
		{
			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");
			IniFile->AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help");
		}
		auto settingsRepo = cpp14::make_unique<cOverridesSettingsRepository>(std::move(IniFile), std::move(overridesRepo));

		LOG("Starting server...");
		m_MojangAPI = new cMojangAPI;
		bool ShouldAuthenticate = settingsRepo->GetValueSetB("Authentication", "Authenticate", true);
		m_MojangAPI->Start(*settingsRepo, ShouldAuthenticate);  // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
		if (!m_Server->InitServer(*settingsRepo, ShouldAuthenticate))
		{
			settingsRepo->Flush();
			LOGERROR("Failure starting server, aborting...");
			return;
		}

		m_WebAdmin = new cWebAdmin();
		m_WebAdmin->Init();

		LOGD("Loading settings...");
		m_RankManager.reset(new cRankManager());
		m_RankManager->Initialize(*m_MojangAPI);
		m_CraftingRecipes = new cCraftingRecipes;
		m_FurnaceRecipe   = new cFurnaceRecipe();

		LOGD("Loading worlds...");
		LoadWorlds(*settingsRepo);

		LOGD("Loading plugin manager...");
		m_PluginManager = new cPluginManager();
		m_PluginManager->ReloadPluginsNow(*settingsRepo);

		LOGD("Loading MonsterConfig...");
		m_MonsterConfig = new cMonsterConfig;

		// This sets stuff in motion
		LOGD("Starting Authenticator...");
		m_Authenticator.Start(*settingsRepo);

		LOGD("Starting worlds...");
		StartWorlds();

		if (settingsRepo->GetValueSetB("DeadlockDetect", "Enabled", true))
		{
			LOGD("Starting deadlock detector...");
			dd.Start(settingsRepo->GetValueSetI("DeadlockDetect", "IntervalSec", 20));
		}

		settingsRepo->Flush();

		LOGD("Finalising startup...");
		if (m_Server->Start())
		{
			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()));

			// Save the current time
			m_StartTime = std::chrono::steady_clock::now();

			#ifdef _WIN32
			EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED);  // Re-enable close button
			#endif

			while (!m_ShouldStop && !m_bRestart && !m_TerminateEventRaised)  // These are modified by external threads
			{
				std::this_thread::sleep_for(std::chrono::seconds(1));
			}

			if (m_TerminateEventRaised)
			{
				m_ShouldStop = true;
			}

			// Stop the server:
			m_WebAdmin->Stop();

			LOG("Shutting down server...");
			m_Server->Shutdown();
		}  // if (m_Server->Start())
		else
		{
			m_ShouldStop = true;
		}

		delete m_MojangAPI; m_MojangAPI = nullptr;

		LOGD("Shutting down deadlock detector...");
		dd.Stop();

		LOGD("Stopping world threads...");
		StopWorlds();

		LOGD("Stopping authenticator...");
		m_Authenticator.Stop();

		LOGD("Freeing MonsterConfig...");
		delete m_MonsterConfig; m_MonsterConfig = nullptr;
		delete m_WebAdmin; m_WebAdmin = nullptr;

		LOGD("Unloading recipes...");
		delete m_FurnaceRecipe;   m_FurnaceRecipe = nullptr;
		delete m_CraftingRecipes; m_CraftingRecipes = nullptr;

		LOGD("Unloading worlds...");
		UnloadWorlds();

		LOGD("Stopping plugin manager...");
		delete m_PluginManager; m_PluginManager = nullptr;

		cItemHandler::Deinit();

		LOG("Cleaning up...");
		delete m_Server; m_Server = nullptr;

		LOG("Shutdown successful!");
	}

	LOG("--- Stopped Log ---");

	cLogger::GetInstance().DetachListener(consoleLogListener);
	delete consoleLogListener;
	cLogger::GetInstance().DetachListener(fileLogListener);
	delete fileLogListener;
}
Exemple #2
0
void cRoot::Start(void)
{
	cDeadlockDetect dd;
	delete m_Log;
	m_Log = new cMCLogger();

	m_bStop = false;
	while (!m_bStop)
	{
		m_bRestart = false;

		LoadGlobalSettings();

		LOG("Creating new server instance...");
		m_Server = new cServer();

		LOG("Reading server config...");
		cIniFile IniFile("settings.ini");
		if (!IniFile.ReadFile())
		{
			LOGWARNING("settings.ini inaccessible, all settings are reset to default values");
		}
		m_PrimaryServerVersion = IniFile.GetValueI("Server", "PrimaryServerVersion", 0);
		if (m_PrimaryServerVersion == 0)
		{
			m_PrimaryServerVersion = cProtocolRecognizer::PROTO_VERSION_LATEST;
		}
		else
		{
			// Make a note in the log that the primary server version is explicitly set in the ini file
			LOGINFO("settings.ini: [Server].PrimaryServerVersion set to %d.", m_PrimaryServerVersion);
		}

		LOG("Starting server...");
		if (!m_Server->InitServer(IniFile))
		{
			LOGERROR("Failed to start server, shutting down.");
			return;
		}
		IniFile.WriteFile();

		cIniFile WebIniFile("webadmin.ini");
		if (!WebIniFile.ReadFile())
		{
			LOGWARNING("webadmin.ini inaccessible, wabadmin is disabled");
		}

		if (WebIniFile.GetValueB("WebAdmin", "Enabled", false))
		{
			LOG("Creating WebAdmin...");
			m_WebAdmin = new cWebAdmin(8080);
		}

		LOG("Loading settings...");
		m_GroupManager    = new cGroupManager();
		m_CraftingRecipes = new cCraftingRecipes;
		m_FurnaceRecipe   = new cFurnaceRecipe();
		
		LOG("Loading worlds...");
		LoadWorlds();

		LOG("Loading plugin manager...");
		m_PluginManager = new cPluginManager();
		m_PluginManager->ReloadPluginsNow();
		
		LOG("Loading MonsterConfig...");
		m_MonsterConfig = new cMonsterConfig;

		// This sets stuff in motion
		LOG("Starting Authenticator...");
		m_Authenticator.Start();
		
		LOG("Starting worlds...");
		StartWorlds();
		
		LOG("Starting deadlock detector...");
		dd.Start();
		
		LOG("Starting server...");
		m_Server->Start();

		#if !defined(ANDROID_NDK)
		LOG("Starting InputThread...");
		m_InputThread = new cThread( InputThread, this, "cRoot::InputThread" );
		m_InputThread->Start( false );	// We should NOT wait? Otherwise we can´t stop the server from other threads than the input thread
		#endif

		LOG("Initialization done, server running now.");
		while (!m_bStop && !m_bRestart)  // These are modified by external threads
		{
			cSleep::MilliSleep(1000);
		}

		#if !defined(ANDROID_NDK)
		delete m_InputThread; m_InputThread = NULL;
		#endif

		// Deallocate stuffs
		LOG("Shutting down server...");
		m_Server->Shutdown();
		
		LOG("Shutting down deadlock detector...");
		dd.Stop();
		
		LOG("Stopping world threads...");
		StopWorlds();
		
		LOG("Stopping authenticator...");
		m_Authenticator.Stop();

		LOG("Freeing MonsterConfig...");
		delete m_MonsterConfig; m_MonsterConfig = NULL;
		LOG("Stopping WebAdmin...");
		delete m_WebAdmin; m_WebAdmin = NULL;
		LOG("Unloading recipes...");
		delete m_FurnaceRecipe;   m_FurnaceRecipe = NULL;
		delete m_CraftingRecipes; m_CraftingRecipes = NULL;
		LOG("Forgetting groups...");
		delete m_GroupManager; m_GroupManager = 0;
		LOG("Unloading worlds...");
		UnloadWorlds();
		
		LOG("Stopping plugin manager...");
		delete m_PluginManager; m_PluginManager = NULL;

		cItemHandler::Deinit();
		cBlockHandler::Deinit();

		LOG("Destroying server...");
		//delete HeartBeat; HeartBeat = 0;
		delete m_Server; m_Server = 0;
		LOG("Shutdown done.");
	}

	delete m_Log; m_Log = 0;
}
Exemple #3
0
void cRoot::Start(void)
{
	#ifdef _WIN32
	HWND hwnd = GetConsoleWindow();
	HMENU hmenu = GetSystemMenu(hwnd, FALSE);
	EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED);  // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
	#endif
	
	cLogger::cListener * consoleLogListener = MakeConsoleListener();
	cLogger::cListener * fileLogListener = new cFileListener();
	cLogger::GetInstance().AttachListener(consoleLogListener);
	cLogger::GetInstance().AttachListener(fileLogListener);
	
	LOG("--- Started Log ---\n");

	#ifdef BUILD_ID
	LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID );
	LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME );
	#endif

	cDeadlockDetect dd;

	m_bStop = false;
	while (!m_bStop)
	{
		cTimer Time;
		long long mseconds = Time.GetNowTime();
		
		m_bRestart = false;

		LoadGlobalSettings();

		LOG("Creating new server instance...");
		m_Server = new cServer();

		LOG("Reading server config...");
		cIniFile IniFile;
		if (!IniFile.ReadFile("settings.ini"))
		{
			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");
			IniFile.AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help");
		}

		m_PrimaryServerVersion = IniFile.GetValueI("Server", "PrimaryServerVersion", 0);
		if (m_PrimaryServerVersion == 0)
		{
			m_PrimaryServerVersion = cProtocolRecognizer::PROTO_VERSION_LATEST;
		}
		else
		{
			// Make a note in the log that the primary server version is explicitly set in the ini file
			LOGINFO("Primary server version set explicitly to %d.", m_PrimaryServerVersion);
		}

		LOG("Starting server...");
		m_MojangAPI.Start(IniFile);  // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
		if (!m_Server->InitServer(IniFile))
		{
			IniFile.WriteFile("settings.ini");
			LOGERROR("Failure starting server, aborting...");
			return;
		}

		m_WebAdmin = new cWebAdmin();
		m_WebAdmin->Init();

		LOGD("Loading settings...");
		m_RankManager.Initialize(m_MojangAPI);
		m_CraftingRecipes = new cCraftingRecipes;
		m_FurnaceRecipe   = new cFurnaceRecipe();
		
		LOGD("Loading worlds...");
		LoadWorlds(IniFile);

		LOGD("Loading plugin manager...");
		m_PluginManager = new cPluginManager();
		m_PluginManager->ReloadPluginsNow(IniFile);
		
		LOGD("Loading MonsterConfig...");
		m_MonsterConfig = new cMonsterConfig;

		// This sets stuff in motion
		LOGD("Starting Authenticator...");
		m_Authenticator.Start(IniFile);
		
		LOGD("Starting worlds...");
		StartWorlds();
		
		if (IniFile.GetValueSetB("DeadlockDetect", "Enabled", true))
		{
			LOGD("Starting deadlock detector...");
			dd.Start(IniFile.GetValueSetI("DeadlockDetect", "IntervalSec", 20));
		}
		
		IniFile.WriteFile("settings.ini");

		LOGD("Finalising startup...");
		m_Server->Start();
		
		m_WebAdmin->Start();

		#if !defined(ANDROID_NDK)
		LOGD("Starting InputThread...");
		m_InputThread = new cThread( InputThread, this, "cRoot::InputThread");
		m_InputThread->Start( false);  // We should NOT wait? Otherwise we can't stop the server from other threads than the input thread
		#endif

		long long finishmseconds = Time.GetNowTime();
		finishmseconds -= mseconds;

		LOG("Startup complete, took %lld ms!", finishmseconds);
		#ifdef _WIN32
		EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED);  // Re-enable close button
		#endif

		while (!m_bStop && !m_bRestart && !m_TerminateEventRaised)  // These are modified by external threads
		{
			cSleep::MilliSleep(1000);
		}

		if (m_TerminateEventRaised)
		{
			m_bStop = true;
		}

		#if !defined(ANDROID_NDK)
		delete m_InputThread; m_InputThread = NULL;
		#endif

		// Stop the server:
		m_WebAdmin->Stop();
		LOG("Shutting down server...");
		m_Server->Shutdown();
		LOGD("Shutting down deadlock detector...");
		dd.Stop();
		LOGD("Stopping world threads...");
		StopWorlds();
		LOGD("Stopping authenticator...");
		m_Authenticator.Stop();

		LOGD("Freeing MonsterConfig...");
		delete m_MonsterConfig; m_MonsterConfig = NULL;
		delete m_WebAdmin; m_WebAdmin = NULL;
		LOGD("Unloading recipes...");
		delete m_FurnaceRecipe;   m_FurnaceRecipe = NULL;
		delete m_CraftingRecipes; m_CraftingRecipes = NULL;
		LOGD("Unloading worlds...");
		UnloadWorlds();
		
		LOGD("Stopping plugin manager...");
		delete m_PluginManager; m_PluginManager = NULL;

		cItemHandler::Deinit();

		LOG("Cleaning up...");
		delete m_Server; m_Server = NULL;
		LOG("Shutdown successful!");
	}
	
	LOG("--- Stopped Log ---");
	
	cLogger::GetInstance().DetachListener(consoleLogListener);
	delete consoleLogListener;
	cLogger::GetInstance().DetachListener(fileLogListener);
	delete fileLogListener;
}
Exemple #4
0
void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
{
	#ifdef _WIN32
		HMENU ConsoleMenu = GetSystemMenu(GetConsoleWindow(), FALSE);
		EnableMenuItem(ConsoleMenu, SC_CLOSE, MF_GRAYED);  // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
	#endif

	auto consoleLogListener = MakeConsoleListener(m_RunAsService);
	auto consoleAttachment = cLogger::GetInstance().AttachListener(std::move(consoleLogListener));
	auto fileLogListenerRet = MakeFileListener();
	if (!fileLogListenerRet.first)
	{
		LOGERROR("Failed to open log file, aborting");
		return;
	}
	auto fileAttachment = cLogger::GetInstance().AttachListener(std::move(fileLogListenerRet.second));

	LOG("--- Started Log ---");

	#ifdef BUILD_ID
		LOG("Cuberite " BUILD_SERIES_NAME " build id: " BUILD_ID);
		LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME);
	#endif

	// Run the self-tests registered previously via cSelfTests::Register():
	#ifdef SELF_TEST
		cSelfTests::ExecuteAll();
	#endif

	cDeadlockDetect dd;
	auto BeginTime = std::chrono::steady_clock::now();

	LoadGlobalSettings();

	LOG("Creating new server instance...");
	m_Server = new cServer();

	LOG("Reading server config...");

	auto IniFile = cpp14::make_unique<cIniFile>();
	bool IsNewIniFile = !IniFile->ReadFile("settings.ini");

	if (IsNewIniFile)
	{
		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");
	}

	auto settingsRepo = cpp14::make_unique<cOverridesSettingsRepository>(std::move(IniFile), std::move(a_OverridesRepo));

	LOG("Starting server...");
	m_MojangAPI = new cMojangAPI;
	bool ShouldAuthenticate = settingsRepo->GetValueSetB("Authentication", "Authenticate", true);
	m_MojangAPI->Start(*settingsRepo, ShouldAuthenticate);  // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
	if (!m_Server->InitServer(*settingsRepo, ShouldAuthenticate))
	{
		settingsRepo->Flush();
		LOGERROR("Failure starting server, aborting...");
		return;
	}

	m_WebAdmin = new cWebAdmin();
	m_WebAdmin->Init();

	LOGD("Loading settings...");
	m_RankManager.reset(new cRankManager());
	m_RankManager->Initialize(*m_MojangAPI);
	m_CraftingRecipes = new cCraftingRecipes();
	m_FurnaceRecipe   = new cFurnaceRecipe();
	m_BrewingRecipes.reset(new cBrewingRecipes());

	LOGD("Loading worlds...");
	LoadWorlds(*settingsRepo, IsNewIniFile);

	LOGD("Loading plugin manager...");
	m_PluginManager = new cPluginManager();
	m_PluginManager->ReloadPluginsNow(*settingsRepo);

	LOGD("Loading MonsterConfig...");
	m_MonsterConfig = new cMonsterConfig;

	// This sets stuff in motion
	LOGD("Starting Authenticator...");
	m_Authenticator.Start(*settingsRepo);

	LOGD("Starting worlds...");
	StartWorlds();

	if (settingsRepo->GetValueSetB("DeadlockDetect", "Enabled", true))
	{
		LOGD("Starting deadlock detector...");
		dd.Start(settingsRepo->GetValueSetI("DeadlockDetect", "IntervalSec", 20));
	}

	settingsRepo->Flush();

	LOGD("Finalising startup...");
	if (m_Server->Start())
	{
		m_WebAdmin->Start();

		#if !defined(ANDROID_NDK)
			LOGD("Starting InputThread...");
			try
			{
				m_InputThreadRunFlag.test_and_set();
				m_InputThread = std::thread(InputThread, std::ref(*this));
			}
			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()));

		// Save the current time
		m_StartTime = std::chrono::steady_clock::now();

		#ifdef _WIN32
			EnableMenuItem(ConsoleMenu, SC_CLOSE, MF_ENABLED);  // Re-enable close button
		#endif

		for (;;)
		{
			m_StopEvent.Wait();

			break;
		}

		// Stop the server:
		m_WebAdmin->Stop();

		LOG("Shutting down server...");
		m_Server->Shutdown();
	}  // if (m_Server->Start()

	delete m_MojangAPI; m_MojangAPI = nullptr;

	LOGD("Shutting down deadlock detector...");
	dd.Stop();

	LOGD("Stopping world threads...");
	StopWorlds();

	LOGD("Stopping authenticator...");
	m_Authenticator.Stop();

	LOGD("Freeing MonsterConfig...");
	delete m_MonsterConfig; m_MonsterConfig = nullptr;
	delete m_WebAdmin; m_WebAdmin = nullptr;

	LOGD("Unloading recipes...");
	delete m_FurnaceRecipe;   m_FurnaceRecipe = nullptr;
	delete m_CraftingRecipes; m_CraftingRecipes = nullptr;

	LOG("Unloading worlds...");
	UnloadWorlds();

	LOGD("Stopping plugin manager...");
	delete m_PluginManager; m_PluginManager = nullptr;

	cItemHandler::Deinit();

	LOG("Cleaning up...");
	delete m_Server; m_Server = nullptr;

	m_InputThreadRunFlag.clear();
	#ifdef _WIN32
		DWORD Length;
		INPUT_RECORD Record
		{
			KEY_EVENT,
			{
				{
					TRUE,
					1,
					VK_RETURN,
					static_cast<WORD>(MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC)),
					{ { VK_RETURN } },
					0
				}
			}
		};

		// Can't kill the input thread since it breaks cin (getline doesn't block / receive input on restart)
		// Apparently no way to unblock getline
		// Only thing I can think of for now
		if (WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &Record, 1, &Length) == 0)
		{
			LOGWARN("Couldn't notify the input thread; the server will hang before shutdown!");
			m_TerminateEventRaised = true;
			m_InputThread.detach();
		}
		else
		{
			m_InputThread.join();
		}
	#else
		if (pthread_kill(m_InputThread.native_handle(), SIGKILL) != 0)
		{
			LOGWARN("Couldn't notify the input thread; the server will hang before shutdown!");
			m_TerminateEventRaised = true;
			m_InputThread.detach();
		}
	#endif

	if (m_TerminateEventRaised)
	{
		LOG("Shutdown successful!");
	}
	else
	{
		LOG("Shutdown successful - restarting...");
	}
	LOG("--- Stopped Log ---");
}
Exemple #5
0
void cRoot::Start(void)
{
	cDeadlockDetect dd;
	delete m_Log;
	m_Log = new cMCLogger();

	m_bStop = false;
	while (!m_bStop)
	{
		cTimer Time;
		long long mseconds = Time.GetNowTime();
		
		m_bRestart = false;

		LoadGlobalSettings();

		LOG("Creating new server instance...");
		m_Server = new cServer();

		LOG("Reading server config...");
		cIniFile IniFile;
		if (!IniFile.ReadFile("settings.ini"))
		{
			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");
			IniFile.AddHeaderComment(" See: http://www.mc-server.org/wiki/doku.php?id=configure:settings.ini for further configuration help");
		}

		m_PrimaryServerVersion = IniFile.GetValueI("Server", "PrimaryServerVersion", 0);
		if (m_PrimaryServerVersion == 0)
		{
			m_PrimaryServerVersion = cProtocolRecognizer::PROTO_VERSION_LATEST;
		}
		else
		{
			// Make a note in the log that the primary server version is explicitly set in the ini file
			LOGINFO("Primary server version set explicitly to %d.", m_PrimaryServerVersion);
		}

		LOG("Starting server...");
		if (!m_Server->InitServer(IniFile))
		{
			LOGERROR("Failure starting server, aborting...");
			return;
		}

		m_WebAdmin = new cWebAdmin();
		m_WebAdmin->Init();

		LOGD("Loading settings...");
		m_GroupManager    = new cGroupManager();
		m_CraftingRecipes = new cCraftingRecipes;
		m_FurnaceRecipe   = new cFurnaceRecipe();
		
		LOGD("Loading worlds...");
		LoadWorlds(IniFile);

		LOGD("Loading plugin manager...");
		m_PluginManager = new cPluginManager();
		m_PluginManager->ReloadPluginsNow(IniFile);
		
		LOGD("Loading MonsterConfig...");
		m_MonsterConfig = new cMonsterConfig;

		// This sets stuff in motion
		LOGD("Starting Authenticator...");
		m_Authenticator.Start(IniFile);
		
		IniFile.WriteFile("settings.ini");

		LOGD("Starting worlds...");
		StartWorlds();
		
		LOGD("Starting deadlock detector...");
		dd.Start();
		
		LOGD("Finalising startup...");
		m_Server->Start();
		
		m_WebAdmin->Start();

		#if !defined(ANDROID_NDK)
		LOGD("Starting InputThread...");
		m_InputThread = new cThread( InputThread, this, "cRoot::InputThread" );
		m_InputThread->Start( false );	// We should NOT wait? Otherwise we can´t stop the server from other threads than the input thread
		#endif

		long long finishmseconds = Time.GetNowTime();
		finishmseconds -= mseconds;

		LOG("Startup complete, took %i ms!", finishmseconds);

		while (!m_bStop && !m_bRestart)  // These are modified by external threads
		{
			cSleep::MilliSleep(1000);
		}

		#if !defined(ANDROID_NDK)
		delete m_InputThread; m_InputThread = NULL;
		#endif

		// Deallocate stuffs
		LOG("Shutting down server...");
		m_Server->Shutdown();
		
		LOGD("Shutting down deadlock detector...");
		dd.Stop();
		
		LOGD("Stopping world threads...");
		StopWorlds();
		
		LOGD("Stopping authenticator...");
		m_Authenticator.Stop();

		LOGD("Freeing MonsterConfig...");
		delete m_MonsterConfig; m_MonsterConfig = NULL;
		delete m_WebAdmin; m_WebAdmin = NULL;
		LOGD("Unloading recipes...");
		delete m_FurnaceRecipe;   m_FurnaceRecipe = NULL;
		delete m_CraftingRecipes; m_CraftingRecipes = NULL;
		LOGD("Forgetting groups...");
		delete m_GroupManager; m_GroupManager = 0;
		LOGD("Unloading worlds...");
		UnloadWorlds();
		
		LOGD("Stopping plugin manager...");
		delete m_PluginManager; m_PluginManager = NULL;

		cItemHandler::Deinit();
		cBlockHandler::Deinit();

		LOG("Cleaning up...");
		//delete HeartBeat; HeartBeat = 0;
		delete m_Server; m_Server = 0;
		LOG("Shutdown successful!");
	}

	delete m_Log; m_Log = 0;
}