2010-10-07 15:35:36 +02:00
/*
2012-01-01 00:32:13 +01:00
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/** \file
2008-10-14 11:57:03 -05:00
\ingroup Trinityd
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2010-05-19 21:16:59 +02:00
#include <ace/Sig_Handler.h>
2009-10-17 15:51:44 -07:00
2008-10-04 06:17:19 -05:00
#include "Common.h"
2010-08-16 09:51:37 +02:00
#include "SystemConfig.h"
2010-05-19 21:16:59 +02:00
#include "SignalHandler.h"
2009-06-04 21:41:07 +02:00
#include "World.h"
#include "WorldRunnable.h"
#include "WorldSocket.h"
#include "WorldSocketMgr.h"
2010-07-29 01:22:45 +02:00
#include "Configuration/Config.h"
2008-10-02 16:23:55 -05:00
#include "Database/DatabaseEnv.h"
2010-09-03 10:52:32 +02:00
#include "Database/DatabaseWorkerPool.h"
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "CliRunnable.h"
2009-06-04 21:41:07 +02:00
#include "Log.h"
#include "Master.h"
2010-12-10 01:01:44 +02:00
#include "RARunnable.h"
2010-07-23 09:26:23 +02:00
#include "TCSoap.h"
2009-12-24 10:20:15 +01:00
#include "Timer.h"
2008-10-02 16:23:55 -05:00
#include "Util.h"
2010-12-28 17:56:15 +01:00
#include "AuthSocket.h"
2009-10-17 15:51:44 -07:00
2010-06-08 01:34:51 +02:00
#include "BigNumber.h"
2009-10-17 15:51:44 -07:00
2010-06-23 01:47:41 +02:00
#ifdef _WIN32
2008-10-02 16:23:55 -05:00
#include "ServiceWin32.h"
extern int m_ServiceStatus ;
#endif
2009-10-17 15:51:44 -07:00
2011-04-12 16:46:37 -04:00
/// Handle worldservers's termination signals
class WorldServerSignalHandler : public Trinity :: SignalHandler
2010-05-19 21:16:59 +02:00
{
public :
virtual void HandleSignal ( int SigNum )
{
switch ( SigNum )
{
case SIGINT :
World :: StopNow ( RESTART_EXIT_CODE );
break ;
case SIGTERM :
#ifdef _WIN32
case SIGBREAK :
if ( m_ServiceStatus != 1 )
#endif /* _WIN32 */
World :: StopNow ( SHUTDOWN_EXIT_CODE );
break ;
}
}
};
2009-05-13 18:22:21 -05:00
class FreezeDetectorRunnable : public ACE_Based :: Runnable
2008-10-02 16:23:55 -05:00
{
public :
FreezeDetectorRunnable () { _delaytime = 0 ; }
uint32 m_loops , m_lastchange ;
uint32 w_loops , w_lastchange ;
uint32 _delaytime ;
void SetDelayTime ( uint32 t ) { _delaytime = t ; }
void run ( void )
{
2010-06-25 01:30:06 +02:00
if ( ! _delaytime )
2008-10-02 16:23:55 -05:00
return ;
2011-03-26 03:28:59 +02:00
sLog -> outString ( "Starting up anti-freeze thread (%u seconds max stuck time)..." , _delaytime / 1000 );
2008-10-02 16:23:55 -05:00
m_loops = 0 ;
w_loops = 0 ;
m_lastchange = 0 ;
w_lastchange = 0 ;
2010-06-25 01:30:06 +02:00
while ( ! World :: IsStopped ())
2008-10-02 16:23:55 -05:00
{
2009-05-13 18:22:21 -05:00
ACE_Based :: Thread :: Sleep ( 1000 );
2008-10-02 16:23:55 -05:00
uint32 curtime = getMSTime ();
// normal work
2010-06-25 01:30:06 +02:00
if ( w_loops != World :: m_worldLoopCounter )
2008-10-02 16:23:55 -05:00
{
w_lastchange = curtime ;
w_loops = World :: m_worldLoopCounter ;
}
2008-11-15 11:56:59 -06:00
// possible freeze
2011-04-29 20:47:02 +02:00
else if ( getMSTimeDiff ( w_lastchange , curtime ) > _delaytime )
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "World Thread hangs, kicking out server!" );
2011-04-07 13:14:26 +03:00
ASSERT ( false );
2008-10-02 16:23:55 -05:00
}
}
2010-12-23 23:25:44 +01:00
sLog -> outString ( "Anti-freeze thread exiting without problems." );
2008-10-02 16:23:55 -05:00
}
};
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Master :: Master ()
{
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Master ::~ Master ()
{
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Main function
int Master :: Run ()
{
2010-05-29 17:26:43 +02:00
BigNumber seed1 ;
seed1 . SetRand ( 16 * 8 );
2011-04-12 16:46:37 -04:00
sLog -> outString ( "%s (worldserver-daemon)" , _FULLVERSION );
2010-12-28 17:56:15 +01:00
sLog -> outString ( "<Ctrl-C> to stop. \n " );
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
sLog -> outString ( " ______ __" );
sLog -> outString ( "/ \\ __ _ \\ __ __/ \\ \\ __" );
2011-09-29 12:43:05 +02:00
sLog -> outString ( " \\ /_/ \\ \\ / _ __ / \\ _ \\ ___ / \\ _ \\ \\ , _ \\ __ __" );
2010-12-28 17:56:15 +01:00
sLog -> outString ( " \\ \\ \\ / \\ `'__ \\ / \\ \\ /' _ ` \\ / \\ \\ \\ \\ / / \\ \\ / \\ \\ " );
sLog -> outString ( " \\ \\ \\ \\ \\ / \\ \\ \\ / \\ \\ / \\ \\ \\ \\ \\ \\ _ \\ \\ \\ _ \\ \\ " );
sLog -> outString ( " \\ \\ _ \\ \\ _ \\ \\ \\ _ \\ \\ _ \\ \\ _ \\ \\ _ \\ \\ __ \\\\ /`____ \\ " );
sLog -> outString ( " \\ /_/ \\ /_/ \\ /_/ \\ /_/ \\ /_/ \\ /_/ \\ /__/ `/___/> \\ " );
sLog -> outString ( " C O R E / \\ ___/" );
sLog -> outString ( "http://TrinityCore.org \\ /__/ \n " );
2010-12-13 22:37:56 +01:00
2010-10-27 19:51:41 -07:00
#ifdef USE_SFMT_FOR_RNG
2010-12-28 17:56:15 +01:00
sLog -> outString ( " \n " );
sLog -> outString ( "SFMT has been enabled as the random number generator, if worldserver" );
2012-02-25 20:39:28 +01:00
sLog -> outString ( "freezes or crashes randomly, first, try disabling SFMT in CMAKE configuration" );
2010-12-28 17:56:15 +01:00
sLog -> outString ( " \n " );
2010-10-27 19:51:41 -07:00
#endif //USE_SFMT_FOR_RNG
2009-10-17 15:51:44 -07:00
2011-04-12 16:46:37 -04:00
/// worldserver PID file creation
2011-09-28 13:00:43 +02:00
std :: string pidfile = ConfigMgr :: GetStringDefault ( "PidFile" , "" );
2010-12-28 17:56:15 +01:00
if ( ! pidfile . empty ())
2008-10-02 16:23:55 -05:00
{
uint32 pid = CreatePIDFile ( pidfile );
2010-12-28 17:56:15 +01:00
if ( ! pid )
2008-10-02 16:23:55 -05:00
{
2010-12-28 17:56:15 +01:00
sLog -> outError ( "Cannot create PID file %s. \n " , pidfile . c_str ());
2008-10-02 16:23:55 -05:00
return 1 ;
}
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
sLog -> outString ( "Daemon PID: %u \n " , pid );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Start the databases
if ( ! _StartDB ())
return 1 ;
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
// set server offline (not connectable)
LoginDatabase . DirectPExecute ( "UPDATE realmlist SET color = (color & ~%u) | %u WHERE id = '%d'" , REALM_FLAG_OFFLINE , REALM_FLAG_INVALID , realmID );
2008-10-02 16:23:55 -05:00
///- Initialize the World
2010-12-23 23:25:44 +01:00
sWorld -> SetInitialWorldSettings ();
2009-10-17 15:51:44 -07:00
2010-05-19 21:16:59 +02:00
// Initialise the signal handlers
2011-04-12 16:46:37 -04:00
WorldServerSignalHandler SignalINT , SignalTERM ;
2010-05-19 21:16:59 +02:00
#ifdef _WIN32
2011-04-12 16:46:37 -04:00
WorldServerSignalHandler SignalBREAK ;
2010-05-19 21:16:59 +02:00
#endif /* _WIN32 */
2011-04-12 16:46:37 -04:00
// Register worldserver's signal handlers
2010-05-19 21:16:59 +02:00
ACE_Sig_Handler Handler ;
Handler . register_handler ( SIGINT , & SignalINT );
Handler . register_handler ( SIGTERM , & SignalTERM );
#ifdef _WIN32
Handler . register_handler ( SIGBREAK , & SignalBREAK );
#endif /* _WIN32 */
2008-10-02 16:23:55 -05:00
///- Launch WorldRunnable thread
2009-08-08 12:37:33 -05:00
ACE_Based :: Thread world_thread ( new WorldRunnable );
world_thread . setPriority ( ACE_Based :: Highest );
2009-10-17 15:51:44 -07:00
2009-08-08 12:12:56 -05:00
ACE_Based :: Thread * cliThread = NULL ;
2009-10-17 15:51:44 -07:00
2010-06-23 01:47:41 +02:00
#ifdef _WIN32
2011-09-28 13:00:43 +02:00
if ( ConfigMgr :: GetBoolDefault ( "Console.Enable" , true ) && ( m_ServiceStatus == - 1 ) /* need disable console in service mode*/ )
2008-10-02 16:23:55 -05:00
#else
2011-09-28 13:00:43 +02:00
if ( ConfigMgr :: GetBoolDefault ( "Console.Enable" , true ))
2008-10-02 16:23:55 -05:00
#endif
{
///- Launch CliRunnable thread
2009-08-08 12:12:56 -05:00
cliThread = new ACE_Based :: Thread ( new CliRunnable );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-08-08 12:37:33 -05:00
ACE_Based :: Thread rar_thread ( new RARunnable );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Handle affinity for multiple processors and process priority on Windows
2010-06-23 01:47:41 +02:00
#ifdef _WIN32
2008-10-02 16:23:55 -05:00
{
HANDLE hProcess = GetCurrentProcess ();
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
uint32 Aff = ConfigMgr :: GetIntDefault ( "UseProcessors" , 0 );
2010-12-28 17:56:15 +01:00
if ( Aff > 0 )
2008-10-02 16:23:55 -05:00
{
ULONG_PTR appAff ;
ULONG_PTR sysAff ;
2009-10-17 15:51:44 -07:00
2011-03-26 03:28:59 +02:00
if ( GetProcessAffinityMask ( hProcess , & appAff , & sysAff ))
2008-10-02 16:23:55 -05:00
{
ULONG_PTR curAff = Aff & appAff ; // remove non accessible processors
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
if ( ! curAff )
2008-10-02 16:23:55 -05:00
{
2011-04-12 16:46:37 -04:00
sLog -> outError ( "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x" , Aff , appAff );
2008-10-02 16:23:55 -05:00
}
else
{
2011-04-12 16:46:37 -04:00
if ( SetProcessAffinityMask ( hProcess , curAff ))
2010-12-23 23:25:44 +01:00
sLog -> outString ( "Using processors (bitmask, hex): %x" , curAff );
2008-10-02 16:23:55 -05:00
else
2010-12-28 17:56:15 +01:00
sLog -> outError ( "Can't set used processors (hex): %x" , curAff );
2008-10-02 16:23:55 -05:00
}
}
2010-12-23 23:25:44 +01:00
sLog -> outString ( "" );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
bool Prio = ConfigMgr :: GetBoolDefault ( "ProcessPriority" , false );
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
//if (Prio && (m_ServiceStatus == -1) /* need set to default process priority class in service mode*/)
if ( Prio )
2008-10-02 16:23:55 -05:00
{
2011-03-26 03:28:59 +02:00
if ( SetPriorityClass ( hProcess , HIGH_PRIORITY_CLASS ))
2011-04-12 16:46:37 -04:00
sLog -> outString ( "worldserver process priority class set to HIGH" );
2008-10-02 16:23:55 -05:00
else
2011-04-12 16:46:37 -04:00
sLog -> outError ( "Can't set worldserver process priority class." );
2010-12-23 23:25:44 +01:00
sLog -> outString ( "" );
2008-10-02 16:23:55 -05:00
}
}
#endif
2010-07-23 09:26:23 +02:00
//Start soap serving thread
ACE_Based :: Thread * soap_thread = NULL ;
2011-09-28 13:00:43 +02:00
if ( ConfigMgr :: GetBoolDefault ( "SOAP.Enabled" , false ))
2010-07-23 09:26:23 +02:00
{
2011-09-15 14:08:17 +02:00
TCSoapRunnable * runnable = new TCSoapRunnable ();
2011-09-28 13:00:43 +02:00
runnable -> setListenArguments ( ConfigMgr :: GetStringDefault ( "SOAP.IP" , "127.0.0.1" ), ConfigMgr :: GetIntDefault ( "SOAP.Port" , 7878 ));
2010-07-23 09:26:23 +02:00
soap_thread = new ACE_Based :: Thread ( runnable );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Start up freeze catcher thread
2011-09-28 13:00:43 +02:00
if ( uint32 freeze_delay = ConfigMgr :: GetIntDefault ( "MaxCoreStuckTime" , 0 ))
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
FreezeDetectorRunnable * fdr = new FreezeDetectorRunnable ();
2008-10-02 16:23:55 -05:00
fdr -> SetDelayTime ( freeze_delay * 1000 );
2009-08-08 12:37:33 -05:00
ACE_Based :: Thread freeze_thread ( fdr );
freeze_thread . setPriority ( ACE_Based :: Highest );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-04 06:17:19 -05:00
///- Launch the world listener socket
2010-12-23 23:25:44 +01:00
uint16 wsport = sWorld -> getIntConfig ( CONFIG_PORT_WORLD );
2011-09-28 13:00:43 +02:00
std :: string bind_ip = ConfigMgr :: GetStringDefault ( "BindIP" , "0.0.0.0" );
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
if ( sWorldSocketMgr -> StartNetwork ( wsport , bind_ip . c_str ()) == - 1 )
2008-10-04 06:17:19 -05:00
{
2011-03-26 03:28:59 +02:00
sLog -> outError ( "Failed to start network" );
2009-03-20 22:17:39 +01:00
World :: StopNow ( ERROR_EXIT_CODE );
// go down and shutdown the server
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
// set server online (allow connecting now)
LoginDatabase . DirectPExecute ( "UPDATE realmlist SET color = color & ~%u, population = 0 WHERE id = '%u'" , REALM_FLAG_INVALID , realmID );
2011-08-04 22:53:33 +02:00
sLog -> outString ( "%s (worldserver-daemon) ready..." , _FULLVERSION );
2010-12-28 17:56:15 +01:00
sWorldSocketMgr -> Wait ();
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
if ( soap_thread )
2010-07-23 09:26:23 +02:00
{
2010-12-28 17:56:15 +01:00
soap_thread -> wait ();
soap_thread -> destroy ();
delete soap_thread ;
2010-07-23 09:26:23 +02:00
}
2008-10-02 16:23:55 -05:00
// set server offline
2011-01-16 00:08:52 +01:00
LoginDatabase . DirectPExecute ( "UPDATE realmlist SET color = color | %u WHERE id = '%d'" , REALM_FLAG_OFFLINE , realmID );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// when the main thread closes the singletons get unloaded
// since worldrunnable uses them, it will crash if unloaded after master
2009-08-08 12:37:33 -05:00
world_thread . wait ();
2010-12-28 17:56:15 +01:00
rar_thread . wait ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Clean database before leaving
clearOnlineAccounts ();
2009-10-17 15:51:44 -07:00
2011-01-26 01:03:35 +01:00
_StopDB ();
2009-10-17 15:51:44 -07:00
2010-12-28 17:56:15 +01:00
sLog -> outString ( "Halting process..." );
2009-10-17 15:51:44 -07:00
2009-08-08 12:37:33 -05:00
if ( cliThread )
2008-10-02 16:23:55 -05:00
{
2010-06-23 01:47:41 +02:00
#ifdef _WIN32
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API)
//_exit(1);
// send keyboard input to safely unblock the CLI thread
INPUT_RECORD b [ 5 ];
HANDLE hStdIn = GetStdHandle ( STD_INPUT_HANDLE );
b [ 0 ]. EventType = KEY_EVENT ;
b [ 0 ]. Event . KeyEvent . bKeyDown = TRUE ;
b [ 0 ]. Event . KeyEvent . uChar . AsciiChar = 'X' ;
b [ 0 ]. Event . KeyEvent . wVirtualKeyCode = 'X' ;
b [ 0 ]. Event . KeyEvent . wRepeatCount = 1 ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
b [ 1 ]. EventType = KEY_EVENT ;
b [ 1 ]. Event . KeyEvent . bKeyDown = FALSE ;
b [ 1 ]. Event . KeyEvent . uChar . AsciiChar = 'X' ;
b [ 1 ]. Event . KeyEvent . wVirtualKeyCode = 'X' ;
b [ 1 ]. Event . KeyEvent . wRepeatCount = 1 ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
b [ 2 ]. EventType = KEY_EVENT ;
b [ 2 ]. Event . KeyEvent . bKeyDown = TRUE ;
b [ 2 ]. Event . KeyEvent . dwControlKeyState = 0 ;
b [ 2 ]. Event . KeyEvent . uChar . AsciiChar = '\r' ;
b [ 2 ]. Event . KeyEvent . wVirtualKeyCode = VK_RETURN ;
b [ 2 ]. Event . KeyEvent . wRepeatCount = 1 ;
b [ 2 ]. Event . KeyEvent . wVirtualScanCode = 0x1c ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
b [ 3 ]. EventType = KEY_EVENT ;
b [ 3 ]. Event . KeyEvent . bKeyDown = FALSE ;
b [ 3 ]. Event . KeyEvent . dwControlKeyState = 0 ;
b [ 3 ]. Event . KeyEvent . uChar . AsciiChar = '\r' ;
b [ 3 ]. Event . KeyEvent . wVirtualKeyCode = VK_RETURN ;
b [ 3 ]. Event . KeyEvent . wVirtualScanCode = 0x1c ;
b [ 3 ]. Event . KeyEvent . wRepeatCount = 1 ;
DWORD numb ;
2010-05-13 00:15:21 +02:00
WriteConsoleInput ( hStdIn , b , 4 , & numb );
2009-10-17 15:51:44 -07:00
2009-08-08 12:12:56 -05:00
cliThread -> wait ();
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
#else
2009-10-17 15:51:44 -07:00
2009-08-08 12:12:56 -05:00
cliThread -> destroy ();
2009-10-17 15:51:44 -07:00
2009-08-08 12:12:56 -05:00
#endif
2009-10-17 15:51:44 -07:00
2009-08-08 12:12:56 -05:00
delete cliThread ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// for some unknown reason, unloading scripts here and not in worldrunnable
// fixes a memory leak related to detaching threads from the module
2010-01-19 11:36:05 +01:00
//UnloadScriptingModule();
2009-10-17 15:51:44 -07:00
2008-11-20 16:16:57 -06:00
// Exit the process with specified return value
return World :: GetExitCode ();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Initialize connection to the databases
bool Master :: _StartDB ()
{
2011-01-13 21:30:37 +01:00
MySQL :: Library_Init ();
2010-12-23 23:25:44 +01:00
sLog -> SetLogDB ( false );
2008-10-02 16:23:55 -05:00
std :: string dbstring ;
2010-12-13 09:18:49 +01:00
uint8 async_threads , synch_threads ;
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
dbstring = ConfigMgr :: GetStringDefault ( "WorldDatabaseInfo" , "" );
2010-06-21 23:58:27 +02:00
if ( dbstring . empty ())
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "World database not specified in configuration file" );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
async_threads = ConfigMgr :: GetIntDefault ( "WorldDatabase.WorkerThreads" , 1 );
2010-09-27 00:20:56 +02:00
if ( async_threads < 1 || async_threads > 32 )
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "World database: invalid number of worker threads specified. "
2010-08-18 02:25:52 +02:00
"Please pick a value between 1 and 32." );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
synch_threads = ConfigMgr :: GetIntDefault ( "WorldDatabase.SynchThreads" , 1 );
2010-08-18 02:25:52 +02:00
///- Initialise the world database
2010-12-13 09:18:49 +01:00
if ( ! WorldDatabase . Open ( dbstring , async_threads , synch_threads ))
2010-08-18 02:25:52 +02:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Cannot connect to world database %s" , dbstring . c_str ());
2010-08-18 02:25:52 +02:00
return false ;
}
2011-03-26 03:28:59 +02:00
2009-03-20 22:17:39 +01:00
///- Get character database info from configuration file
2011-09-28 13:00:43 +02:00
dbstring = ConfigMgr :: GetStringDefault ( "CharacterDatabaseInfo" , "" );
2010-06-21 23:58:27 +02:00
if ( dbstring . empty ())
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Character database not specified in configuration file" );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
async_threads = ConfigMgr :: GetIntDefault ( "CharacterDatabase.WorkerThreads" , 1 );
2010-09-27 00:20:56 +02:00
if ( async_threads < 1 || async_threads > 32 )
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Character database: invalid number of worker threads specified. "
2010-08-18 02:25:52 +02:00
"Please pick a value between 1 and 32." );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
synch_threads = ConfigMgr :: GetIntDefault ( "CharacterDatabase.SynchThreads" , 2 );
2010-09-03 10:52:32 +02:00
2010-08-18 02:25:52 +02:00
///- Initialise the Character database
2010-12-13 09:18:49 +01:00
if ( ! CharacterDatabase . Open ( dbstring , async_threads , synch_threads ))
2010-08-18 02:25:52 +02:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Cannot connect to Character database %s" , dbstring . c_str ());
2010-08-18 02:25:52 +02:00
return false ;
}
2010-09-03 10:52:32 +02:00
2008-10-02 16:23:55 -05:00
///- Get login database info from configuration file
2011-09-28 13:00:43 +02:00
dbstring = ConfigMgr :: GetStringDefault ( "LoginDatabaseInfo" , "" );
2010-06-21 23:58:27 +02:00
if ( dbstring . empty ())
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Login database not specified in configuration file" );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
async_threads = ConfigMgr :: GetIntDefault ( "LoginDatabase.WorkerThreads" , 1 );
2010-09-27 00:20:56 +02:00
if ( async_threads < 1 || async_threads > 32 )
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Login database: invalid number of worker threads specified. "
2010-08-18 02:25:52 +02:00
"Please pick a value between 1 and 32." );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-28 13:00:43 +02:00
synch_threads = ConfigMgr :: GetIntDefault ( "LoginDatabase.SynchThreads" , 1 );
2010-08-18 02:25:52 +02:00
///- Initialise the login database
2010-12-13 09:18:49 +01:00
if ( ! LoginDatabase . Open ( dbstring , async_threads , synch_threads ))
2010-08-18 02:25:52 +02:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Cannot connect to login database %s" , dbstring . c_str ());
2010-08-18 02:25:52 +02:00
return false ;
}
2011-03-26 03:28:59 +02:00
2008-10-02 16:23:55 -05:00
///- Get the realm Id from the configuration file
2011-09-28 13:00:43 +02:00
realmID = ConfigMgr :: GetIntDefault ( "RealmID" , 0 );
2010-06-21 23:58:27 +02:00
if ( ! realmID )
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Realm ID not defined in configuration file" );
2008-10-02 16:23:55 -05:00
return false ;
}
2010-12-23 23:25:44 +01:00
sLog -> outString ( "Realm running as realm ID %d" , realmID );
2009-10-17 15:51:44 -07:00
2009-05-04 11:39:43 -04:00
///- Initialize the DB logging system
2011-09-28 13:00:43 +02:00
sLog -> SetLogDBLater ( ConfigMgr :: GetBoolDefault ( "EnableLogDB" , false )); // set var to enable DB logging once startup finished.
2010-12-23 23:25:44 +01:00
sLog -> SetLogDB ( false );
sLog -> SetRealmID ( realmID );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Clean the database before starting
clearOnlineAccounts ();
2009-10-17 15:51:44 -07:00
2009-03-25 15:52:28 +01:00
///- Insert version info into DB
2011-12-31 00:32:05 +01:00
WorldDatabase . PExecute ( "UPDATE version SET core_version = '%s', core_revision = '%s'" , _FULLVERSION , _HASH ); // One-time query
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sWorld -> LoadDBVersion ();
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outString ( "Using World DB: %s" , sWorld -> GetDBVersion ());
2008-10-02 16:23:55 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2011-01-13 21:30:37 +01:00
void Master :: _StopDB ()
{
CharacterDatabase . Close ();
WorldDatabase . Close ();
LoginDatabase . Close ();
MySQL :: Library_End ();
}
2008-10-02 16:23:55 -05:00
/// Clear 'online' status for all accounts with characters in this realm
void Master :: clearOnlineAccounts ()
{
// Cleanup online status for characters hosted at current realm
/// \todo Only accounts with characters logged on *this* realm should have online status reset. Move the online column from 'account' to 'realmcharacters'?
2011-01-16 00:08:52 +01:00
LoginDatabase . DirectPExecute (
2008-10-02 16:23:55 -05:00
"UPDATE account SET online = 0 WHERE online > 0 "
2011-03-26 03:28:59 +02:00
"AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = '%d')" , realmID );
2009-10-17 15:51:44 -07:00
2011-03-26 03:28:59 +02:00
CharacterDatabase . DirectExecute ( "UPDATE characters SET online = 0 WHERE online <> 0" );
2009-10-17 15:51:44 -07:00
2009-03-20 22:17:39 +01:00
// Battleground instance ids reset at server restart
2012-03-19 17:35:27 +01:00
CharacterDatabase . DirectExecute ( "UPDATE character_battleground_data SET instanceId = 0" );
2008-10-02 16:23:55 -05:00
}