/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * 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 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef __WORLD_H #define __WORLD_H #define IS_INSTANCE(a) (((a)>1)&&((a)!=530)) #include "../shared/Threading/RWLock.h" class Object; class WorldPacket; class WorldSession; class Unit; class Creature; class GameObject; class DynamicObject; class Player; class EventableObjectHolder; class MapMgr; class Battleground; enum Rates { RATE_HEALTH=0, RATE_POWER1, RATE_POWER2, RATE_POWER3, RATE_DROP0, // separate rates for each quality level RATE_DROP1, RATE_DROP2, RATE_DROP3, RATE_DROP4, RATE_DROP5, RATE_DROP6, RATE_MONEY, RATE_XP, RATE_RESTXP, RATE_QUESTXP, RATE_HONOR, RATE_QUESTREPUTATION, RATE_KILLREPUTATION, RATE_SKILLCHANCE, RATE_SKILLRATE, MAX_RATES }; enum IntRates { INTRATE_SAVE=0, INTRATE_COMPRESSION, INTRATE_PVPTIMER, MAX_INTRATES }; enum EnviromentalDamage { DAMAGE_EXHAUSTED = 0, DAMAGE_DROWNING = 1, DAMAGE_FALL = 2, DAMAGE_LAVA = 3, DAMAGE_SLIME = 4, DAMAGE_FIRE = 5 }; enum CharCreateErrors { SUCCESS, FAILURE, CANCELLED, DISCONNECT_FROM_SERVER, FAILED_TO_CONNECT, CONNECTED, WRONG_CLIENT_VERSION, CONNECTING_TO_SERVER, NEGOTIATING_SECURITY, NEGOTIATING_SECURITY_COMPLETE, NEGOTIATING_SECURITY_FAILED, AUTHENTICATING, AUTHENTICATION_SUCCESSFUL, AUTHENTICATION_FAILED, LOGIN_UNAVAIBLE, SERVER_IS_NOT_VALID, SYSTEM_UNAVAIBLE, SYSTEM_ERROR, BILLING_SYSTEM_ERROR, ACCOUNT_BILLING_EXPIRED, WRONG_CLIENT_VERSION_2, UNKNOWN_ACCOUNT, INCORRECT_PASSWORD, SESSION_EXPIRED, SERVER_SHUTTING_DOWN, ALREADY_LOGGED_IN, INVALID_LOGIN_SERVER, POSITION_IN_QUEUE_0, THIS_ACCOUNT_HAS_BEEN_BANNED, THIS_CHARACTER_STILL_LOGGED_ON, YOUR_WOW_SUBSCRIPTION_IS_EXPIRED, THIS_SESSION_HAS_TIMED_OUT, THIS_ACCOUNT_TEMP_SUSPENDED, ACCOUNT_BLOCKED_BY_PARENTAL_CONTROL, RETRIEVING_REALMLIST, REALMLIST_RETRIEVED, UNABLE_TO_CONNECT_REALMLIST_SERVER, INVALID_REALMLIST, GAME_SERVER_DOWN, CREATING_ACCOUNT, ACCOUNT_CREATED, ACCOUNT_CREATION_FAIL, RETRIEVE_CHAR_LIST, CHARLIST_RETRIEVED, CHARLIST_ERROR, CREATING_CHARACTER, CHARACTER_CREATED, ERROR_CREATING_CHARACTER, CHARACTER_CREATION_FAIL, NAME_IS_IN_USE, CREATION_OF_RACE_DISABLED, ALL_CHARS_ON_PVP_REALM_MUST_AT_SAME_SIDE, ALREADY_HAVE_MAXIMUM_CHARACTERS, ALREADY_HAVE_MAXIMUM_CHARACTERS_2, SERVER_IS_CURRENTLY_QUEUED, ONLY_PLAYERS_WHO_HAVE_CHARACTERS_ON_THIS_REALM, NEED_EXPANSION_ACCOUNT, DELETING_CHARACTER, CHARACTER_DELETED, CHARACTER_DELETION_FAILED, ENTERING_WOW, LOGIN_SUCCESFUL, WORLD_SERVER_DOWN, A_CHARACTER_WITH_THAT_NAME_EXISTS, NO_INSTANCE_SERVER_AVAIBLE, LOGIN_FAILED, LOGIN_FOR_THAT_RACE_DISABLED, LOGIN_FOR_THAT_RACE_CLASS_DISABLED,//check ENTER_NAME_FOR_CHARACTER, NAME_AT_LEAST_TWO_CHARACTER, NAME_AT_MOST_12_CHARACTER, NAME_CAN_CONTAIN_ONLY_CHAR, NAME_CONTAIN_ONLY_ONE_LANG, NAME_CONTAIN_PROFANTY, NAME_IS_RESERVED, YOU_CANNOT_USE_APHOS, YOU_CAN_ONLY_HAVE_ONE_APHOS, YOU_CANNOT_USE_SAME_LETTER_3_TIMES, NO_SPACE_BEFORE_NAME, BLANK, INVALID_CHARACTER_NAME, BLANK_1 //All further codes give the number in dec. }; // ServerMessages.dbc enum ServerMessageType { SERVER_MSG_SHUTDOWN_TIME = 1, SERVER_MSG_RESTART_TIME = 2, SERVER_MSG_STRING = 3, SERVER_MSG_SHUTDOWN_CANCELLED = 4, SERVER_MSG_RESTART_CANCELLED = 5 }; enum WorldMapInfoFlag { WMI_INSTANCE_ENABLED = 0x1, WMI_INSTANCE_WELCOME = 0x2, WMI_INSTANCE_MULTIMODE = 0x4, WMI_INSTANCE_XPACK_01 = 0x8, //The Burning Crusade expansion }; enum AccountFlags { ACCOUNT_FLAG_VIP = 0x1, ACCOUNT_FLAG_XTEND_INFO = 0x4, ACCOUNT_FLAG_XPACK_01 = 0x8, }; struct MapInfo { uint32 mapid; uint32 screenid; uint32 type; uint32 playerlimit; uint32 minlevel; float repopx; float repopy; float repopz; uint32 repopmapid; char * name; uint32 flags; uint32 cooldown; uint32 lvl_mod_a; uint32 required_quest; uint32 required_item; bool HasFlag(uint32 flag) { return (flags & flag) != 0; } }; enum REALM_TYPE { REALM_PVE = 0, REALM_PVP = 1, }; struct AreaTable; class BasicTaskExecutor : public ThreadBase { CallbackBase * cb; uint32 priority; public: BasicTaskExecutor(CallbackBase * Callback, uint32 Priority) : cb(Callback), priority(Priority) {} ~BasicTaskExecutor() { delete cb; } void run(); }; class Task { CallbackBase * _cb; public: Task(CallbackBase * cb) : _cb(cb), completed(false), in_progress(false) {} ~Task() { delete _cb; } bool completed; bool in_progress; void execute(); }; class TaskList { set tasks; Mutex queueLock; public: Task * GetTask(); void AddTask(Task* task); void RemoveTask(Task * task) { queueLock.Acquire(); tasks.erase(task); queueLock.Release(); } void spawn(); void kill(); void wait(); void waitForThreadsToExit(); uint32 thread_count; bool running; Mutex tcMutex; inline void incrementThreadCount() { tcMutex.Acquire(); ++thread_count; tcMutex.Release(); } inline void decrementThreadCount() { tcMutex.Acquire(); --thread_count; tcMutex.Release(); } }; enum BasicTaskExecutorPriorities { BTE_PRIORITY_LOW = 0, BTE_PRIORITY_MED = 1, BTW_PRIORITY_HIGH = 2, }; class TaskExecutor : public ThreadBase { TaskList * starter; public: TaskExecutor(TaskList * l) : starter(l) { l->incrementThreadCount(); } ~TaskExecutor() { starter->decrementThreadCount(); } void run(); }; class WorldSocket; // Slow for remove in middle, oh well, wont get done much. typedef std::vector QueueSet; typedef set SessionSet; class SERVER_DECL World : public Singleton, public EventableObject { public: World(); ~World(); /** Reloads the config and sets all of the setting variables */ void Rehash(bool load); WorldSession* FindSession(uint32 id); WorldSession* FindSessionByName(const char *); void AddSession(WorldSession *s); void RemoveSession(uint32 id); void AddGlobalSession(WorldSession *session); void RemoveGlobalSession(WorldSession *session); void DeleteSession(WorldSession *session); inline uint32 GetSessionCount() const { return m_sessions.size(); } uint32 GetNonGmSessionCount(); inline uint32 GetQueueCount() { return mQueuedSessions.size(); } void GetStats(uint32 * GMCount, float * AverageLatency); inline uint32 GetPlayerLimit() const { return m_playerLimit; } void SetPlayerLimit(uint32 limit) { m_playerLimit = limit; } inline bool getAllowMovement() const { return m_allowMovement; } void SetAllowMovement(bool allow) { m_allowMovement = allow; } inline bool getGMTicketStatus() { return m_gmTicketSystem; }; bool toggleGMTicketStatus() { m_gmTicketSystem = !m_gmTicketSystem; return m_gmTicketSystem; }; inline bool getReqGmClient() { return reqGmClient; } inline std::string getGmClientChannel() { return GmClientChannel; } void SetMotd(const char *motd) { m_motd = motd; } inline const char* GetMotd() const { return m_motd.c_str(); } inline time_t GetGameTime() const { return m_gameTime; } void SetInitialWorldSettings(); void SendWorldText(const char *text, WorldSession *self = 0); void SendWorldWideScreenText(const char *text, WorldSession *self = 0); void SendGlobalMessage(WorldPacket *packet, WorldSession *self = 0); void SendZoneMessage(WorldPacket *packet, uint32 zoneid, WorldSession *self = 0); void SendFactionMessage(WorldPacket *packet, uint8 teamId); inline void SetStartTime(uint32 val) { m_StartTime = val; } inline uint32 GetUptime(void) { return (uint32)time(NULL) - m_StartTime; } inline uint32 GetStartTime(void) { return m_StartTime; } inline std::string GetUptimeString() { int seconds = (uint32)time(NULL) - m_StartTime; int mins=0; int hours=0; int days=0; if(seconds >= 60) { mins = seconds / 60; if(mins) { seconds -= mins*60; if(mins >= 60) { hours = mins / 60; if(hours) { mins -= hours*60; if(hours >= 24) { days = hours/24; if(days) hours -= days*24; } } } } } char str[200]; snprintf(str, 200, "%d days, %d hours, %d minutes, %d seconds.", days, hours, mins, seconds); return str; } // update the world server every frame void Update(time_t diff); void UpdateSessions(uint32 diff); inline void setRate(int index,float value) { regen_values[index]=value; } inline float getRate(int index) { return regen_values[index]; } inline uint32 getIntRate(int index) { return int_rates[index]; } inline void setIntRate(int index, uint32 value) { int_rates[index] = value; } // map text emote to spell prices typedef std::map< uint32, uint32> SpellPricesMap; SpellPricesMap mPrices; inline uint32 GetTimeOut(){return TimeOut;} std::string GenerateName(uint32 type = 0); void SetUpdateDistance(float dist) { m_UpdateDistance = (float)pow(dist, 2); } inline float GetUpdateDistance() { return (m_UpdateDistance ? m_UpdateDistance : 79.1f); } std::map mAreaIDToTable; std::map mZoneIDToTable; uint32 AddQueuedSocket(WorldSocket* Socket); void RemoveQueuedSocket(WorldSocket* Socket); uint32 GetQueuePos(WorldSocket* Socket); void UpdateQueuedSessions(uint32 diff); Mutex queueMutex; uint32 mQueueUpdateInterval; bool m_useIrc; bool sendRevisionOnJoin; void SaveAllPlayers(); uint32 LevelCap; uint32 Expansion1LevelCap; string MapPath; bool UnloadMapFiles; bool BreathingEnabled; bool SpeedhackProtection; void EventDeleteBattleground(Battleground * BG); uint32 mInWorldPlayerCount; uint32 mAcceptedConnections; uint32 SocketSendBufSize; uint32 SocketRecvBufSize; inline void AddExtendedSession(WorldSession * session) { mExtendedSessions.insert(session); } inline void RemoveExtendedSession(WorldSession * session) { mExtendedSessions.erase(session); } void BroadcastExtendedMessage(WorldSession * self, const char* str, ...); uint32 HordePlayers; uint32 AlliancePlayers; uint32 PeakSessionCount; bool SendStatsOnJoin; SessionSet gmList; void ShutdownClasses(); void DeleteObject(Object * obj); uint32 compression_threshold; void SetKickAFKPlayerTime(uint32 idletimer){m_KickAFKPlayers=idletimer;} uint32 GetKickAFKPlayerTime(){return m_KickAFKPlayers;} uint32 GetRealmType() { return realmtype; } uint32 flood_lines; uint32 flood_seconds; bool flood_message; bool gm_skip_attunement; float m_UpdateDistance; bool show_gm_in_who_list; uint32 map_unload_time; bool antihack_teleport; bool antihack_speed; bool antihack_falldmg; bool antihack_flight; bool no_antihack_on_gm; protected: // update Stuff, FIXME: use diff time_t _UpdateGameTime() { // Update Server time time_t thisTime = time(NULL); m_gameTime += thisTime - m_lastTick; m_lastTick = thisTime; return m_gameTime; } void FillSpellReplacementsTable(); private: EventableObjectHolder * eventholder; //! Timers typedef HM_NAMESPACE::hash_map SessionMap; SessionMap m_sessions; RWLock m_sessionlock; typedef HM_NAMESPACE::hash_map AreaTriggerMap; AreaTriggerMap m_AreaTrigger; public: static time_t UNIXTIME; static time_t MSTIME; protected: Mutex SessionsMutex;//FOR GLOBAL ! SessionSet Sessions; float regen_values[MAX_RATES]; uint32 int_rates[MAX_INTRATES]; uint32 m_playerLimit; bool m_allowMovement; bool m_gmTicketSystem; std::string m_motd; bool reqGmClient; std::string GmClientChannel; uint32 realmtype; time_t m_gameTime; time_t m_lastTick; uint32 TimeOut; uint32 m_StartTime; uint32 m_queueUpdateTimer; QueueSet mQueuedSessions; SessionSet mExtendedSessions; uint32 m_KickAFKPlayers;//don't lag the server if you are useless anyway :P public: list dummyspells; }; #define sWorld World::getSingleton() #endif