aboutsummaryrefslogtreecommitdiff
path: root/src/trinitycore
diff options
context:
space:
mode:
Diffstat (limited to 'src/trinitycore')
-rw-r--r--src/trinitycore/CliRunnable.cpp1265
-rw-r--r--src/trinitycore/CliRunnable.h33
-rw-r--r--src/trinitycore/Main.cpp164
-rw-r--r--src/trinitycore/Makefile.am78
-rw-r--r--src/trinitycore/Master.cpp492
-rw-r--r--src/trinitycore/Master.h50
-rw-r--r--src/trinitycore/RASocket.cpp251
-rw-r--r--src/trinitycore/RASocket.h65
-rw-r--r--src/trinitycore/TrinityCore.icobin0 -> 34494 bytes
-rw-r--r--src/trinitycore/TrinityCore.rc85
-rw-r--r--src/trinitycore/WorldRunnable.cpp82
-rw-r--r--src/trinitycore/WorldRunnable.h33
-rw-r--r--src/trinitycore/monitor-mangosd18
-rw-r--r--src/trinitycore/resource.h15
-rw-r--r--src/trinitycore/run-mangosd14
-rw-r--r--src/trinitycore/trinitycore.conf.dist1027
16 files changed, 3672 insertions, 0 deletions
diff --git a/src/trinitycore/CliRunnable.cpp b/src/trinitycore/CliRunnable.cpp
new file mode 100644
index 00000000000..2a92273f764
--- /dev/null
+++ b/src/trinitycore/CliRunnable.cpp
@@ -0,0 +1,1265 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup mangosd
+/// @{
+/// \file
+
+#include "Common.h"
+#include "Language.h"
+#include "Log.h"
+#include "World.h"
+#include "ScriptCalls.h"
+#include "GlobalEvents.h"
+#include "ObjectMgr.h"
+#include "WorldSession.h"
+#include "SystemConfig.h"
+#include "Config/ConfigEnv.h"
+#include "Util.h"
+#include "AccountMgr.h"
+#include "CliRunnable.h"
+#include "MapManager.h"
+#include "PlayerDump.h"
+#include "Player.h"
+
+//CliCommand and CliCommandHolder are defined in World.h to avoid cyclic deps
+
+//func prototypes must be defined
+
+void CliHelp(char*,pPrintf);
+void CliInfo(char*,pPrintf);
+void CliBan(char*,pPrintf);
+void CliBanList(char*,pPrintf);
+void CliRemoveBan(char*,pPrintf);
+void CliSetGM(char*,pPrintf);
+void CliListGM(char*,pPrintf);
+void CliVersion(char*,pPrintf);
+void CliExit(char*,pPrintf);
+void CliIdleRestart(char*,pPrintf zprintf);
+void CliRestart(char*,pPrintf zprintf);
+void CliIdleShutdown(char*,pPrintf zprintf);
+void CliShutdown(char*,pPrintf zprintf);
+void CliBroadcast(char*,pPrintf);
+void CliCreate(char*,pPrintf);
+void CliDelete(char*,pPrintf);
+void CliCharDelete(char *,pPrintf);
+void CliLoadScripts(char*,pPrintf);
+void CliKick(char*,pPrintf);
+void CliTele(char*,pPrintf);
+void CliMotd(char*,pPrintf);
+void CliCorpses(char*,pPrintf);
+void CliSetLogLevel(char*,pPrintf);
+void CliUpTime(char*,pPrintf);
+void CliSetTBC(char*,pPrintf);
+void CliWritePlayerDump(char*,pPrintf);
+void CliLoadPlayerDump(char*,pPrintf);
+void CliSave(char*,pPrintf);
+void CliSend(char*,pPrintf);
+void CliPLimit(char*,pPrintf);
+void CliSetPassword(char*,pPrintf);
+/// Table of known commands
+const CliCommand Commands[]=
+{
+ {"help", & CliHelp,"Display this help message"},
+ {"broadcast", & CliBroadcast,"Announce in-game message"},
+ {"create", & CliCreate,"Create account"},
+ {"delete", & CliDelete,"Delete account and characters"},
+ {"chardelete", & CliCharDelete,"Delete character"},
+ {"info", & CliInfo,"Display Server infomation"},
+ {"uptime", & CliUpTime, "Displays the server uptime"},
+ {"motd", & CliMotd,"Change or display motd"},
+ {"kick", & CliKick,"Kick user"},
+ {"ban", & CliBan,"Ban account|ip"},
+ {"listbans", & CliBanList,"List bans"},
+ {"unban", & CliRemoveBan,"Remove ban from account|ip"},
+ {"setgm", & CliSetGM,"Edit user privileges"},
+ {"setpass", & CliSetPassword,"Set password for account"},
+ {"setbc", & CliSetTBC,"Set user expansion allowed"},
+ {"listgm", & CliListGM,"Display user privileges"},
+ {"loadscripts", & CliLoadScripts,"Load script library"},
+ {"setloglevel", & CliSetLogLevel,"Set Log Level"},
+ {"corpses", & CliCorpses,"Manually call corpses erase global even code"},
+ {"version", & CliVersion,"Display server version"},
+ {"idlerestart", & CliIdleRestart,"Restart server with some delay when there are no active connections remaining"},
+ {"restart", & CliRestart,"Restart server with some delay"},
+ {"idleshutdown", & CliIdleShutdown,"Shutdown server with some delay when there are no active connections remaining"},
+ {"shutdown", & CliShutdown,"Shutdown server with some delay"},
+ {"exit", & CliExit,"Shutdown server NOW"},
+ {"writepdump", &CliWritePlayerDump,"Write a player dump to a file"},
+ {"loadpdump", &CliLoadPlayerDump,"Load a player dump from a file"},
+ {"saveall", &CliSave,"Save all players"},
+ {"send", &CliSend,"Send message to a player"},
+ {"tele", &CliTele,"Teleport player to location"},
+ {"plimit", &CliPLimit,"Show or set player login limitations"}
+};
+/// \todo Need some pragma pack? Else explain why in a comment.
+#define CliTotalCmds sizeof(Commands)/sizeof(CliCommand)
+
+#if PLATFORM == PLATFORM_WINDOWS
+int utf8printf(const char* str,...)
+{
+ UTF8PRINTF(stdout,str,1);
+ return 0;
+}
+#define UTF8ZPRINTF utf8printf
+#else
+#define UTF8ZPRINTF printf
+#endif
+
+/// Create a character dump file
+void CliWritePlayerDump(char*command,pPrintf zprintf)
+{
+ char * file = strtok(command, " ");
+ char * p2 = strtok(NULL, " ");
+ if(!file || !p2)
+ {
+ zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n");
+ return;
+ }
+
+ std::string name;
+ if(!consoleToUtf8(p2,name)) // convert from console encoding to utf8
+ return;
+
+ if(!normalizePlayerName(name))
+ {
+ zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n");
+ return;
+ }
+
+ uint32 guid = objmgr.GetPlayerGUIDByName(name);
+ if(!guid)
+ guid = atoi(p2);
+
+ if(!guid)
+ {
+ zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n");
+ return;
+ }
+
+ PlayerDumpWriter().WriteDump(file, guid);
+}
+
+/// Load a character from a dump file
+void CliLoadPlayerDump(char*command,pPrintf zprintf)
+{
+ char * file = strtok(command, " ");
+ char * acc = strtok(NULL, " ");
+ if (!file ||!acc)
+ {
+ zprintf("Syntax is: loadpdump $filename $account ($newname) ($newguid)\r\n");
+ return;
+ }
+
+ uint32 account_id = objmgr.GetAccountByAccountName(acc);
+ if(!account_id)
+ {
+ account_id = atoi(acc);
+ if(account_id)
+ {
+ std::string acc_name;
+ if(!objmgr.GetAccountNameByAccount(account_id,acc_name))
+ {
+ zprintf("Failed to load the character! Account not exist.\r\n");
+ return;
+ }
+ }
+ else
+ {
+ zprintf("Failed to load the character! Account not exist.\r\n");
+ return;
+ }
+ }
+
+ char * name_str = strtok(NULL, " ");
+ char * guid_str = name_str ? strtok(NULL, " ") : NULL;
+
+ uint32 guid = guid_str ? atoi(guid_str) : 0;
+
+ std::string name;
+ if(name_str)
+ {
+ if(!consoleToUtf8(name_str,name)) // convert from console encoding to utf8
+ return;
+
+ if(!normalizePlayerName(name))
+ {
+ zprintf("Syntax is: loadpdump $filename $account ($newname) ($newguid)\r\n");
+ return;
+ }
+ }
+
+ if(PlayerDumpReader().LoadDump(file, account_id, name, guid))
+ zprintf("Character loaded successfully!\r\n");
+ else
+ zprintf("Failed to load the character!\r\n");
+}
+
+/// Reload the scripts and notify the players
+void CliLoadScripts(char*command,pPrintf zprintf)
+{
+ char const *del=strtok(command," ");
+ if (!del)
+ del="";
+ if(!LoadScriptingModule(del)) // Error report is already done by LoadScriptingModule
+ return;
+
+ sWorld.SendWorldText(LANG_SCRIPTS_RELOADED);
+}
+
+/// Delete a user account and all associated characters in this realm
+/// \todo This function has to be enhanced to respect the login/realm split (delete char, delete account chars in realm, delete account chars in realm then delete account
+void CliDelete(char*command,pPrintf zprintf)
+{
+ ///- Get the account name from the command line
+ char *account_name_str=strtok(command," ");
+ if(!account_name_str)
+ {
+ // \r\n is used because this function can also be called from RA
+ zprintf("Syntax is: delete $account\r\n");
+ return;
+ }
+
+ std::string account_name;
+ if(!consoleToUtf8(account_name_str,account_name)) // convert from console encoding to utf8
+ return;
+
+ AccountOpResult result = accmgr.DeleteAccount(accmgr.GetId(account_name));
+ switch(result)
+ {
+ case AOR_OK:
+ zprintf("We deleted account: %s\r\n",account_name.c_str());
+ break;
+ case AOR_NAME_NOT_EXIST:
+ zprintf("User %s does not exist\r\n",account_name.c_str());
+ break;
+ case AOR_DB_INTERNAL_ERROR:
+ zprintf("User %s NOT deleted (probably sql file format was updated)\r\n",account_name.c_str());
+ break;
+ default:
+ zprintf("User %s NOT deleted (unknown error)\r\n",account_name.c_str());
+ break;
+ }
+}
+
+void CliCharDelete(char*command,pPrintf zprintf)
+{
+ char *character_name_str = strtok(command," ");
+
+ if(!character_name_str)
+ {
+ zprintf("Syntax is: chardelete $character_name\r\n");
+ return;
+ }
+
+ std::string character_name;
+ if(!consoleToUtf8(character_name_str,character_name)) // convert from console encoding to utf8
+ return;
+
+ if(!normalizePlayerName(character_name))
+ {
+ zprintf("Syntax is: chardelete $character_name\r\n");
+ return;
+ }
+
+ Player *player = objmgr.GetPlayer(character_name.c_str());
+
+ uint64 character_guid;
+ uint32 account_id;
+
+ if(player)
+ {
+ character_guid = player->GetGUID();
+ account_id = player->GetSession()->GetAccountId();
+ player->GetSession()->KickPlayer();
+ }
+ else
+ {
+ character_guid = objmgr.GetPlayerGUIDByName(character_name);
+ if(!character_guid)
+ {
+ zprintf("Player %s not found!\r\n",character_name.c_str());
+ return;
+ }
+
+ account_id = objmgr.GetPlayerAccountIdByGUID(character_guid);
+ }
+
+ Player::DeleteFromDB(character_guid, account_id, true);
+ zprintf("Player %s (Guid: %u AccountId: %u) deleted\r\n",character_name.c_str(),GUID_LOPART(character_guid),account_id);
+}
+
+/// Broadcast a message to the World
+void CliBroadcast(char *text,pPrintf zprintf)
+{
+ std::string textUtf8;
+ if(!consoleToUtf8(text,textUtf8)) // convert from console encoding to utf8
+ return;
+
+ sWorld.SendWorldText(LANG_SYSTEMMESSAGE,textUtf8.c_str());
+ zprintf("Broadcasting to the world: %s\r\n",textUtf8.c_str());
+}
+
+/// Print the list of commands and associated description
+void CliHelp(char*,pPrintf zprintf)
+{
+ for (unsigned int x=0;x<CliTotalCmds;x++)
+ zprintf("%-13s - %s.\r\n",Commands[x].cmd ,Commands[x].description);
+}
+
+/// Exit the realm
+void CliExit(char*,pPrintf zprintf)
+{
+ zprintf( "Exiting daemon...\r\n" );
+ World::m_stopEvent = true;
+}
+
+/// Restart the server (with some delay) as soon as no active connections remain on the server
+void CliIdleRestart(char* command,pPrintf zprintf)
+{
+ char *args = strtok(command," ");
+
+ if(!args)
+ {
+ zprintf("Syntax is: idlerestart $seconds|cancel\r\n");
+ return;
+ }
+
+ if(std::string(args)=="cancel")
+ {
+ sWorld.ShutdownCancel();
+ }
+ else
+ {
+
+ uint32 time = atoi(args);
+
+ ///- Prevent interpret wrong arg value as 0 secs shutdown time
+ if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
+ {
+ zprintf("Syntax is: idlerestart $seconds|cancel\r\n");
+ return;
+ }
+
+ sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART|SHUTDOWN_MASK_IDLE);
+ }
+}
+
+/// Restart the server with some delay
+void CliRestart(char* command,pPrintf zprintf)
+{
+ char *args = strtok(command," ");
+
+ if(!args)
+ {
+ zprintf("Syntax is: restart $seconds|cancel\r\n");
+ return;
+ }
+
+ if(std::string(args)=="cancel")
+ {
+ sWorld.ShutdownCancel();
+ }
+ else
+ {
+ int32 time = atoi(args);
+
+ ///- Prevent interpret wrong arg value as 0 secs shutdown time
+ if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
+ {
+ zprintf("Syntax is: restart $seconds|cancel\r\n");
+ return;
+ }
+
+ sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART);
+ }
+}
+
+/// Shutdown the server (with some delay) as soon as no active connections remain on the server
+void CliIdleShutdown(char* command,pPrintf zprintf)
+{
+ char *args = strtok(command," ");
+
+ if(!args)
+ {
+ zprintf("Syntax is: idleshutdown $seconds|cancel\r\n");
+ return;
+ }
+
+ if(std::string(args)=="cancel")
+ {
+ sWorld.ShutdownCancel();
+ }
+ else
+ {
+
+ uint32 time = atoi(args);
+
+ ///- Prevent interpret wrong arg value as 0 secs shutdown time
+ if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
+ {
+ zprintf("Syntax is: idleshutdown $seconds|cancel\r\n");
+ return;
+ }
+
+ sWorld.ShutdownServ(time,SHUTDOWN_MASK_IDLE);
+ }
+}
+
+/// Shutdown the server with some delay
+void CliShutdown(char* command,pPrintf zprintf)
+{
+ char *args = strtok(command," ");
+
+ if(!args)
+ {
+ zprintf("Syntax is: shutdown $seconds|cancel\r\n");
+ return;
+ }
+
+ if(std::string(args)=="cancel")
+ {
+ sWorld.ShutdownCancel();
+ }
+ else
+ {
+ int32 time = atoi(args);
+
+ ///- Prevent interpret wrong arg value as 0 secs shutdown time
+ if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
+ {
+ zprintf("Syntax is: shutdown $seconds|cancel\r\n");
+ return;
+ }
+
+ sWorld.ShutdownServ(time);
+ }
+}
+
+/// Display info on users currently in the realm
+void CliInfo(char*,pPrintf zprintf)
+{
+ uint32 activeClientsNum = sWorld.GetActiveSessionCount();
+ uint32 queuedClientsNum = sWorld.GetQueuedSessionCount();
+ uint32 maxActiveClientsNum = sWorld.GetMaxActiveSessionCount();
+ uint32 maxQueuedClientsNum = sWorld.GetMaxQueuedSessionCount();
+ std::string timeStr = secsToTimeString(sWorld.GetUptime(),true);
+
+ zprintf("Online players: %u (max: %u) queued: %u (max: %u) Uptime: %s\r\n",activeClientsNum,maxActiveClientsNum,queuedClientsNum,maxQueuedClientsNum,timeStr.c_str());
+
+ ///- Get the list of accounts ID logged to the realm
+ QueryResult *resultDB = CharacterDatabase.Query("SELECT name,account FROM characters WHERE online > 0");
+
+ if (!resultDB)
+ return;
+
+ ///- Display the list of account/characters online
+ zprintf("=====================================================================\r\n");
+ zprintf("| Account | Character | IP | GM | TBC |\r\n");
+ zprintf("=====================================================================\r\n");
+
+ ///- Circle through accounts
+ do
+ {
+ Field *fieldsDB = resultDB->Fetch();
+ std::string name = fieldsDB[0].GetCppString();
+ uint32 account = fieldsDB[1].GetUInt32();
+
+ ///- Get the username, last IP and GM level of each account
+ // No SQL injection. account is uint32.
+ // 0 1 2 3
+ QueryResult *resultLogin = loginDatabase.PQuery("SELECT username, last_ip, gmlevel, tbc FROM account WHERE id = '%u'",account);
+
+ if(resultLogin)
+ {
+ Field *fieldsLogin = resultLogin->Fetch();
+ zprintf("|%15s| %20s | %15s |%4d|%5d|\r\n",
+ fieldsLogin[0].GetString(),name.c_str(),fieldsLogin[1].GetString(),fieldsLogin[2].GetUInt32(),fieldsLogin[3].GetUInt32());
+
+ delete resultLogin;
+ }
+ else
+ zprintf("|<Error> | %20s |<Error> |<Er>|<Err>|\r\n",name.c_str());
+
+ }while(resultDB->NextRow());
+
+ delete resultDB;
+
+ zprintf("=====================================================================\r\n");
+}
+
+/// Display a list of banned accounts and ip addresses
+void CliBanList(char*,pPrintf zprintf)
+{
+ bool found = false;
+ ///- Get the list of banned accounts and display them
+ QueryResult *result = loginDatabase.Query("SELECT id,username FROM account WHERE id IN (SELECT id FROM account_banned WHERE active = 1)");
+ if(result)
+ {
+ found = true;
+
+ zprintf("Currently Banned Accounts:\r\n");
+ zprintf("===============================================================================\r\n");
+ zprintf("| Account | BanDate | UnbanDate | Banned By | Ban Reason |\r\n");
+ do
+ {
+ zprintf("-------------------------------------------------------------------------------\r\n");
+ Field *fields = result->Fetch();
+ // No SQL injection. id is uint32.
+ QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u AND active = 1 ORDER BY unbandate", fields[0].GetUInt32());
+ if (banInfo)
+ {
+ Field *fields2 = banInfo->Fetch();
+ do
+ {
+ time_t t_ban = fields2[0].GetUInt64();
+ tm* aTm_ban = localtime(&t_ban);
+ zprintf("|%-15.15s|", fields[1].GetString());
+ zprintf("%02d-%02d-%02d %02d:%02d|", aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min);
+ if ( fields2[0].GetUInt64() == fields2[1].GetUInt64() )
+ zprintf(" permanent |");
+ else
+ {
+ time_t t_unban = fields2[1].GetUInt64();
+ tm* aTm_unban = localtime(&t_unban);
+ zprintf("%02d-%02d-%02d %02d:%02d|",aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min);
+ }
+ zprintf("%-15.15s|%-15.15s|\r\n",fields2[2].GetString(),fields2[3].GetString());
+ }while ( banInfo->NextRow() );
+ delete banInfo;
+ }
+ }while( result->NextRow() );
+ zprintf("===============================================================================\r\n");
+ delete result;
+ }
+
+ ///- Get the list of banned IP addresses and display them
+ result = loginDatabase.Query( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) ORDER BY unbandate" );
+ if(result)
+ {
+ found = true;
+
+ zprintf("Currently Banned IPs:\r\n");
+ zprintf("===============================================================================\r\n");
+ zprintf("| IP | BanDate | UnbanDate | Banned By | Ban Reason |\r\n");
+ do
+ {
+ zprintf("-------------------------------------------------------------------------------\r\n");
+ Field *fields = result->Fetch();
+ time_t t_ban = fields[1].GetUInt64();
+ tm* aTm_ban = localtime(&t_ban);
+ zprintf("|%-15.15s|", fields[0].GetString());
+ zprintf("%02d-%02d-%02d %02d:%02d|", aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min);
+ if ( fields[1].GetUInt64() == fields[2].GetUInt64() )
+ zprintf(" permanent |");
+ else
+ {
+ time_t t_unban = fields[2].GetUInt64();
+ tm* aTm_unban = localtime(&t_unban);
+ zprintf("%02d-%02d-%02d %02d:%02d|", aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min);
+ }
+ zprintf("%-15.15s|%-15.15s|\r\n", fields[3].GetString(), fields[4].GetString());
+ }while( result->NextRow() );
+ zprintf("===============================================================================\r\n");
+ delete result;
+ }
+
+ if(!found)
+ zprintf("We do not have banned users\r\n");
+}
+
+/// Ban an IP address or a user account
+void CliBan(char*command,pPrintf zprintf)
+{
+ ///- Get the command parameter
+ char* type_str = strtok((char*)command, " ");
+ char* nameOrIP_str = strtok(NULL, " ");
+ char* duration_str = strtok(NULL," ");
+ char* reason_str = strtok(NULL,"");
+
+ if(!type_str||!nameOrIP_str||!duration_str||!reason_str)// ?!? input of single char "0"-"9" wouldn't detect when with: || !atoi(duration)
+ {
+ zprintf("Syntax: ban account|ip|character $AccountOrIpOrCharacter $duration[s|m|h|d] $reason \r\n");
+ return;
+ }
+
+ std::string type;
+ if(!consoleToUtf8(type_str,type)) // convert from console encoding to utf8
+ return;
+
+ std::string nameOrIP;
+ if(!consoleToUtf8(nameOrIP_str,nameOrIP)) // convert from console encoding to utf8
+ return;
+
+ std::string duration;
+ if(!consoleToUtf8(duration_str,duration)) // convert from console encoding to utf8
+ return;
+
+ std::string reason;
+ if(!consoleToUtf8(reason_str,reason)) // convert from console encoding to utf8
+ return;
+
+ switch (sWorld.BanAccount(type, nameOrIP, duration, reason, "Set by console."))
+ {
+ case BAN_SUCCESS:
+ if(atoi(duration_str)>0)
+ zprintf("%s is banned for %s. Reason: %s.\r\n",nameOrIP.c_str(),secsToTimeString(TimeStringToSecs(duration_str),true,false).c_str(),reason.c_str());
+ else
+ zprintf("%s is banned permanently. Reason: %s.\r\n",nameOrIP.c_str(),reason.c_str());
+ break;
+ case BAN_NOTFOUND:
+ zprintf("%s %s not found\r\n", type.c_str(), nameOrIP.c_str());
+ break;
+ case BAN_SYNTAX_ERROR:
+ zprintf("Syntax: ban account|ip|character $AccountOrIpOrCharacter $duration[s|m|h|d] $reason \r\n");
+ break;
+ }
+}
+
+/// Display %MaNGOS version
+void CliVersion(char*,pPrintf zprintf)
+{
+ //<--maybe better append to info cmd
+ zprintf( "%s (world-daemon)\r\n", _FULLVERSION );
+}
+
+/// Unban an IP adress or a user account
+void CliRemoveBan(char *command,pPrintf zprintf)
+{
+ ///- Get the command parameter
+ char *type_str = strtok(command," ");
+ char *nameorip_str = strtok(NULL," ");
+ if(!nameorip_str||!type_str)
+ {
+ zprintf("Syntax is: unban account|ip|character $nameorip\r\n");
+ return;
+ }
+
+ std::string type;
+ if(!consoleToUtf8(type_str,type)) // convert from console encoding to utf8
+ return;
+
+ std::string nameorip;
+ if(!consoleToUtf8(nameorip_str,nameorip)) // convert from console encoding to utf8
+ return;
+
+ if (!sWorld.RemoveBanAccount(type, nameorip))
+ zprintf("%s %s not found\r\n", type.c_str(), nameorip.c_str());
+ else
+ zprintf("We removed ban from %s: %s\r\n",type_str,nameorip.c_str());
+}
+
+/// Display the list of GMs
+void CliListGM(char*,pPrintf zprintf)
+{
+
+ ///- Get the accounts with GM Level >0
+ Field *fields;
+
+ QueryResult *result = loginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" );
+ if(result)
+ {
+
+ zprintf("Current gamemasters:\r\n");
+ zprintf("========================\r\n");
+ zprintf("| Account | GM |\r\n");
+ zprintf("========================\r\n");
+
+ ///- Circle through them. Display username and GM level
+ do
+ {
+ fields = result->Fetch();
+ zprintf("|%15s|", fields[0].GetString());
+ zprintf("%6s|\r\n",fields[1].GetString());
+ }while( result->NextRow() );
+
+ zprintf("========================\r\n");
+ delete result;
+ }
+ else
+ {
+ zprintf("No gamemasters\r\n");
+ }
+}
+
+/// Set the GM level of an account
+void CliSetGM(char *command,pPrintf zprintf)
+{
+ ///- Get the command line arguments
+ char *szAcc = strtok(command," ");
+ char *szLevel = strtok(NULL," ");
+
+ if(!szAcc||!szLevel) //wrong syntax 'setgm' without name
+ {
+ zprintf("Syntax is: setgm $account $number (0 - normal, 3 - gamemaster)>\r\n");
+ return;
+ }
+
+ //wow it's ok,let's hope it was integer given
+ int lev=atoi(szLevel); //get int anyway (0 if error)
+
+ std::string safe_account_name;
+ if(!consoleToUtf8(szAcc,safe_account_name)) // convert from console encoding to utf8
+ return;
+
+ ///- Convert Account name to Upper Format
+ AccountMgr::normilizeString(safe_account_name);
+
+ ///- Escape the account name to allow quotes in names
+ loginDatabase.escape_string(safe_account_name);
+
+ ///- Try to find the account, then update the GM level
+ // No SQL injection (account name is escaped)
+ QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",safe_account_name.c_str());
+
+ if (result)
+ {
+ Field *fields = result->Fetch();
+ uint32 account_id = fields[0].GetUInt32();
+ delete result;
+
+ WorldSession* session = sWorld.FindSession(account_id);
+ if(session)
+ session->SetSecurity(lev);
+
+ // No SQL injection (account name is escaped)
+ loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE username = '%s'",lev,safe_account_name.c_str());
+ zprintf("We set %s gmlevel %d\r\n",safe_account_name.c_str(),lev);
+ }
+ else
+ {
+ zprintf("No account %s found\r\n",safe_account_name.c_str());
+ }
+}
+
+/// Set password for account
+void CliSetPassword(char *command,pPrintf zprintf)
+{
+ ///- Get the command line arguments
+ char *szAcc = strtok(command," ");
+ char *szPassword1 = strtok(NULL," ");
+ char *szPassword2 = strtok(NULL," ");
+
+ if(!szAcc||!szPassword1 || !szPassword2)
+ {
+ zprintf("Syntax is: setpass $account $password $password\r\n");
+ return;
+ }
+
+ std::string account_name;
+ if(!consoleToUtf8(szAcc,account_name)) // convert from console encoding to utf8
+ return;
+
+ std::string pass1;
+ if(!consoleToUtf8(szPassword1,pass1)) // convert from console encoding to utf8
+ return;
+
+ std::string pass2;
+ if(!consoleToUtf8(szPassword2,pass2)) // convert from console encoding to utf8
+ return;
+
+ uint32 acc_id = accmgr.GetId(szAcc);
+ if (!acc_id)
+ {
+ zprintf("Account '%s' does not exist!\r\n", account_name.c_str());
+ return;
+ }
+
+ if (pass1 != pass2)
+ {
+ zprintf("Password does not match the confirm password, password not changed!\r\n");
+ return;
+ }
+
+ AccountOpResult result = accmgr.ChangePassword(acc_id, pass1);
+
+ switch(result)
+ {
+ case AOR_OK:
+ zprintf("The password was changed for account '%s' (ID: %u).\r\n",account_name.c_str(),acc_id);
+ break;
+ case AOR_PASS_TOO_LONG:
+ zprintf("Password can't be longer than 16 characters (client limit), password not changed!\r\n");
+ break;
+ case AOR_NAME_NOT_EXIST:
+ zprintf("Account '%s' does not exist!\r\n", account_name.c_str());
+ break;
+ case AOR_DB_INTERNAL_ERROR:
+ zprintf("Password not changed! (probably sql file format was updated)\r\n");
+ break;
+ default:
+ zprintf("Password not changed! (unknown error\r\n");
+ break;
+ }
+}
+
+/// Create an account
+void CliCreate(char *command,pPrintf zprintf)
+{
+ //I see no need in this function (why would an admin personally create accounts
+ //instead of using account registration page or accessing db directly?)
+ //but still let it be
+
+ ///- %Parse the command line arguments
+ char *szAcc = strtok(command, " ");
+ char *szPassword = strtok(NULL, " ");
+ if(!szAcc || !szPassword)
+ {
+ zprintf("Syntax is: create $username $password\r\n");
+ return;
+ }
+
+ std::string account_name;
+ if(!consoleToUtf8(szAcc,account_name)) // convert from console encoding to utf8
+ return;
+
+ std::string password;
+ if(!consoleToUtf8(szPassword,password)) // convert from console encoding to utf8
+ return;
+
+ AccountOpResult result = accmgr.CreateAccount(account_name, password);
+ switch(result)
+ {
+ case AOR_OK:
+ zprintf("User %s with password %s created successfully\r\n",account_name.c_str(),password.c_str());
+ break;
+ case AOR_NAME_TOO_LONG:
+ zprintf("Username %s is too long\r\n", account_name.c_str());
+ break;
+ case AOR_NAME_ALREDY_EXIST:
+ zprintf("User %s already exists\r\n",account_name.c_str());
+ break;
+ case AOR_DB_INTERNAL_ERROR:
+ zprintf("User %s with password %s NOT created (probably sql file format was updated)\r\n",account_name.c_str(),password.c_str());
+ break;
+ default:
+ zprintf("User %s with password %s NOT created (unknown error)\r\n",account_name.c_str(),password.c_str());
+ break;
+ }
+}
+
+/// Command parser and dispatcher
+void ParseCommand( pPrintf zprintf, char* input)
+{
+ unsigned int x;
+ bool bSuccess=false;
+ if (!input)
+ return;
+
+ unsigned int l=strlen(input);
+ char *supposedCommand=NULL,* arguments=(char*)("");
+ if(l)
+ {
+ ///- Get the command and the arguments
+ supposedCommand = strtok(input," ");
+ if (supposedCommand)
+ {
+ if (l>strlen(supposedCommand))
+ arguments=&input[strlen(supposedCommand)+1];
+
+ ///- Circle through the command table and, if found, put the command in the queue
+ for ( x=0;x<CliTotalCmds;x++)
+ if(!strcmp(Commands[x].cmd,supposedCommand))
+ {
+ sWorld.QueueCliCommand(new CliCommandHolder(&Commands[x], arguments, zprintf));
+ bSuccess=true;
+ break;
+ }
+
+ ///- Display an error message if the command is unknown
+ if(x==CliTotalCmds)
+ zprintf("Unknown command: %s\r\n", input);
+ }
+ }
+ if (!bSuccess)
+ zprintf("mangos>");
+}
+
+/// Kick a character out of the realm
+void CliKick(char*command,pPrintf zprintf)
+{
+ char *kickName = strtok(command, " ");
+
+ if (!kickName)
+ {
+ zprintf("Syntax is: kick $charactername\r\n");
+ return;
+ }
+
+ std::string name;
+ if(!consoleToUtf8(kickName,name)) // convert from console encoding to utf8
+ return;
+
+ if(!normalizePlayerName(name))
+ return;
+
+ sWorld.KickPlayer(name);
+}
+
+/// Teleport a character to location
+void CliTele(char*command,pPrintf zprintf)
+{
+ char *charName = strtok(command, " ");
+ char *locName = strtok(NULL, " ");
+
+ if (!charName || !locName)
+ {
+ zprintf("Syntax is: tele $charactername $location\r\n");
+ return;
+ }
+
+ std::string name = charName;
+ if(!consoleToUtf8(charName,name)) // convert from console encoding to utf8
+ return;
+
+ if(!normalizePlayerName(name))
+ return;
+
+ std::string location;
+ if(!consoleToUtf8(locName,location)) // convert from console encoding to utf8
+ return;
+
+ WorldDatabase.escape_string(location);
+ QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",location.c_str());
+ if (!result)
+ {
+ zprintf(objmgr.GetMangosStringForDBCLocale(LANG_COMMAND_TELE_NOTFOUND),"\r\n");
+ return;
+ }
+
+ Field *fields = result->Fetch();
+ float x = fields[0].GetFloat();
+ float y = fields[1].GetFloat();
+ float z = fields[2].GetFloat();
+ float ort = fields[3].GetFloat();
+ int mapid = fields[4].GetUInt16();
+ delete result;
+
+ if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
+ {
+ zprintf(objmgr.GetMangosStringForDBCLocale(LANG_INVALID_TARGET_COORD),"\r\n",x,y,mapid);
+ return;
+ }
+
+ Player *chr = objmgr.GetPlayer(name.c_str());
+ if (chr)
+ {
+
+ if(chr->IsBeingTeleported()==true)
+ {
+ zprintf(objmgr.GetMangosStringForDBCLocale(LANG_IS_TELEPORTED),"\r\n",chr->GetName());
+ return;
+ }
+
+ if(chr->isInFlight())
+ {
+ zprintf(objmgr.GetMangosStringForDBCLocale(LANG_CHAR_IN_FLIGHT),"\r\n",chr->GetName());
+ return;
+ }
+
+ zprintf(objmgr.GetMangosStringForDBCLocale(LANG_TELEPORTING_TO),"\r\n",chr->GetName(),"", location.c_str());
+
+ chr->SaveRecallPosition();
+
+ chr->TeleportTo(mapid,x,y,z,chr->GetOrientation());
+ }
+ else if (uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()))
+ {
+ zprintf(objmgr.GetMangosStringForDBCLocale(LANG_TELEPORTING_TO),"\r\n",name.c_str(), objmgr.GetMangosStringForDBCLocale(LANG_OFFLINE), location.c_str());
+ Player::SavePositionInDB(mapid,x,y,z,ort,MapManager::Instance().GetZoneId(mapid,x,y),guid);
+ }
+ else
+ zprintf(objmgr.GetMangosStringForDBCLocale(LANG_NO_PLAYER),"\r\n",name.c_str());
+}
+
+/// Display/Define the 'Message of the day' for the realm
+void CliMotd(char*command,pPrintf zprintf)
+{
+
+ if (strlen(command) == 0)
+ {
+ zprintf("Current Message of the day: \r\n%s\r\n", sWorld.GetMotd());
+ return;
+ }
+ else
+ {
+ std::string commandUtf8;
+ if(!consoleToUtf8(command,commandUtf8)) // convert from console encoding to utf8
+ return;
+
+ sWorld.SetMotd(commandUtf8);
+ zprintf("Message of the day changed to:\r\n%s\r\n", commandUtf8.c_str());
+ }
+}
+
+/// Comment me
+/// \todo What is CorpsesErase for?
+void CliCorpses(char*,pPrintf)
+{
+ CorpsesErase();
+}
+
+/// Set the level of logging
+void CliSetLogLevel(char*command,pPrintf zprintf)
+{
+ char *NewLevel = strtok(command, " ");
+ if (!NewLevel)
+ {
+ zprintf("Syntax is: setloglevel $loglevel\r\n");
+ return;
+ }
+ sLog.SetLogLevel(NewLevel);
+}
+
+/// Display the server uptime
+void CliUpTime(char*,pPrintf zprintf)
+{
+ uint32 uptime = sWorld.GetUptime();
+ std::string suptime = secsToTimeString(uptime,true,(uptime > 86400));
+ zprintf("Server has been up for: %s\r\n", suptime.c_str());
+}
+
+/// Set/Unset the TBC flag for an account
+void CliSetTBC(char *command,pPrintf zprintf)
+{
+ ///- Get the command line arguments
+ char *szAcc = strtok(command," ");
+ char *szTBC = strtok(NULL," ");
+
+ if(!szAcc||!szTBC)
+ {
+ zprintf("Syntax is: setbc $account $number (0 - normal, 1 - tbc)>\r\n");
+ return;
+ }
+
+ int lev=atoi(szTBC); //get int anyway (0 if error)
+
+ if((lev > 1)|| (lev < 0))
+ {
+ zprintf("Syntax is: setbc $account $number (0 - normal, 1 - tbc)>\r\n");
+ return;
+ }
+
+ ///- Escape the account name to allow quotes in names
+ std::string safe_account_name;
+ if(!consoleToUtf8(szAcc,safe_account_name)) // convert from console encoding to utf8
+ return;
+
+ ///- Convert Account name to Upper Format
+ AccountMgr::normilizeString(safe_account_name);
+
+ ///- Escape the account name to allow quotes in names
+ loginDatabase.escape_string(safe_account_name);
+
+ // No SQL injection (account name is escaped)
+ QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'",safe_account_name.c_str());
+
+ if (result)
+ {
+ // No SQL injection (account name is escaped)
+ loginDatabase.PExecute("UPDATE account SET tbc = '%d' WHERE username = '%s'",lev,safe_account_name.c_str());
+ zprintf("We set %s to expansion allowed %d\r\n",safe_account_name.c_str(),lev);
+
+ delete result;
+ }
+ else
+ {
+ zprintf("No account %s found\r\n",safe_account_name.c_str());
+ }
+}
+
+/// Save all players
+void CliSave(char*,pPrintf zprintf)
+{
+ ///- Save players
+ ObjectAccessor::Instance().SaveAllPlayers();
+ zprintf( objmgr.GetMangosStringForDBCLocale(LANG_PLAYERS_SAVED) );
+
+ ///- Send a message
+ sWorld.SendWorldText(LANG_PLAYERS_SAVED);
+}
+
+/// Send a message to a player in game
+void CliSend(char *playerN,pPrintf zprintf)
+{
+ ///- Get the command line arguments
+ char* name_str = strtok((char*)playerN, " ");
+ char* msg_str = strtok(NULL, "");
+
+ if(!name_str || !msg_str)
+ {
+ zprintf("Syntax: send $player $message (Player name is case sensitive)\r\n");
+ return;
+ }
+
+ std::string name;
+ if(!consoleToUtf8(name_str,name)) // convert from console encoding to utf8
+ return;
+
+ std::string msg;
+ if(!consoleToUtf8(msg_str,msg)) // convert from console encoding to utf8
+ return;
+
+ if(!normalizePlayerName(name))
+ {
+ zprintf("Syntax: send $player $message (Player name is case sensitive)\r\n");
+ return;
+ }
+
+ ///- Find the player and check that he is not logging out.
+ Player *rPlayer = objmgr.GetPlayer(name.c_str());
+ if(!rPlayer)
+ {
+ zprintf("Player %s not found!\r\n", name.c_str());
+ return;
+ }
+
+ if (rPlayer->GetSession()->isLogingOut())
+ {
+ zprintf("Cannot send message while player %s is logging out!\r\n",name.c_str());
+ return;
+ }
+
+ ///- Send the message
+ //Use SendAreaTriggerMessage for fastest delivery.
+ rPlayer->GetSession()->SendAreaTriggerMessage("%s", msg.c_str());
+ rPlayer->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r");
+
+ //Confirmation message
+ zprintf("Message '%s' sent to %s\r\n",msg.c_str(), name.c_str());
+}
+
+void CliPLimit(char *args,pPrintf zprintf)
+{
+ if(*args)
+ {
+ char* param = strtok((char*)args, " ");
+ if(!param || !*param)
+ return;
+
+ int l = strlen(param);
+
+ if( strncmp(param,"player",l) == 0 )
+ sWorld.SetPlayerLimit(-SEC_PLAYER);
+ else if(strncmp(param,"moderator",l) == 0 )
+ sWorld.SetPlayerLimit(-SEC_MODERATOR);
+ else if(strncmp(param,"gamemaster",l) == 0 )
+ sWorld.SetPlayerLimit(-SEC_GAMEMASTER);
+ else if(strncmp(param,"administrator",l) == 0 )
+ sWorld.SetPlayerLimit(-SEC_ADMINISTRATOR);
+ else if(strncmp(param,"reset",l) == 0 )
+ sWorld.SetPlayerLimit(sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT));
+ else
+ {
+ int val = atoi(param);
+ if(val < -SEC_ADMINISTRATOR) val = -SEC_ADMINISTRATOR;
+
+ sWorld.SetPlayerLimit(val);
+ }
+
+ // kick all low security level players
+ if(sWorld.GetPlayerAmountLimit() > SEC_PLAYER)
+ sWorld.KickAllLess(sWorld.GetPlayerSecurityLimit());
+ }
+
+ uint32 pLimit = sWorld.GetPlayerAmountLimit();
+ AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit();
+ char const* secName = "";
+ switch(allowedAccountType)
+ {
+ case SEC_PLAYER: secName = "Player"; break;
+ case SEC_MODERATOR: secName = "Moderator"; break;
+ case SEC_GAMEMASTER: secName = "Gamemaster"; break;
+ case SEC_ADMINISTRATOR: secName = "Administrator"; break;
+ default: secName = "<unknown>"; break;
+ }
+
+ zprintf("Player limits: amount %u, min. security level %s.\r\n",pLimit,secName);
+}
+
+/// @}
+
+#ifdef linux
+// Non-blocking keypress detector, when return pressed, return 1, else always return 0
+int kb_hit_return()
+{
+ struct timeval tv;
+ fd_set fds;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
+ return FD_ISSET(STDIN_FILENO, &fds);
+}
+#endif
+
+/// %Thread start
+void CliRunnable::run()
+{
+ ///- Init new SQL thread for the world database (one connection call enough)
+ WorldDatabase.ThreadStart(); // let thread do safe mySQL requests
+
+ char commandbuf[256];
+
+ ///- Display the list of available CLI functions then beep
+ sLog.outString();
+ /// \todo Shoudn't we use here also the sLog singleton?
+ CliHelp(NULL,&UTF8ZPRINTF);
+
+ if(sConfig.GetBoolDefault("BeepAtStart", true))
+ {
+ printf("\a"); // \a = Alert
+ }
+
+ // print this here the first time
+ // later it will be printed after command queue updates
+ printf("mangos>");
+
+ ///- As long as the World is running (no World::m_stopEvent), get the command line and handle it
+ while (!World::m_stopEvent)
+ {
+ fflush(stdout);
+ #ifdef linux
+ while (!kb_hit_return() && !World::m_stopEvent)
+ // With this, we limit CLI to 10commands/second
+ usleep(100);
+ if (World::m_stopEvent)
+ break;
+ #endif
+ char *command = fgets(commandbuf,sizeof(commandbuf),stdin);
+ if (command != NULL)
+ {
+ for(int x=0;command[x];x++)
+ if(command[x]=='\r'||command[x]=='\n')
+ {
+ command[x]=0;
+ break;
+ }
+ //// \todo Shoudn't we use here also the sLog singleton?
+ ParseCommand(&UTF8ZPRINTF,command);
+ }
+ else if (feof(stdin))
+ {
+ World::m_stopEvent = true;
+ }
+ }
+
+ ///- End the database thread
+ WorldDatabase.ThreadEnd(); // free mySQL thread resources
+}
diff --git a/src/trinitycore/CliRunnable.h b/src/trinitycore/CliRunnable.h
new file mode 100644
index 00000000000..2dc4a51d89a
--- /dev/null
+++ b/src/trinitycore/CliRunnable.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup mangosd
+/// @{
+/// \file
+
+#ifndef __CLIRUNNABLE_H
+#define __CLIRUNNABLE_H
+
+/// Command Line Interface handling thread
+class CliRunnable : public ZThread::Runnable
+{
+ public:
+ void run();
+};
+#endif
+/// @}
diff --git a/src/trinitycore/Main.cpp b/src/trinitycore/Main.cpp
new file mode 100644
index 00000000000..27e8c0861ce
--- /dev/null
+++ b/src/trinitycore/Main.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup mangosd Mangos Daemon
+/// @{
+/// \file
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "Config/ConfigEnv.h"
+#include "Log.h"
+#include "Master.h"
+
+#ifndef _TRINITY_CORE_CONFIG
+# define _TRINITY_CORE_CONFIG "trinitycore.conf"
+#endif //_TRINITY_CORE_CONFIG
+
+// Format is YYYYMMDDRR where RR is the change in the conf file
+// for that day.
+#ifndef _TRINITY_CORE_CONFVER
+# define _TRINITY_CORE_CONFVER 2008022901
+#endif //_TRINITY_CORE_CONFVER
+
+#ifdef WIN32
+#include "ServiceWin32.h"
+char serviceName[] = "mangosd";
+char serviceLongName[] = "MaNGOS world service";
+char serviceDescription[] = "Massive Network Game Object Server";
+/*
+ * -1 - not in service mode
+ * 0 - stopped
+ * 1 - running
+ * 2 - paused
+ */
+int m_ServiceStatus = -1;
+#endif
+
+DatabaseType WorldDatabase; ///< Accessor to the world database
+DatabaseType CharacterDatabase; ///< Accessor to the character database
+DatabaseType loginDatabase; ///< Accessor to the realm/login database
+
+uint32 realmID; ///< Id of the realm
+
+/// Print out the usage string for this program on the console.
+void usage(const char *prog)
+{
+ sLog.outString("Usage: \n %s [<options>]\n"
+ " -c config_file use config_file as configuration file\n\r"
+ #ifdef WIN32
+ " Running as service functions:\n\r"
+ " --service run as service\n\r"
+ " -s install install service\n\r"
+ " -s uninstall uninstall service\n\r"
+ #endif
+ ,prog);
+}
+
+/// Launch the mangos server
+extern int main(int argc, char **argv)
+{
+ ///- Command line parsing to get the configuration file name
+ char const* cfg_file = _TRINITY_CORE_CONFIG;
+ int c=1;
+ while( c < argc )
+ {
+ if( strcmp(argv[c],"-c") == 0)
+ {
+ if( ++c >= argc )
+ {
+ sLog.outError("Runtime-Error: -c option requires an input argument");
+ usage(argv[0]);
+ return 1;
+ }
+ else
+ cfg_file = argv[c];
+ }
+
+ #ifdef WIN32
+ ////////////
+ //Services//
+ ////////////
+ if( strcmp(argv[c],"-s") == 0)
+ {
+ if( ++c >= argc )
+ {
+ sLog.outError("Runtime-Error: -s option requires an input argument");
+ usage(argv[0]);
+ return 1;
+ }
+ if( strcmp(argv[c],"install") == 0)
+ {
+ if (WinServiceInstall())
+ sLog.outString("Installing service");
+ return 1;
+ }
+ else if( strcmp(argv[c],"uninstall") == 0)
+ {
+ if(WinServiceUninstall())
+ sLog.outString("Uninstalling service");
+ return 1;
+ }
+ else
+ {
+ sLog.outError("Runtime-Error: unsupported option %s",argv[c]);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ if( strcmp(argv[c],"--service") == 0)
+ {
+ WinServiceRun();
+ }
+ ////
+ #endif
+ ++c;
+ }
+
+ if (!sConfig.SetSource(cfg_file))
+ {
+ sLog.outError("Could not find configuration file %s.", cfg_file);
+ return 1;
+ }
+
+ sLog.outString("Using configuration file %s.", cfg_file);
+
+ uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
+ if (confVersion < _TRINITY_CORE_CONFVER)
+ {
+ sLog.outError("*****************************************************************************");
+ sLog.outError(" WARNING: Your trinitycore.conf version indicates your conf file is out of date!");
+ sLog.outError(" Please check for updates, as your current default values may cause");
+ sLog.outError(" strange behavior.");
+ sLog.outError("*****************************************************************************");
+ clock_t pause = 3000 + clock();
+
+ while (pause > clock()) {}
+ }
+
+ ///- and run the 'Master'
+ /// \todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd?
+ return sMaster.Run();
+
+ // at sMaster return function exist with codes
+ // 0 - normal shutdown
+ // 1 - shutdown at error
+ // 2 - restart command used, this code can be used by restarter for restart mangosd
+}
+
+/// @}
diff --git a/src/trinitycore/Makefile.am b/src/trinitycore/Makefile.am
new file mode 100644
index 00000000000..624bfb93c37
--- /dev/null
+++ b/src/trinitycore/Makefile.am
@@ -0,0 +1,78 @@
+# Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+## Process this file with automake to produce Makefile.in
+
+## Build world list daemon as standalone program
+bin_PROGRAMS = trinity-core
+
+## Preprocessor flags
+trinity_core_CPPFLAGS = \
+$(MYSQL_INCLUDES) \
+$(POSTGRE_INCLUDES) \
+-I$(top_srcdir)/dep/include \
+-I$(top_srcdir)/src/shared \
+-I$(top_srcdir)/src/framework \
+-I$(top_srcdir)/src/game \
+-D_TRINITY_CORE_CONFIG='"$(sysconfdir)/trinitycore.conf"'
+
+## Sources
+trinity_core_SOURCES = \
+$(srcdir)/CliRunnable.cpp \
+$(srcdir)/CliRunnable.h \
+$(srcdir)/Main.cpp \
+$(srcdir)/Master.cpp \
+$(srcdir)/Master.h \
+$(srcdir)/RASocket.cpp \
+$(srcdir)/RASocket.h \
+$(srcdir)/WorldRunnable.cpp \
+$(srcdir)/WorldRunnable.h
+
+## Convenience libs to add
+trinity_core_LDADD = \
+$(top_builddir)/src/game/libgame.a \
+$(top_builddir)/src/shared/libshared.a \
+$(top_builddir)/src/shared/vmap/libvmaps.a \
+$(top_builddir)/src/framework/libmangosframework.a \
+$(top_builddir)/dep/src/sockets/libmangossockets.a \
+$(top_builddir)/dep/src/zthread/libZThread.la \
+$(top_builddir)/dep/src/g3dlite/libg3dlite.a
+
+if USE_TSCRIPTS
+trinity_core_LDADD += $(top_builddir)/src/bindings/scripts/libtrinityscript.la
+else
+trinity_core_LDADD += $(top_builddir)/src/bindings/interface/libtrinityscript.la
+endif
+
+## Linker flags
+trinity_core_LDFLAGS = $(MYSQL_LIBS) $(POSTGRE_LIBS) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
+
+## Additional files to install
+sysconf_DATA = \
+ trinitycore.conf.dist
+
+## Prevend overwrite of the config file, if its already installed
+install-data-hook:
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ dest=`echo $$p | sed -e s/.dist//`; \
+ if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \
+ echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \
+ else \
+ echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$dest"; \
+ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$dest; \
+ fi; \
+ done
+
diff --git a/src/trinitycore/Master.cpp b/src/trinitycore/Master.cpp
new file mode 100644
index 00000000000..cf094bbd048
--- /dev/null
+++ b/src/trinitycore/Master.cpp
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup mangosd
+*/
+
+#include "Master.h"
+#include "sockets/SocketHandler.h"
+#include "sockets/ListenSocket.h"
+#include "WorldSocket.h"
+#include "WorldSocketMgr.h"
+#include "WorldRunnable.h"
+#include "World.h"
+#include "Log.h"
+#include "Timer.h"
+#include <signal.h>
+#include "Policies/SingletonImp.h"
+#include "SystemConfig.h"
+#include "Config/ConfigEnv.h"
+#include "Database/DatabaseEnv.h"
+#include "CliRunnable.h"
+#include "RASocket.h"
+#include "ScriptCalls.h"
+#include "Util.h"
+
+#include "sockets/TcpSocket.h"
+#include "sockets/Utility.h"
+#include "sockets/Parse.h"
+#include "sockets/Socket.h"
+
+#ifdef WIN32
+#include "ServiceWin32.h"
+extern int m_ServiceStatus;
+#endif
+
+/// \todo Warning disabling not useful under VC++2005. Can somebody say on which compiler it is useful?
+#pragma warning(disable:4305)
+
+INSTANTIATE_SINGLETON_1( Master );
+
+volatile uint32 Master::m_masterLoopCounter = 0;
+
+class FreezeDetectorRunnable : public ZThread::Runnable
+{
+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)
+ {
+ if(!_delaytime)
+ return;
+ sLog.outString("Starting up anti-freeze thread (%u seconds max stuck time)...",_delaytime/1000);
+ m_loops = 0;
+ w_loops = 0;
+ m_lastchange = 0;
+ w_lastchange = 0;
+ while(!World::m_stopEvent)
+ {
+ ZThread::Thread::sleep(1000);
+ uint32 curtime = getMSTime();
+ //DEBUG_LOG("anti-freeze: time=%u, counters=[%u; %u]",curtime,Master::m_masterLoopCounter,World::m_worldLoopCounter);
+
+ // normal work
+ if(m_loops != Master::m_masterLoopCounter)
+ {
+ m_lastchange = curtime;
+ m_loops = Master::m_masterLoopCounter;
+ }
+ // possible freeze
+ else if(getMSTimeDiff(m_lastchange,curtime) > _delaytime)
+ {
+ sLog.outError("Main/Sockets Thread hangs, kicking out server!");
+ *((uint32 volatile*)NULL) = 0; // bang crash
+ }
+
+ // normal work
+ if(w_loops != World::m_worldLoopCounter)
+ {
+ w_lastchange = curtime;
+ w_loops = World::m_worldLoopCounter;
+ }
+ // possible freeze
+ else if(getMSTimeDiff(w_lastchange,curtime) > _delaytime)
+ {
+ sLog.outError("World Thread hangs, kicking out server!");
+ *((uint32 volatile*)NULL) = 0; // bang crash
+ }
+ }
+ sLog.outString("Anti-freeze thread exiting without problems.");
+ }
+};
+
+Master::Master()
+{
+}
+
+Master::~Master()
+{
+}
+
+/// Main function
+int Master::Run()
+{
+ sLog.outString( "%s (core-daemon)", _FULLVERSION );
+ sLog.outString( "<Ctrl-C> to stop.\n" );
+
+ sLog.outTitle( " ______ __");
+ sLog.outTitle( "/\\__ _\\ __ __/\\ \\__");
+ sLog.outTitle( "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\ ,_\\ __ __");
+ sLog.outTitle( " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\");
+ sLog.outTitle( " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\");
+ sLog.outTitle( " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\");
+ sLog.outTitle( " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\");
+ sLog.outTitle( " C O R E /\\___/");
+ sLog.outTitle( "http://TrinityCore.org \\/__/\n");
+
+ /// worldd PID file creation
+ std::string pidfile = sConfig.GetStringDefault("PidFile", "");
+ if(!pidfile.empty())
+ {
+ uint32 pid = CreatePIDFile(pidfile);
+ if( !pid )
+ {
+ sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() );
+ return 1;
+ }
+
+ sLog.outString( "Daemon PID: %u\n", pid );
+ }
+
+ ///- Start the databases
+ if (!_StartDB())
+ return 1;
+
+ ///- Initialize the World
+ sWorld.SetInitialWorldSettings();
+
+ ///- Launch the world listener socket
+ port_t wsport = sWorld.getConfig(CONFIG_PORT_WORLD);
+ std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0");
+
+ SocketHandler h;
+ ListenSocket<WorldSocket> worldListenSocket(h);
+ if (worldListenSocket.Bind(bind_ip.c_str(),wsport))
+ {
+ clearOnlineAccounts();
+ sLog.outError("MaNGOS cannot bind to %s:%d",bind_ip.c_str(), wsport);
+ return 1;
+ }
+
+ h.Add(&worldListenSocket);
+
+ ///- Catch termination signals
+ _HookSignals();
+
+ ///- Launch WorldRunnable thread
+ ZThread::Thread t(new WorldRunnable);
+ t.setPriority ((ZThread::Priority )2);
+
+ // set server online
+ loginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID);
+
+#ifdef WIN32
+ if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
+#else
+ if (sConfig.GetBoolDefault("Console.Enable", true))
+#endif
+ {
+ ///- Launch CliRunnable thread
+ ZThread::Thread td1(new CliRunnable);
+ }
+
+ ///- Launch the RA listener socket
+ ListenSocket<RASocket> RAListenSocket(h);
+ if (sConfig.GetBoolDefault("Ra.Enable", false))
+ {
+ port_t raport = sConfig.GetIntDefault( "Ra.Port", 3443 );
+ std::string stringip = sConfig.GetStringDefault( "Ra.IP", "0.0.0.0" );
+ ipaddr_t raip;
+ if(!Utility::u2ip(stringip, raip))
+ sLog.outError( "MaNGOS RA can not bind to ip %s", stringip.c_str());
+ else if (RAListenSocket.Bind(raip, raport))
+ sLog.outError( "MaNGOS RA can not bind to port %d on %s", raport, stringip.c_str());
+ else
+ {
+ h.Add(&RAListenSocket);
+
+ sLog.outString("Starting Remote access listner on port %d on %s", raport, stringip.c_str());
+ }
+ }
+
+ ///- Handle affinity for multiple processors and process priority on Windows
+ #ifdef WIN32
+ {
+ HANDLE hProcess = GetCurrentProcess();
+
+ uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
+ if(Aff > 0)
+ {
+ ULONG_PTR appAff;
+ ULONG_PTR sysAff;
+
+ if(GetProcessAffinityMask(hProcess,&appAff,&sysAff))
+ {
+ ULONG_PTR curAff = Aff & appAff; // remove non accessible processors
+
+ if(!curAff )
+ {
+ sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for mangosd. Accessible processors bitmask (hex): %x",Aff,appAff);
+ }
+ else
+ {
+ if(SetProcessAffinityMask(hProcess,curAff))
+ sLog.outString("Using processors (bitmask, hex): %x", curAff);
+ else
+ sLog.outError("Can't set used processors (hex): %x",curAff);
+ }
+ }
+ sLog.outString();
+ }
+
+ bool Prio = sConfig.GetBoolDefault("ProcessPriority", false);
+
+// if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/)
+ if(Prio)
+ {
+ if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS))
+ sLog.outString("TrinityCore process priority class set to HIGH");
+ else
+ sLog.outError("ERROR: Can't set mangosd process priority class.");
+ sLog.outString();
+ }
+ }
+ #endif
+
+ uint32 realCurrTime, realPrevTime;
+ realCurrTime = realPrevTime = getMSTime();
+
+ uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME);
+
+ // maximum counter for next ping
+ uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / socketSelecttime));
+ uint32 loopCounter = 0;
+
+ ///- Start up freeze catcher thread
+ uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0);
+ if(freeze_delay)
+ {
+ FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable();
+ fdr->SetDelayTime(freeze_delay*1000);
+ ZThread::Thread t(fdr);
+ t.setPriority(ZThread::High);
+ }
+
+ ///- Wait for termination signal
+ while (!World::m_stopEvent)
+ {
+ ++Master::m_masterLoopCounter;
+#ifdef WIN32
+ if (m_ServiceStatus == 0) World::m_stopEvent = true;
+ while (m_ServiceStatus == 2) Sleep(1000);
+#endif
+ if (realPrevTime > realCurrTime)
+ realPrevTime = 0;
+
+ realCurrTime = getMSTime();
+ sWorldSocketMgr.Update( getMSTimeDiff(realPrevTime,realCurrTime) );
+ realPrevTime = realCurrTime;
+
+ h.Select(0, socketSelecttime);
+
+ // ping if need
+ if( (++loopCounter) == numLoops )
+ {
+ loopCounter = 0;
+ sLog.outDetail("Ping MySQL to keep connection alive");
+ delete WorldDatabase.Query("SELECT 1 FROM command LIMIT 1");
+ delete loginDatabase.Query("SELECT 1 FROM realmlist LIMIT 1");
+ delete CharacterDatabase.Query("SELECT 1 FROM bugreport LIMIT 1");
+ }
+ }
+
+ // set server offline
+ loginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID);
+
+ ///- Remove signal handling before leaving
+ _UnhookSignals();
+
+ // when the main thread closes the singletons get unloaded
+ // since worldrunnable uses them, it will crash if unloaded after master
+ t.wait();
+
+ ///- Clean database before leaving
+ clearOnlineAccounts();
+
+ ///- Wait for delay threads to end
+ CharacterDatabase.HaltDelayThread();
+ WorldDatabase.HaltDelayThread();
+ loginDatabase.HaltDelayThread();
+
+ sLog.outString( "Halting process..." );
+
+ #ifdef WIN32
+ if (sConfig.GetBoolDefault("Console.Enable", true))
+ {
+ // 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;
+
+ 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;
+
+ 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;
+
+ 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;
+ BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb);
+ }
+ #endif
+
+ // for some unknown reason, unloading scripts here and not in worldrunnable
+ // fixes a memory leak related to detaching threads from the module
+ UnloadScriptingModule();
+
+ return sWorld.GetShutdownMask() & SHUTDOWN_MASK_RESTART ? 2 : 0;
+}
+
+/// Initialize connection to the databases
+bool Master::_StartDB()
+{
+ ///- Get world database info from configuration file
+ std::string dbstring;
+ if(!sConfig.GetString("WorldDatabaseInfo", &dbstring))
+ {
+ sLog.outError("Database not specified in configuration file");
+ return false;
+ }
+ sLog.outString("World Database: %s", dbstring.c_str());
+
+ ///- Initialise the world database
+ if(!WorldDatabase.Initialize(dbstring.c_str()))
+ {
+ sLog.outError("Cannot connect to world database %s",dbstring.c_str());
+ return false;
+ }
+
+ if(!sConfig.GetString("CharacterDatabaseInfo", &dbstring))
+ {
+ sLog.outError("Character Database not specified in configuration file");
+ return false;
+ }
+ sLog.outString("Character Database: %s", dbstring.c_str());
+
+ ///- Initialise the Character database
+ if(!CharacterDatabase.Initialize(dbstring.c_str()))
+ {
+ sLog.outError("Cannot connect to Character database %s",dbstring.c_str());
+ return false;
+ }
+
+ ///- Get login database info from configuration file
+ if(!sConfig.GetString("LoginDatabaseInfo", &dbstring))
+ {
+ sLog.outError("Login database not specified in configuration file");
+ return false;
+ }
+
+ ///- Initialise the login database
+ sLog.outString("Login Database: %s", dbstring.c_str() );
+ if(!loginDatabase.Initialize(dbstring.c_str()))
+ {
+ sLog.outError("Cannot connect to login database %s",dbstring.c_str());
+ return false;
+ }
+
+ ///- Get the realm Id from the configuration file
+ realmID = sConfig.GetIntDefault("RealmID", 0);
+ if(!realmID)
+ {
+ sLog.outError("Realm ID not defined in configuration file");
+ return false;
+ }
+ sLog.outString("Realm running as realm ID %d", realmID);
+
+ ///- Clean the database before starting
+ clearOnlineAccounts();
+
+ QueryResult* result = WorldDatabase.Query("SELECT version FROM db_version LIMIT 1");
+ if(result)
+ {
+ Field* fields = result->Fetch();
+
+ sLog.outString("Using %s", fields[0].GetString());
+ delete result;
+ }
+ else
+ sLog.outString("Using unknown world database.");
+
+ return true;
+}
+
+/// 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'?
+ loginDatabase.PExecute(
+ "UPDATE account SET online = 0 WHERE online > 0 "
+ "AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = '%d')",realmID);
+
+
+ CharacterDatabase.Execute("UPDATE characters SET online = 0");
+}
+
+/// Handle termination signals
+/** Put the World::m_stopEvent to 'true' if a termination signal is caught **/
+void Master::_OnSignal(int s)
+{
+ switch (s)
+ {
+ case SIGINT:
+ case SIGTERM:
+ #ifdef _WIN32
+ case SIGBREAK:
+ #endif
+ World::m_stopEvent = true;
+ break;
+ }
+
+ signal(s, _OnSignal);
+}
+
+/// Define hook '_OnSignal' for all termination signals
+void Master::_HookSignals()
+{
+ signal(SIGINT, _OnSignal);
+ signal(SIGTERM, _OnSignal);
+ #ifdef _WIN32
+ signal(SIGBREAK, _OnSignal);
+ #endif
+}
+
+/// Unhook the signals before leaving
+void Master::_UnhookSignals()
+{
+ signal(SIGINT, 0);
+ signal(SIGTERM, 0);
+ #ifdef _WIN32
+ signal(SIGBREAK, 0);
+ #endif
+}
diff --git a/src/trinitycore/Master.h b/src/trinitycore/Master.h
new file mode 100644
index 00000000000..ce756545720
--- /dev/null
+++ b/src/trinitycore/Master.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup mangosd
+/// @{
+/// \file
+
+#ifndef _MASTER_H
+#define _MASTER_H
+
+#include "Common.h"
+#include "Policies/Singleton.h"
+
+/// Start the server
+class Master
+{
+ public:
+ Master();
+ ~Master();
+ int Run();
+ static volatile uint32 m_masterLoopCounter;
+
+ private:
+ bool _StartDB();
+
+ void _HookSignals();
+ void _UnhookSignals();
+ static void _OnSignal(int s);
+
+ void clearOnlineAccounts();
+};
+
+#define sMaster MaNGOS::Singleton<Master>::Instance()
+#endif
+/// @}
diff --git a/src/trinitycore/RASocket.cpp b/src/trinitycore/RASocket.cpp
new file mode 100644
index 00000000000..8baa5d34e39
--- /dev/null
+++ b/src/trinitycore/RASocket.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup mangosd
+*/
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "Log.h"
+#include "RASocket.h"
+#include "World.h"
+#include "Config/ConfigEnv.h"
+#include "Util.h"
+#include "AccountMgr.h"
+
+/// \todo Make this thread safe if in the future 2 admins should be able to log at the same time.
+SOCKET r;
+
+#define dropclient {Sendf("I'm busy right now, come back later."); \
+ SetCloseAndDelete(); \
+ return; \
+ }
+
+uint32 iSession=0; ///< Session number (incremented each time a new connection is made)
+unsigned int iUsers=0; ///< Number of active administrators
+
+typedef int(* pPrintf)(const char*,...);
+
+void ParseCommand(pPrintf zprintf, char*command);
+
+/// RASocket constructor
+RASocket::RASocket(ISocketHandler &h): TcpSocket(h)
+{
+
+ ///- Increment the session number
+ iSess =iSession++ ;
+
+ ///- Get the config parameters
+ bSecure = sConfig.GetBoolDefault( "RA.Secure", true );
+ iMinLevel = sConfig.GetIntDefault( "RA.MinLevel", 3 );
+
+ ///- Initialize buffer and data
+ iInputLength=0;
+ buff=new char[RA_BUFF_SIZE];
+ stage=NONE;
+}
+
+/// RASocket destructor
+RASocket::~RASocket()
+{
+ ///- Delete buffer and decrease active admins count
+ delete [] buff;
+
+ sLog.outRALog("Connection was closed.\n");
+
+ if(stage==OK)
+ iUsers--;
+}
+
+/// Accept an incoming connection
+void RASocket::OnAccept()
+{
+ std::string ss=GetRemoteAddress();
+ sLog.outRALog("Incoming connection from %s.\n",ss.c_str());
+ ///- If there is already an active admin, drop the connection
+ if(iUsers)
+ dropclient
+
+ ///- Else print Motd
+ Sendf("%s\r\n",sWorld.GetMotd());
+}
+
+/// Read data from the network
+void RASocket::OnRead()
+{
+ ///- Read data and check input length
+ TcpSocket::OnRead();
+
+ unsigned int sz=ibuf.GetLength();
+ if(iInputLength+sz>=RA_BUFF_SIZE)
+ {
+ sLog.outRALog("Input buffer overflow, possible DOS attack.\n");
+ SetCloseAndDelete();
+ return;
+ }
+
+ ///- If there is already an active admin (other than you), drop the connection
+ if(stage!=OK && iUsers)
+ dropclient
+
+ char *inp = new char [sz+1];
+ ibuf.Read(inp,sz);
+
+ /// \todo Can somebody explain this 'Linux bugfix'?
+ if(stage==NONE)
+ if(sz>4) //linux remote telnet
+ if(memcmp(inp ,"USER ",5))
+ {
+ delete [] inp;return;
+ printf("lin bugfix");
+ } //linux bugfix
+
+ ///- Discard data after line break or line feed
+ bool gotenter=false;
+ unsigned int y=0;
+ for(;y<sz;y++)
+ if(inp[y]=='\r'||inp[y]=='\n')
+ {
+ gotenter=true;
+ break;
+ }
+
+ //No buffer overflow (checked above)
+ memcpy(&buff[iInputLength],inp,y);
+ iInputLength+=y;
+ delete [] inp;
+ if(gotenter)
+ {
+
+ buff[iInputLength]=0;
+ iInputLength=0;
+ switch(stage)
+ {
+ /// <ul> <li> If the input is 'USER <username>'
+ case NONE:
+ if(!memcmp(buff,"USER ",5)) //got "USER" cmd
+ {
+ szLogin=&buff[5];
+
+ ///- Get the gmlevel and password from the account table
+ std::string login = szLogin;
+
+ ///- Convert Account name to Upper Format
+ AccountMgr::normilizeString(login);
+
+ ///- Escape the Login to allow quotes in names
+ loginDatabase.escape_string(login);
+
+ QueryResult* result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE username = '%s'",login.c_str());
+
+ ///- If the user is not found, deny access
+ if(!result)
+ {
+ Sendf("-No such user.\r\n");
+ sLog.outRALog("User %s does not exist.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ else
+ {
+ Field *fields = result->Fetch();
+
+ //szPass=fields[0].GetString();
+
+ ///- if gmlevel is too low, deny access
+ if(fields[0].GetUInt32()<iMinLevel)
+ {
+ Sendf("-Not enough privileges.\r\n");
+ sLog.outRALog("User %s has no privilege.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ } else
+ {
+ stage=LG;
+ }
+ delete result;
+ }
+ }
+ break;
+ ///<li> If the input is 'PASS <password>' (and the user already gave his username)
+ case LG:
+ if(!memcmp(buff,"PASS ",5)) //got "PASS" cmd
+ { //login+pass ok
+ ///- If password is correct, increment the number of active administrators
+ std::string login = szLogin;
+ std::string pw = &buff[5];
+
+ AccountMgr::normilizeString(login);
+ AccountMgr::normilizeString(pw);
+ loginDatabase.escape_string(login);
+ loginDatabase.escape_string(pw);
+
+ QueryResult *check = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", login.c_str(), pw.c_str());
+ if(check)
+ {
+ delete check;
+ r=GetSocket();
+ stage=OK;
+ ++iUsers;
+
+ Sendf("+Logged in.\r\n");
+ sLog.outRALog("User %s has logged in.\n",szLogin.c_str());
+ Sendf("mangos>");
+ }
+ else
+ {
+ ///- Else deny access
+ Sendf("-Wrong pass.\r\n");
+ sLog.outRALog("User %s has failed to log in.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ }
+ break;
+ ///<li> If user is logged, parse and execute the command
+ case OK:
+ if(strlen(buff))
+ {
+ sLog.outRALog("Got '%s' cmd.\n",buff);
+ ParseCommand(&RASocket::zprintf , buff);
+ }
+ else
+ Sendf("mangos>");
+ break;
+ ///</ul>
+ };
+
+ }
+}
+
+/// Output function
+int RASocket::zprintf( const char * szText, ... )
+{
+ if( !szText ) return 0;
+ va_list ap;
+ va_start(ap, szText);
+ /// \todo Remove buffer length here. Can be >1024 (e.g. list of users)
+ char *megabuffer=new char[1024];
+ unsigned int sz=vsnprintf(megabuffer,1024,szText,ap);
+ #ifdef RA_CRYPT
+ Encrypt(megabuffer,sz);
+ #endif
+
+ send(r,megabuffer,sz,0);
+ delete [] megabuffer;
+ va_end(ap);
+ return 0;
+}
diff --git a/src/trinitycore/RASocket.h b/src/trinitycore/RASocket.h
new file mode 100644
index 00000000000..d082c45112a
--- /dev/null
+++ b/src/trinitycore/RASocket.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup mangosd
+/// @{
+/// \file
+
+#ifndef _RASOCKET_H
+#define _RASOCKET_H
+
+#include "Common.h"
+#include "sockets/TcpSocket.h"
+
+#define RA_BUFF_SIZE 1024
+
+class ISocketHandler;
+
+/// Remote Administration socket
+class RASocket: public TcpSocket
+{
+ public:
+
+ RASocket(ISocketHandler& h);
+ ~RASocket();
+
+ void OnAccept();
+ void OnRead();
+
+ private:
+
+ char * buff;
+ std::string szLogin;
+ uint32 iSess;
+ unsigned int iInputLength;
+ bool bLog;
+ bool bSecure; //kick on wrong pass, non exist. user, user with no priv
+ //will protect from DOS, bruteforce attacks
+ //some 'smart' protection must be added for more scurity
+ uint8 iMinLevel;
+ enum
+ {
+ NONE, //initial value
+ LG, //only login was entered
+ OK, //both login and pass were given, and they are correct and user have enough priv.
+ }stage;
+
+ static int zprintf( const char * szText, ... );
+};
+#endif
+/// @}
diff --git a/src/trinitycore/TrinityCore.ico b/src/trinitycore/TrinityCore.ico
new file mode 100644
index 00000000000..8df5f0174bd
--- /dev/null
+++ b/src/trinitycore/TrinityCore.ico
Binary files differ
diff --git a/src/trinitycore/TrinityCore.rc b/src/trinitycore/TrinityCore.rc
new file mode 100644
index 00000000000..7e00bb16d8b
--- /dev/null
+++ b/src/trinitycore/TrinityCore.rc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "windows.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APPICON ICON "TrinityCore.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutre (Par défaut système) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,1,6700,670
+ PRODUCTVERSION 0,1,6700,670
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x0L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080004b0"
+ BEGIN
+ VALUE "FileDescription", "TrinityCore"
+ VALUE "FileVersion", "0, 1, 6700, 670"
+ VALUE "InternalName", "TrinityCore"
+ VALUE "LegalCopyright", "Copyright (C) 2008"
+ VALUE "OriginalFilename", "TrinityCore.exe"
+ VALUE "ProductName", "TrinityCore"
+ VALUE "ProductVersion", "0, 1, 6700, 670"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x800, 1200
+ END
+END
+#endif
diff --git a/src/trinitycore/WorldRunnable.cpp b/src/trinitycore/WorldRunnable.cpp
new file mode 100644
index 00000000000..6dae1575ac2
--- /dev/null
+++ b/src/trinitycore/WorldRunnable.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup mangosd
+*/
+
+#include "Common.h"
+#include "World.h"
+#include "WorldRunnable.h"
+#include "Timer.h"
+#include "ObjectAccessor.h"
+#include "MapManager.h"
+
+#include "Database/DatabaseEnv.h"
+
+#ifdef WIN32
+#define WORLD_SLEEP_CONST 50
+#else
+#define WORLD_SLEEP_CONST 100 //Is this still needed?? [On linux some time ago not working 50ms]
+#endif
+
+/// Heartbeat for the World
+void WorldRunnable::run()
+{
+ ///- Init new SQL thread for the world database
+ WorldDatabase.ThreadStart(); // let thread do safe mySQL requests (one connection call enough)
+ sWorld.InitResultQueue();
+
+ uint32 realCurrTime = 0;
+ uint32 realPrevTime = getMSTime();
+
+ uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST
+
+ ///- While we have not World::m_stopEvent, update the world
+ while (!World::m_stopEvent)
+ {
+ ++World::m_worldLoopCounter;
+ realCurrTime = getMSTime();
+
+ uint32 diff = getMSTimeDiff(realPrevTime,realCurrTime);
+
+ sWorld.Update( diff );
+ realPrevTime = realCurrTime;
+
+ // diff (D0) include time of previous sleep (d0) + tick time (t0)
+ // we want that next d1 + t1 == WORLD_SLEEP_CONST
+ // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement
+ // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0
+ if (diff <= WORLD_SLEEP_CONST+prevSleepTime)
+ {
+ prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff;
+ ZThread::Thread::sleep(prevSleepTime);
+ }
+ else
+ prevSleepTime = 0;
+ }
+
+ sWorld.KickAllQueued(); // kick all queued players (and prevent its login at kick in game players)
+ sWorld.KickAll(); // save and kick all players
+ sWorld.UpdateSessions( 1 ); // real players unload required UpdateSessions call
+
+ MapManager::Instance().UnloadAll(); // unload all grids (including locked in memory)
+
+ ///- End the database thread
+ WorldDatabase.ThreadEnd(); // free mySQL thread resources
+}
diff --git a/src/trinitycore/WorldRunnable.h b/src/trinitycore/WorldRunnable.h
new file mode 100644
index 00000000000..2fec658f5d1
--- /dev/null
+++ b/src/trinitycore/WorldRunnable.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup mangosd
+/// @{
+/// \file
+
+#ifndef __WORLDRUNNABLE_H
+#define __WORLDRUNNABLE_H
+
+/// Heartbeat thread for the World
+class WorldRunnable : public ZThread::Runnable
+{
+ public:
+ void run();
+};
+#endif
+/// @}
diff --git a/src/trinitycore/monitor-mangosd b/src/trinitycore/monitor-mangosd
new file mode 100644
index 00000000000..a740ae5e8fa
--- /dev/null
+++ b/src/trinitycore/monitor-mangosd
@@ -0,0 +1,18 @@
+#!/bin/bash
+# Massive Network Game Object Server
+# Monitoring Script
+
+pid=`ps ax | awk '($5 ~ /mangos-worldd/) { print $1 }'`
+cpu=`top -b -n 1 -p $pid | awk '($12 ~ /mangos-worldd/) { print $9 }'`
+#echo $pid
+#echo $cpu
+intcpu=${cpu%.*}
+#echo $intcpu
+if [ "$intcpu" -gt "95" ]
+then
+ kill -9 $pid
+ echo "Killed MaNGOS for exceeding it's cpu limit."
+ echo `date` ", Killed MaNGOS for $intcpu% CPU Usage." >> serverlog
+else
+ echo "MaNGOS Passes the cpu test."
+fi
diff --git a/src/trinitycore/resource.h b/src/trinitycore/resource.h
new file mode 100644
index 00000000000..7e7d8e4b76f
--- /dev/null
+++ b/src/trinitycore/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by TrinityCore.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/trinitycore/run-mangosd b/src/trinitycore/run-mangosd
new file mode 100644
index 00000000000..f307bd9e1ad
--- /dev/null
+++ b/src/trinitycore/run-mangosd
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Trinity Server
+# autorestart Script
+
+while :
+do
+ echo "TrinityCore daemon restarted"
+ echo `date` >> crash.log &
+ ./mangosd | tail -n 20 >> crash.log
+ echo " " >> crash.log &
+ pid=`ps ax | awk '($5 ~ /trinitycore/) { print $1 }'`
+ wait $pid
+ echo `date` ", TrinityCore daemon crashed and restarted." >> serverlog
+done
diff --git a/src/trinitycore/trinitycore.conf.dist b/src/trinitycore/trinitycore.conf.dist
new file mode 100644
index 00000000000..17678bee08d
--- /dev/null
+++ b/src/trinitycore/trinitycore.conf.dist
@@ -0,0 +1,1027 @@
+#####################################
+# MaNGOS Configuration file #
+#####################################
+ConfVersion=2008080101
+
+###################################################################################################################
+# CONNECTIONS AND DIRECTORIES
+#
+# RealmID
+# RealmID must match the realmlist inside the realmd database
+#
+# DataDir
+# Data directory setting.
+# Important: DataDir needs to be quoted, as it is a string which may contain space characters.
+# Example: "@prefix@/share/mangos"
+#
+# LogsDir
+# Logs directory setting.
+# Important: Logs dir must exists, or all logs need to be disabled
+# Default: "" - no log directory prefix, if used log names isn't absolute path
+# then logs will be stored in current directory for run program.
+#
+#
+# LoginDatabaseInfo
+# WorldDatabaseInfo
+# CharacterDatabaseInfo
+# Database connection settings for the world server.
+# Default: hostname;port;username;password;database
+# .;somenumber;username;password;database - use named pipes at Windows
+# Named pipes: mySQL required adding "enable-named-pipe" to [mysqld] section my.ini
+# .;/path/to/unix_socket;username;password;database - use Unix sockets at Unix/Linux
+# Unix sockets: experimental, not tested
+#
+# MaxPingTime
+# Settings for maximum database-ping interval (minutes between pings)
+#
+# WorldServerPort
+# Default WorldServerPort
+#
+# BindIP
+# Bind World Server to IP/hostname
+#
+###################################################################################################################
+
+RealmID = 1
+DataDir = "."
+LogsDir = ""
+LoginDatabaseInfo = "127.0.0.1;3306;root;mangos;realmd"
+WorldDatabaseInfo = "127.0.0.1;3306;root;mangos;mangos"
+CharacterDatabaseInfo = "127.0.0.1;3306;root;mangos;characters"
+MaxPingTime = 30
+WorldServerPort = 8085
+BindIP = "0.0.0.0"
+
+###################################################################################################################
+# PERFORMANCE SETINGS
+#
+# UseProcessors
+# Used processors mask for multi-processors system (Used only at Windows)
+# Default: 0 (selected by OS)
+# number (bitmask value of selected processors)
+#
+# ProcessPriority
+# Process proirity setting (Used only at Windows)
+# Default: 1 (HIGH)
+# 0 (Normal)
+#
+# Compression
+# Compression level for update packages sent to client (1..9)
+# Default: 1 (speed)
+# 9 (best compression)
+#
+# TcpNoDelay
+# TCP Nagle algorithm setting
+# Default: 0 (enable Nagle algorithm, less traffic, more latency)
+# 1 (TCP_NO_DELAY, disable Nagle algorithm, more traffic but less latency)
+#
+# PlayerLimit
+# Maximum number of players in the world. Excluding Mods, GM's and Admins
+# Default: 100
+# 0 (for infinite players)
+# -1 (for Mods, GM's and Admins only)
+# -2 (for GM's and Admins only)
+# -3 (for Admins only)
+#
+# SaveRespawnTimeImmediately
+# Save respawn time for creatures at death and for gameobjects at use/open
+# Default: 1 (save creature/gameobject respawn time without waiting grid unload)
+# 0 (save creature/gameobject respawn time at grid unload)
+#
+# MaxOverspeedPings
+# Maximum overspeed ping count before player kick (minimum is 2, 0 used for disable check)
+# Default: 2
+#
+# GridUnload
+# Unload grids (if you have lot memory you can disable it to speed up player move to new grids second time)
+# Default: 1 (unload grids)
+# 0 (do not unload grids)
+#
+# SocketSelectTime
+# Socket select time (in milliseconds)
+# Default: 10000
+#
+# GridCleanUpDelay
+# Grid clean up delay (in milliseconds)
+# Default: 300000 (5 min)
+#
+# MapUpdateInterval
+# Map update interval (in milliseconds)
+# Default: 100
+#
+# ChangeWeatherInterval
+# Weather update interval (in milliseconds)
+# Default: 600000 (10 min)
+#
+# PlayerSaveInterval
+# Player save interval (in milliseconds)
+# Default: 900000 (15 min)
+#
+# vmap.enableLOS
+# vmap.enableHeight
+# Enable/Disable VMmap support for line of sight and height calculation
+# Default: 1 (true)
+# 0 (false)
+#
+# vmap.ignoreMapIds
+# Map id that will be ignored by VMaps
+# List of ids with delimiter ','
+# If more then one id is defined and spaces are included, the string has to be enclosed by "
+# Example: "369,0,1,530"
+#
+# vmap.ignoreSpellIds
+# These spells are ignored for LoS calculation
+# List of ids with delimiter ','
+#
+# DetectPosCollision
+# Check final move position, summon position, etc for visible collision with other objects or
+# wall (wall only if vmaps are enabled)
+# Default: 1 (enable, required more CPU power usage)
+# 0 (disable, less nice position selection but will less CPU power usage)
+#
+# TargetPosRecalculateRange
+# Max distance from movement target point (+moving unit size) and targeted object (+size)
+# after that new target movmeent point calculated. Max: melee attack range (5), min: contact range (0.5)
+# More distance let have better performence, less distance let have more sensitive reaction at target move.
+# Default: 1.5
+#
+# UpdateUptimeInterval
+# Update realm uptime period in minutes (for save data in 'uptime' table). Must be > 0
+# Default: 10 (minutes)
+#
+# MaxCoreStuckTime
+# Periodically check if the process got freezed, if this is the case force crash after the specified
+# amount of seconds. Must be > 0. Recommended > 10 secs if you use this.
+# Default: 0 (Disabled)
+#
+# AddonChannel
+# Permit/disable the use of the addon channel through the server
+# (some client side addons can stop work correctly with disabled addon channel)
+# Default: 1 (permit addon channel)
+# 0 (do not permit addon channel)
+#
+###################################################################################################################
+
+UseProcessors = 0
+ProcessPriority = 1
+Compression = 1
+TcpNoDelay = 0
+PlayerLimit = 100
+SaveRespawnTimeImmediately = 1
+MaxOverspeedPings = 2
+GridUnload = 1
+SocketSelectTime = 10000
+GridCleanUpDelay = 300000
+MapUpdateInterval = 100
+ChangeWeatherInterval = 600000
+PlayerSaveInterval = 900000
+vmap.enableLOS = 0
+vmap.enableHeight = 0
+vmap.ignoreMapIds = "369"
+vmap.ignoreSpellIds = "7720"
+DetectPosCollision = 1
+TargetPosRecalculateRange = 1.5
+UpdateUptimeInterval = 10
+MaxCoreStuckTime = 0
+AddonChannel = 1
+
+###################################################################################################################
+# SERVER LOGGING
+#
+# LogSQL
+# Enable logging of GM commands - all SQL code will be written to a log file
+# All commands are written to a file: YYYY-MM-DD_logSQL.sql
+# If a new day starts (00:00:00) then a new file is created - the old file will not be deleted.
+# Default: 1 - Write SQL code to logfile
+# 0 - Do not log
+#
+# PidFile
+# World daemon PID file
+# Default: "" - do not create PID file
+# "./worldd.pid" - create PID file (recommended name)
+#
+# LogLevel
+# Server console level of logging
+# 0 = Minimum; 1 = Basic&Error; 2 = Detail; 3 = Full/Debug
+# Default: 3
+#
+# LogTime
+# Include time in server console output [hh:mm:ss]
+# Default: 0 (no time)
+# 1 (print time)
+#
+# LogFile
+# Logfile name
+# Default: "Server.log"
+# "" - Empty name disable creating log file
+#
+# LogTimestamp
+# Logfile with timestamp of server start in name
+# Default: 0 - no timestamp in name
+# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
+#
+# LogFileLevel
+# Server file level of logging
+# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
+# Default: 0
+#
+# LogFilter_TransportMoves
+# LogFilter_CreatureMoves
+# LogFilter_VisibilityChanges
+# Log filters
+# Default: 1 - not include with any log level
+# 0 - include in log if log level permit
+#
+# WorldLogFile
+# Packet logging file for the worldserver
+# Default: "world.log"
+#
+# DBErrorLogFile
+# Log file of DB errors detected at server run
+# Default: "DBErrors.log"
+#
+# CharLogFile
+# Character operations logfile name
+# Default: "Char.log"
+# "" - Empty name disable creating log file
+#
+# CharLogTimestamp
+# Logfile with timestamp of server start in name
+# Default: 0 - no timestamp in name
+# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
+#
+# CharLogDump
+# Write character dump before deleting in Char.log
+# For restoration, cut character data from log starting from
+# line == START DUMP == to line == END DUMP == (without its) in file and load it using loadpdump command
+# Default: 0 - don't include dumping chars to log
+# 1 - include dumping chars to log
+#
+# GmLogFile
+# Log file of gm commands
+# Default: "" (Disable)
+#
+# GmLogTimestamp
+# Logfile with timestamp of server start in name
+# Default: 0 - no timestamp in name
+# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
+#
+# RaLogFile
+# Log file of RA commands
+# Default: "Ra.log"
+# "" - Empty name for disable
+#
+# LogColors
+# Color for messages (format "normal_color details_color debug_color error_color)
+# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
+# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
+# Default: "" - none colors
+# Example: "13 7 11 9"
+#
+###################################################################################################################
+
+LogSQL = 1
+PidFile = ""
+LogLevel = 3
+LogTime = 0
+LogFile = "Server.log"
+LogTimestamp = 0
+LogFileLevel = 0
+LogFilter_TransportMoves = 1
+LogFilter_CreatureMoves = 1
+LogFilter_VisibilityChanges = 1
+WorldLogFile = "world.log"
+DBErrorLogFile = "DBErrors.log"
+CharLogFile = "Char.log"
+CharLogTimestamp = 0
+CharLogDump = 0
+GmLogFile = ""
+GmLogTimestamp = 0
+RaLogFile = ""
+LogColors = ""
+
+###################################################################################################################
+# SERVER SETTINGS
+#
+# GameType
+# Server realm style
+# 0 = NORMAL;1 = PVP; 4 = NORMAL; 6 = RP; 8 = RPPVP
+# also custom type: 16 FFA_PVP (free for all pvp mode like arena PvP in all zones except rest
+# activated places and sanctuaries)
+#
+# RealmZone
+# Server realm zone (set allowed alphabet in character names/etc). See also Strict*Names options.
+#
+# 1 Development - any language (Default)
+# 2 United States - extended-Latin
+# 3 Oceanic - extended-Latin
+# 4 Latin America - extended-Latin
+# 5 Tournament - basic-Latin at create, any at login
+# 6 Korea - East-Asian
+# 7 Tournament - basic-Latin at create, any at login
+# 8 English - extended-Latin
+# 9 German - extended-Latin
+# 10 French - extended-Latin
+# 11 Spanish - extended-Latin
+# 12 Russian - Cyrillic
+# 13 Tournament - basic-Latin at create, any at login
+# 14 Taiwan - East-Asian
+# 15 Tournament - basic-Latin at create, any at login
+# 16 China - East-Asian
+# 17 CN1 - basic-Latin at create, any at login
+# 18 CN2 - basic-Latin at create, any at login
+# 19 CN3 - basic-Latin at create, any at login
+# 20 CN4 - basic-Latin at create, any at login
+# 21 CN5 - basic-Latin at create, any at login
+# 22 CN6 - basic-Latin at create, any at login
+# 23 CN7 - basic-Latin at create, any at login
+# 24 CN8 - basic-Latin at create, any at login
+# 25 Tournament - basic-Latin at create, any at login
+# 26 Test Server - any language
+# 27 Tournament - basic-Latin at create, any at login
+# 28 QA Server - any language
+# 29 CN9 - basic-Latin at create, any at login
+#
+# Expansion
+# Allow server use expansion content
+# Default: 1 - check expansion maps existence, and if client support expansion and account have
+# expansion setting then allow visit expansion maps, allow create new races character)
+# 0 - not check expansion maps existence, not allow wisit its, not allow create new race
+# characters, ignore account expansion setting)
+#
+# DBC.Locale
+# DBC Language Settings
+# 0 = English; 1 = Korean; 2 = French; 3 = German; 4 = Chinese; 5 = Taiwanese; 6 = Spanish; 7 = Spanish Mexico
+# 8 = Russian; 255 = Auto Detect (Default)
+#
+# DeclinedNames
+# Allow russian clients to set and use declined names
+# Default: 0 - do not use declined names, except when the Russian RealmZone is set
+# 1 - use declined names
+#
+# StrictPlayerNames
+# Limit player name to language specific symbols set, not allow create characters, and set rename request and disconnect at not allowed symbols name
+# Default: 0 disable (but limited server timezone dependent client check)
+# 1 basic latin characters (strict)
+# 2 realm zone specific (strict). See RealmZone setting.
+# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
+# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
+# 3 basic latin characters + server timezone specific
+#
+# StrictCharterNames
+# Limit guild/arena team charter names to language specific symbols set, not allow create charters with allowed symbols in name
+# Default: 0 disable
+# 1 basic latin characters (strict)
+# 2 realm zone specific (strict). See RealmZone setting.
+# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
+# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
+# 3 basic latin characters + server timezone specific
+#
+# StrictPetNames
+# Limit pet names to language specific symbols set
+# Default: 0 disable
+# 1 basic latin characters (strict)
+# 2 realm zone specific (strict). See RealmZone setting.
+# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
+# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
+# 3 basic latin characters + server timezone specific
+#
+# CharactersCreatingDisabled
+# Disable characters creating for specific team or any (non-player accounts not affected)
+# Default: 0 - enabled
+# 1 - disabled only for Alliance
+# 2 - disabled only for Horde
+# 3 - disabled for both teams
+#
+# CharactersPerAccount
+# Limit numbers of characters per account (at all realms).
+# Note: this setting limit character creating at _current_ realm base at characters amount at all realms
+# Default: 50
+# The number must be >= CharactersPerRealm
+#
+# CharactersPerRealm
+# Limit numbers of characters for account at realm
+# Default: 10 (client limitation)
+# The number must be between 1 and 10
+#
+# SkipCinematics
+# Disable in-game script movie at first character's login(allows to prevent buggy intro in case of custom start location coordinates)
+# Default: 0 - show intro for each new characrer
+# 1 - show intro only for first character of selected race
+# 2 - disable intro show in all cases
+#
+# MaxPlayerLevel
+# Max level that can be reached by player for experience (in range from 1 to 255).
+# Change not recommended
+# Default: 70
+#
+# MaxHonorPoints
+# Max honor points that player can have.
+# Default: 75000
+#
+# MaxArenaPoints
+# Max arena points that player can have.
+# Default: 5000
+#
+# StartPlayerLevel
+# Staring level that have character at creating (in range 1 to MaxPlayerLevel)
+# Default: 1
+#
+# ActivateWeather
+# Activate weather system
+# Default: 1 (true)
+# 0 (false)
+#
+# Battleground.CastDeserter
+# Cast or not Deserter spell at player who leave battleground in progress
+# Default: 1 (true)
+# 0 (false)
+#
+# Battleground.QueueAnnouncer.Enable
+# Enable queue announcer posting to chat
+# Default: 1 (true)
+# 0 (false)
+#
+# Battleground.QueueAnnouncer.PlayerOnly
+# Enable queue announcer posting to chat
+# Default: 0 (false)
+# 1 (true)
+#
+# CastUnstuck
+# Allow cast or not Unstuck spell at .start or client Help option use
+# Default: 1 (true)
+# 0 (false)
+#
+# Instance.IgnoreLevel
+# Ignore level requirement to enter instance
+# Default: 0 (false)
+# 1 (true)
+#
+# Instance.IgnoreRaid
+# Ignore raid requirement to enter instance
+# Default: 0 (false)
+# 1 (true)
+#
+# Instance.ResetTimeHour
+# The hour of the day (0-23) when the global instance resets occur.
+# Default: 4
+#
+# Instance.UnloadDelay
+# Unload the instance map from memory after some time if no players are inside.
+# Default: 1800000 (miliseconds, i.e 30 minutes)
+# 0 (instance maps are kept in memory until they are reset)
+#
+# Quests.LowLevelHideDiff
+# Quest level difference to hide for player low level quests:
+# if player_level > quest_level + LowLevelQuestsHideDiff then quest "!" mark not show for quest giver
+# Default: 4
+# -1 (show all available quests marks)
+#
+# Quests.HighLevelHideDiff
+# Quest level difference to hide for player high level quests:
+# if player_level < quest_min_level - HighLevelQuestsHideDiff then quest "!" mark not show for quest giver
+# Default: 7
+# -1 (show all available quests marks)
+#
+# MaxPrimaryTradeSkill
+# Max count that player can learn the primary trade skill.
+# Default: 2
+# Max : 10
+#
+# MinPetitionSigns
+# Min signatures count to creating guild (0..9).
+# Default: 9
+#
+# MaxGroupXPDistance
+# Max distance to creature for group memeber to get XP at creature death.
+# Default: 74
+#
+# MailDeliveryDelay
+# Mail delivery delay time for item sending
+# Default: 3600 sec (1 hour)
+#
+# SkillChance.Prospecting
+# For prospecting skillup not possible by default, but can be allowed as custom setting
+# Default: 0 - no skilups
+# 1 - skilups possible
+#
+# Event.Announce
+# Default: 0 (false)
+# 1 (true)
+#
+# BeepAtStart
+# Beep at mangosd start finished (mostly work only at Unix/Linux systems)
+# Default: 1 (true)
+# 0 (false)
+#
+# Motd
+# Message of the Day. Displayed at worldlogin for every user ('@' for a newline).
+#
+###################################################################################################################
+
+GameType = 1
+RealmZone = 1
+Expansion = 1
+DBC.Locale = 255
+DeclinedNames = 0
+StrictPlayerNames = 0
+StrictCharterNames = 0
+StrictPetNames = 0
+CharactersCreatingDisabled = 0
+CharactersPerAccount = 50
+CharactersPerRealm = 10
+SkipCinematics = 0
+MaxPlayerLevel = 70
+MaxHonorPoints = 75000
+MaxArenaPoints = 5000
+StartPlayerLevel = 1
+ActivateWeather = 1
+Battleground.CastDeserter = 1
+Battleground.QueueAnnouncer.Enable = 1
+Battleground.QueueAnnouncer.PlayerOnly = 0
+CastUnstuck = 1
+Instance.IgnoreLevel = 0
+Instance.IgnoreRaid = 0
+Instance.ResetTimeHour = 4
+Instance.UnloadDelay = 1800000
+Quests.LowLevelHideDiff = 4
+Quests.HighLevelHideDiff = 7
+MaxPrimaryTradeSkill = 2
+MinPetitionSigns = 9
+MaxGroupXPDistance = 74
+MailDeliveryDelay = 3600
+SkillChance.Prospecting = 0
+Event.Announce = 0
+BeepAtStart = 1
+Motd = "Welcome to the Massive Network Game Object Server."
+
+###################################################################################################################
+# PLAYER INTERACTION
+#
+# AllowTwoSide.Accounts
+# Allow or not accounts to create characters in the 2 teams in any game type.
+# Default: 0 (Not allowed)
+# 1 (Allowed)
+#
+# AllowTwoSide.Interaction.Chat
+# AllowTwoSide.Interaction.Channel
+# AllowTwoSide.Interaction.Group
+# AllowTwoSide.Interaction.Guild
+# AllowTwoSide.Interaction.Auction
+# AllowTwoSide.Interaction.Mail
+# Allow or not common :chat(say,yell);channel(chat)group(join)guild(join);merge all auction houses for players from
+# different teams, send mail to different team.
+# Default: 0 (Not allowed)
+# 1 (Allowed)
+#
+# AllowTwoSide.WhoList
+# Allow or not show player from both team in who list.
+# Default: 0 (Not allowed)
+# 1 (Allowed)
+#
+# AllowTwoSide.AddFriend
+# Allow or not adding friends from other team in friend list.
+# Default: 0 (Not allowed)
+# 1 (Allowed)
+#
+# TalentsInspecting
+# Allow other players see character talents in inspect dialog (Characters in Gamemaster mode can
+# inspect talents always)
+# Default: 1 (allow)
+# 0 (not allow)
+#
+###################################################################################################################
+
+AllowTwoSide.Accounts = 0
+AllowTwoSide.Interaction.Chat = 0
+AllowTwoSide.Interaction.Channel = 0
+AllowTwoSide.Interaction.Group = 0
+AllowTwoSide.Interaction.Guild = 0
+AllowTwoSide.Interaction.Auction = 0
+AllowTwoSide.Interaction.Mail = 0
+AllowTwoSide.WhoList = 0
+AllowTwoSide.AddFriend = 0
+TalentsInspecting = 1
+
+###################################################################################################################
+# CREATURE SETTINGS
+#
+# ThreatRadius
+# Radius for creature to evade after being pulled away from combat start point
+# If ThreatRadius is less than creature aggro radius then aggro radius will be used
+# Default: 100 yards
+#
+# Rate.Creature.Aggro
+# Aggro radius percent or off.
+# Default: 1 - 100%
+# 1.5 - 150%
+# 0 - off (0%)
+#
+# CreatureFamilyAssistenceRadius
+# Creature family assistence radius
+# Default: 10
+# 0 - off
+#
+# WorldBossLevelDiff
+# Difference for boss dynamic level with target
+# Default: 3
+#
+# Corpse.Decay.NORMAL
+# Corpse.Decay.RARE
+# Corpse.Decay.ELITE
+# Corpse.Decay.RAREELITE
+# Corpse.Decay.WORLDBOSS
+# Seconds until creature corpse will decay without being looted or skinned.
+# Default: 60, 300, 300, 300, 3600
+#
+# Rate.Corpse.Decay.Looted
+# Controls how long the creature corpse stays after it had been looted, as a multiplier of its Corpse.Decay.* config.
+# Default: 0.1
+#
+# Rate.Creature.Normal.Damage
+# Rate.Creature.Elite.Elite.Damage
+# Rate.Creature.Elite.RAREELITE.Damage
+# Rate.Creature.Elite.WORLDBOSS.Damage
+# Rate.Creature.Elite.RARE.Damage
+# Creature Damage Rates.
+# Examples: 2 - creatures will damage 2x, 1.7 - 1.7x.
+#
+# Rate.Creature.Normal.SpellDamage
+# Rate.Creature.Elite.Elite.SpellDamage
+# Rate.Creature.Elite.RAREELITE.SpellDamage
+# Rate.Creature.Elite.WORLDBOSS.SpellDamag
+# Rate.Creature.Elite.RARE.SpellDamage
+# Creature Spell Damage Rates.
+# Examples: 2 - creatures will damage with spells 2x, 1.7 - 1.7x.
+#
+# Rate.Creature.Normal.HP
+# Rate.Creature.Elite.Elite.HP
+# Rate.Creature.Elite.RAREELITE.HP
+# Rate.Creature.Elite.WORLDBOSS.HP
+# Rate.Creature.Elite.RARE.HP
+# Creature Health Ammount Modifier.
+# Examples: 2 - creatures have 2x health, 1.7 - 1.7x.
+#
+###################################################################################################################
+
+ThreatRadius = 100
+Rate.Creature.Aggro = 1
+CreatureFamilyAssistenceRadius = 10
+WorldBossLevelDiff = 3
+Corpse.Decay.NORMAL = 60
+Corpse.Decay.RARE = 300
+Corpse.Decay.ELITE = 300
+Corpse.Decay.RAREELITE = 300
+Corpse.Decay.WORLDBOSS = 3600
+Rate.Corpse.Decay.Looted = 0.1
+Rate.Creature.Normal.Damage = 1
+Rate.Creature.Elite.Elite.Damage = 1
+Rate.Creature.Elite.RAREELITE.Damage = 1
+Rate.Creature.Elite.WORLDBOSS.Damage = 1
+Rate.Creature.Elite.RARE.Damage = 1
+Rate.Creature.Normal.SpellDamage = 1
+Rate.Creature.Elite.Elite.SpellDamage = 1
+Rate.Creature.Elite.RAREELITE.SpellDamage = 1
+Rate.Creature.Elite.WORLDBOSS.SpellDamage = 1
+Rate.Creature.Elite.RARE.SpellDamage = 1
+Rate.Creature.Normal.HP = 1
+Rate.Creature.Elite.Elite.HP = 1
+Rate.Creature.Elite.RAREELITE.HP = 1
+Rate.Creature.Elite.WORLDBOSS.HP = 1
+Rate.Creature.Elite.RARE.HP = 1
+
+###################################################################################################################
+# CHAT SETTINGS
+#
+# ChatFakeMessagePreventing
+# Chat protection from creating fake messages using a lot spaces (other invisible symbols),
+# not applied to addon language messages, but can prevent working old addons
+# that use normal languages for sending data to another clients.
+# Default: 0 (disible fake messages preventing)
+# 1 (enabled fake messages preventing)
+#
+# ChatFlood.MessageCount
+# Chat anti-flood protection, haste message count to activate protection
+# Default: 10
+# 0 (disible anti-flood protection)
+#
+# ChatFlood.MessageDelay
+# Chat anti-flood protection, minimum message delay to count message
+# Default: 1 (in secs)
+#
+# ChatFlood.MuteTime
+# Chat anti-flood protection, mute time at activation flood protection (not saved)
+# Default: 10 (in secs)
+#
+# Channel.RestrictedLfg
+# Restrict use LookupForGroup channel only registered in LFG tool players
+# Default: 1 (allow join to channel only if active in LFG)
+# 0 (allow join to channel in any time)
+#
+# Channel.SilentlyGMJoin
+# Silently join GM characters (security level > 1) to channels
+# Default: 0 (join announcement in normal way)
+# 1 (GM join without announcement)
+#
+###################################################################################################################
+
+ChatFakeMessagePreventing = 0
+ChatFlood.MessageCount = 10
+ChatFlood.MessageDelay = 1
+ChatFlood.MuteTime = 10
+Channel.RestrictedLfg = 1
+Channel.SilentlyGMJoin = 0
+
+###################################################################################################################
+# GAME MASTER SETTINGS
+#
+# GM.WhisperingTo
+# Is GM accepting whispers from player by default or not.
+# Default: 0 (false)
+# 1 (true)
+#
+# GM.InGMList
+# Is GM showed in GM list (if visible) in non-GM state (.gmoff)
+# Default: 0 (false)
+# 1 (true)
+#
+# GM.InWhoList
+# Is GM showed in who list (if visible).
+# Default: 0 (false)
+# 1 (true)
+#
+# GM.LoginState
+# GM mode at login
+# Default: 2 (last save state)
+# 0 (disable)
+# 1 (enable)
+#
+# GM.LogTrade
+# Include GM trade and trade slot enchanting operations in GM log if it enable
+# Default: 1 (include)
+# 0 (not include)
+#
+###################################################################################################################
+
+GM.WhisperingTo = 0
+GM.InGMList = 0
+GM.InWhoList = 0
+GM.LoginState = 2
+GM.LogTrade = 1
+
+###################################################################################################################
+# VISIBILITY AND RADIUSES
+#
+# Visibility.GroupMode
+# Group visibility modes
+# Default: 0 (standard setting: only members from same group can 100% auto detect invisible player)
+# 1 (raid members 100% auto detect invisible player from same raid)
+# 2 (players from same team can 100% auto detect invisible player)
+#
+# Visibility.Distance.Creature
+# Visibility.Distance.Player
+# Visibility distance for different in game object
+# Max limited by active player zone: ~ 166
+# Min limit dependent from objects
+# Default: 66 (cell size)
+# Min limit is max aggro radius (45) * Rate.Creature.Aggro
+#
+# Visibility.Distance.Object
+# Visible distance for gameobject, dynobject, bodies, corpses, bones
+# Min limit is iteraction distance (5)
+#
+# Visibility.Distance.InFlight
+# Visible distance for player in flight
+# Min limit is 0 (not show any objects)
+#
+# Visibility.Distance.Grey.Unit
+# Visibility grey distance for creatures/players (fast changing objects)
+# addition to appropriate object type Visibility.Distance.* use in case visibility removing to
+# object (except corpse around distences) If � is distance and G is grey distance then object
+# make visible if distance to it <= D but make non visible if distance > D+G
+# Default: 1 (yard)
+#
+# Visibility.Distance.Grey.Object
+# Visibility grey distance for dynobjects/gameobjects/corpses/creature bodies
+# Default: 10 (yards)
+#
+#
+###################################################################################################################
+
+Visibility.GroupMode = 0
+Visibility.Distance.Creature = 66
+Visibility.Distance.Player = 66
+Visibility.Distance.Object = 66
+Visibility.Distance.InFlight = 66
+Visibility.Distance.Grey.Unit = 1
+Visibility.Distance.Grey.Object = 10
+
+###################################################################################################################
+# SERVER RATES
+#
+# Rate.Health
+# Rate.Mana
+# Rate.Rage.Income
+# Rate.Rage.Loss
+# Rate.Focus
+# Rate.Loyalty
+# Health and power regeneration and rage income from damage.
+# Default: 1
+#
+# Rate.Skill.Discovery
+# Skill Discovery Rates
+# Default: 1
+#
+# Rate.Drop.Item.Poor
+# Rate.Drop.Item.Normal
+# Rate.Drop.Item.Uncommon
+# Rate.Drop.Item.Rare
+# Rate.Drop.Item.Epic
+# Rate.Drop.Item.Legendary
+# Rate.Drop.Item.Artifact
+# Rate.Drop.Item.Referenced
+# Rate.Drop.Money
+# Drop rates (items by qualify and money)
+# Default: 1
+#
+# Rate.Drop.Money
+# Drop rates
+# Default: 1
+#
+# Rate.XP.Kill
+# Rate.XP.Quest
+# Rate.XP.Explore
+# XP rates
+# Default: 1
+#
+# Rate.XP.PastLevel70
+# XP needed per level past 70 (Rates below 1 not recommended)
+# Default: 1
+#
+# Rate.Rest.InGame
+# Rate.Rest.Offline.InTavernOrCity
+# Rate.Rest.Offline.InWilderness
+# Resting points grow rates (1 - normal, 2 - double rate, 0.5 - half rate, etc) from standard values
+#
+# Rate.Damage.Fall
+# Damage after fall rate. (1 - standard, 2 - double damage, 0.5 - half damage, etc)
+#
+# Rate.Auction.Time
+# Rate.Auction.Deposit
+# Rate.Auction.Cut
+# Auction rates (auction time, deposit get at auction start, auction cut from price at auction end)
+#
+# Rate.Honor
+# Honor gain rate
+#
+# Rate.Mining.Amount
+# Rate.Mining.Next
+# Mining Rates (Mining.Amount changes minimum/maximum usetimes of a deposit,
+# Mining.Next changes chance to have next use of a deposit)
+#
+# Rate.Talent
+# Talent Point rates
+# Default: 1
+#
+# Rate.Reputation.Gain
+# Reputation Gain rate
+# Default: 1
+#
+# Rate.InstanceResetTime
+# Multiplier for the number of days in between global raid/heroic instance resets.
+# Default: 1
+#
+# SkillGain.Crafting
+# SkillGain.Defense
+# SkillGain.Gathering
+# SkillGain.Weapon
+# crafting/defense/gathering/weapon skills gain at skill grow (1,2,...)
+# Default: 1
+#
+# SkillChance.Orange
+# SkillChance.Yellow
+# SkillChance.Green
+# SkillChance.Grey
+# Skill chance values (0..100)
+# Default: 100-75-25-0
+#
+# SkillChance.MiningSteps
+# SkillChance.SkinningSteps
+# For skinning and Mining chance decrease with skill level.
+# Default: 0 - no decrease
+# 75 - in 2 times each 75 skill points
+#
+# DurabilityLossChance.Damage
+# Chance lost one from equiped items durability point at damage apply or receive.
+# Default: 0.5 (100/0.5 = 200) Each 200 damage apply one from 19 possible equipped items
+#
+# DurabilityLossChance.Absorb
+# Chance lost one from armor items durability point at damage absorb.
+# Default: 0.5 (100/0.5 = 200) Each 200 absorbs apply one from 15 possible armor equipped items
+#
+# DurabilityLossChance.Parry
+# Chance lost weapon durability point at parry.
+# Default: 0.05 (100/0.05 = 2000) Each 2000 parry attacks main weapon lost point
+#
+# DurabilityLossChance.Block
+# Chance lost sheild durability point at damage block.
+# Default: 0.05 (100/0.05 = 2000) Each 2000 partly or full blocked attacks shield lost point
+#
+# Death.SicknessLevel
+# Starting Character start gain sickness at spirit resurrection (1 min)
+# Default: 11
+# -10 - character will have full time (10min) sickness at 1 level
+# maxplayerlevel+1 - chaarcter will not have sickess at any level
+#
+# Death.CorpseReclaimDelay.PvP
+# Death.CorpseReclaimDelay.PvE
+# Enabled/disabled increase corpse reclaim delay at often PvP/PvE deaths
+# Default: 1 (enabled)
+# 0 (disabled)
+#
+###################################################################################################################
+
+Rate.Health = 1
+Rate.Mana = 1
+Rate.Rage.Income = 1
+Rate.Rage.Loss = 1
+Rate.Focus = 1
+Rate.Loyalty = 1
+Rate.Skill.Discovery = 1
+Rate.Drop.Item.Poor = 1
+Rate.Drop.Item.Normal = 1
+Rate.Drop.Item.Uncommon = 1
+Rate.Drop.Item.Rare = 1
+Rate.Drop.Item.Epic = 1
+Rate.Drop.Item.Legendary = 1
+Rate.Drop.Item.Artifact = 1
+Rate.Drop.Item.Referenced = 1
+Rate.Drop.Money = 1
+Rate.XP.Kill = 1
+Rate.XP.Quest = 1
+Rate.XP.Explore = 1
+Rate.XP.PastLevel70 = 1
+Rate.Rest.InGame = 1
+Rate.Rest.Offline.InTavernOrCity = 1
+Rate.Rest.Offline.InWilderness = 1
+Rate.Damage.Fall = 1
+Rate.Auction.Time = 1
+Rate.Auction.Deposit = 1
+Rate.Auction.Cut = 1
+Rate.Honor = 1
+Rate.Mining.Amount = 1
+Rate.Mining.Next = 1
+Rate.Talent = 1
+Rate.Reputation.Gain = 1
+Rate.InstanceResetTime = 1
+SkillGain.Crafting = 1
+SkillGain.Defense = 1
+SkillGain.Gathering = 1
+SkillGain.Weapon = 1
+SkillChance.Orange = 100
+SkillChance.Yellow = 75
+SkillChance.Green = 25
+SkillChance.Grey = 0
+SkillChance.MiningSteps = 0
+SkillChance.SkinningSteps = 0
+DurabilityLossChance.Damage = 0.5
+DurabilityLossChance.Absorb = 0.5
+DurabilityLossChance.Parry = 0.05
+DurabilityLossChance.Block = 0.05
+Death.SicknessLevel = 11
+Death.CorpseReclaimDelay.PvP = 1
+Death.CorpseReclaimDelay.PvE = 1
+
+###################################################################################################################
+# CONSOLE AND REMOTE ACCESS
+#
+# Console.Enable
+# Enable console
+# Default: 1 - on
+# 0 - off
+#
+# Ra.Enable
+# Enable remote console
+# Default: 0 - off
+# 1 - on
+#
+# Ra.IP
+# Default remote console ip address, use 0.0.0.0 for every address
+#
+# Ra.Port
+# Default remote console port
+#
+# Ra.MinLevel
+# Minimum level that's required to login,3 by default
+#
+# Ra.Secure
+# Kick client on wrong pass
+#
+###################################################################################################################
+
+Console.Enable = 1
+Ra.Enable = 0
+Ra.IP = 0.0.0.0
+Ra.Port = 3443
+Ra.MinLevel = 3
+Ra.Secure = 1