diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/game-server/being.cpp | 49 | ||||
-rw-r--r-- | src/game-server/being.h | 34 | ||||
-rw-r--r-- | src/game-server/character.h | 6 | ||||
-rw-r--r-- | src/game-server/main-game.cpp | 82 | ||||
-rw-r--r-- | src/game-server/monster.cpp | 23 | ||||
-rw-r--r-- | src/game-server/monster.h | 17 | ||||
-rw-r--r-- | src/game-server/state.cpp | 28 | ||||
-rw-r--r-- | src/game-server/state.h | 4 | ||||
-rw-r--r-- | src/game-server/timeout.cpp | 42 | ||||
-rw-r--r-- | src/game-server/timeout.h | 76 |
11 files changed, 221 insertions, 142 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42708f65..c1a5bd05 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -252,6 +252,8 @@ SET(SRCS_MANASERVGAME game-server/statuseffect.cpp game-server/statusmanager.h game-server/statusmanager.cpp + game-server/timeout.h + game-server/timeout.cpp game-server/trade.h game-server/trade.cpp game-server/trigger.h diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp index bbe07828..8c2b08c7 100644 --- a/src/game-server/being.cpp +++ b/src/game-server/being.cpp @@ -126,8 +126,8 @@ int Being::damage(Actor * /* source */, const Damage &damage) << mAttributes.at(ATTR_MAX_HP).getModifiedAttribute()); setAttribute(ATTR_HP, HP.getBase() - HPloss); // No HP regen after being hit if this is set. - setTimerSoft(T_B_HP_REGEN, - Configuration::getValue("game_hpRegenBreakAfterHit", 0)); + mHealthRegenerationTimeout.setSoft( + Configuration::getValue("game_hpRegenBreakAfterHit", 0)); } else { @@ -638,21 +638,14 @@ void Being::setStatusEffectTime(int id, int time) void Being::update() { - //update timers - for (Timers::iterator i = mTimers.begin(); i != mTimers.end(); i++) - { - if (i->second > -1) - i->second--; - } - int oldHP = getModifiedAttribute(ATTR_HP); int newHP = oldHP; int maxHP = getModifiedAttribute(ATTR_MAX_HP); // Regenerate HP - if (mAction != DEAD && !isTimerRunning(T_B_HP_REGEN)) + if (mAction != DEAD && mHealthRegenerationTimeout.expired()) { - setTimerHard(T_B_HP_REGEN, TICKS_PER_HP_REGENERATION); + mHealthRegenerationTimeout.set(TICKS_PER_HP_REGENERATION); newHP += getModifiedAttribute(ATTR_HP_REGEN); } // Cap HP at maximum @@ -710,40 +703,6 @@ void Being::inserted() mOld = getPosition(); } -void Being::setTimerSoft(TimerID id, int value) -{ - Timers::iterator i = mTimers.find(id); - if (i == mTimers.end()) - { - mTimers[id] = value; - } - else if (i->second < value) - { - i->second = value; - } -} - -void Being::setTimerHard(TimerID id, int value) -{ - mTimers[id] = value; -} - -int Being::getTimer(TimerID id) const -{ - Timers::const_iterator i = mTimers.find(id); - return (i == mTimers.end()) ? -1 : i->second; -} - -bool Being::isTimerRunning(TimerID id) const -{ - return getTimer(id) > 0; -} - -bool Being::isTimerJustFinished(TimerID id) const -{ - return getTimer(id) == 0; -} - void Being::setGender(BeingGender gender) { mGender = gender; diff --git a/src/game-server/being.h b/src/game-server/being.h index 27c14b09..8e7d6199 100644 --- a/src/game-server/being.h +++ b/src/game-server/being.h @@ -30,6 +30,7 @@ #include "game-server/actor.h" #include "game-server/attribute.h" #include "game-server/autoattack.h" +#include "game-server/timeout.h" class Being; class MapComposite; @@ -37,16 +38,6 @@ class StatusEffect; typedef std::map< unsigned int, Attribute > AttributeMap; -enum TimerID -{ - T_M_STROLL, // time until monster strolls to new location - T_M_KILLSTEAL_PROTECTED, // killsteal protection time - T_M_DECAY, // time until dead monster is removed - T_M_ATTACK_TIME, // time until monster can attack again - T_B_HP_REGEN, // time until hp is regenerated again - T_C_MUTE // time until the character can chat again -}; - struct Status { StatusEffect *status; @@ -296,6 +287,7 @@ class Being : public Actor protected: static const int TICKS_PER_HP_REGENERATION = 100; + BeingAction mAction; AttributeMap mAttributes; AutoAttacks mAutoAttacks; @@ -305,24 +297,6 @@ class Being : public Actor Point mDst; /**< Target coordinates. */ BeingGender mGender; /**< Gender of the being. */ - /** Sets timer unless already higher. */ - void setTimerSoft(TimerID id, int value); - - /** - * Sets timer even when already higher (when in doubt this one is - * faster) - */ - void setTimerHard(TimerID id, int value); - - /** Returns number of ticks left on the timer */ - int getTimer(TimerID id) const; - - /** Returns whether timer exists and is > 0 */ - bool isTimerRunning(TimerID id) const; - - /** Returns whether the timer reached 0 in this tick */ - bool isTimerJustFinished(TimerID id) const; - private: Being(const Being &rhs); Being &operator=(const Being &rhs); @@ -340,8 +314,8 @@ class Being : public Actor std::string mName; Hits mHitsTaken; /**< List of punches taken since last update. */ - typedef std::map<TimerID, int> Timers; - Timers mTimers; + /** Time until hp is regenerated again */ + Timeout mHealthRegenerationTimeout; }; #endif // BEING_H diff --git a/src/game-server/character.h b/src/game-server/character.h index ec3fc737..b465a90e 100644 --- a/src/game-server/character.h +++ b/src/game-server/character.h @@ -405,10 +405,10 @@ class Character : public Being /** Makes it impossible to chat for a while */ void mute(int seconds) - { setTimerHard(T_C_MUTE, seconds * 10); } + { mMuteTimeout.set(seconds * 10); } bool isMuted() const - { return isTimerRunning(T_C_MUTE); } + { return !mMuteTimeout.expired(); } bool isConnected() const { return mConnected; } @@ -520,6 +520,8 @@ class Character : public Being int mTalkNpcId; /**< Public ID of NPC the character is talking to, if any */ Script::Thread *mNpcThread; /**< Script thread executing NPC interaction, if any */ + Timeout mMuteTimeout; /**< Time until the character is no longer muted */ + static Script::Ref mDeathCallback; static Script::Ref mDeathAcceptedCallback; diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp index c7566b61..647a74ef 100644 --- a/src/game-server/main-game.cpp +++ b/src/game-server/main-game.cpp @@ -19,23 +19,6 @@ * along with The Mana Server. If not, see <http://www.gnu.org/licenses/>. */ -#include <cstdlib> -#include <getopt.h> -#include <iostream> -#include <signal.h> -#include <physfs.h> -#include <enet/enet.h> -#include <unistd.h> - -#ifdef __MINGW32__ -#include <windows.h> -#define usleep(usec) (Sleep ((usec) / 1000), 0) -#endif - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - #include "common/configuration.h" #include "common/permissionmanager.h" #include "common/resourcemanager.h" @@ -60,6 +43,23 @@ #include "utils/timer.h" #include "utils/mathutils.h" +#include <cstdlib> +#include <getopt.h> +#include <iostream> +#include <signal.h> +#include <physfs.h> +#include <enet/enet.h> +#include <unistd.h> + +#ifdef __MINGW32__ +#include <windows.h> +#define usleep(usec) (Sleep ((usec) / 1000), 0) +#endif + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + using utils::Logger; // Default options that automake should be able to override. @@ -78,9 +78,9 @@ using utils::Logger; static int const WORLD_TICK_SKIP = 2; /** tolerance for lagging behind in world calculation) **/ /** Timer for world ticks */ -utils::Timer worldTimer(WORLD_TICK_MS); -int worldTime = 0; /**< Current world time in ticks */ -bool running = true; /**< Determines if server keeps running */ +static utils::Timer worldTimer(WORLD_TICK_MS); +static int currentTick = 0; /**< Current world time in ticks */ +static bool running = true; /**< Whether the server keeps running */ utils::StringFilter *stringFilter; /**< Slang's Filter */ @@ -373,29 +373,31 @@ int main(int argc, char *argv[]) // Account connection lost flag bool accountServerLost = false; - int elapsedWorldTicks = 0; while (running) { - elapsedWorldTicks = worldTimer.poll(); - if (elapsedWorldTicks == 0) worldTimer.sleep(); + int elapsedTicks = worldTimer.poll(); - while (elapsedWorldTicks > 0) + if (elapsedTicks == 0) { - if (elapsedWorldTicks > WORLD_TICK_SKIP) - { - LOG_WARN("Skipped "<< elapsedWorldTicks - 1 - << " world tick due to insufficient CPU time."); - elapsedWorldTicks = 1; - } - worldTime++; - elapsedWorldTicks--; + worldTimer.sleep(); + continue; + } - // Print world time at 10 second intervals to show we're alive - if (worldTime % 100 == 0) { - LOG_INFO("World time: " << worldTime); + if (elapsedTicks > WORLD_TICK_SKIP) + { + LOG_WARN("Skipping "<< elapsedTicks - 1 << " ticks."); + elapsedTicks = 1; + } - } + while (elapsedTicks > 0) + { + currentTick++; + elapsedTicks--; + + // Print world time at 10 second intervals to show we're alive + if (currentTick % 100 == 0) + LOG_INFO("World time: " << currentTick); if (accountHandler->isConnected()) { @@ -404,12 +406,12 @@ int main(int argc, char *argv[]) // Handle all messages that are in the message queues accountHandler->process(); - if (worldTime % 100 == 0) { + if (currentTick % 100 == 0) { accountHandler->syncChanges(true); // force sending changes to the account server every 10 secs. } - if (worldTime % 300 == 0) + if (currentTick % 300 == 0) { accountHandler->sendStatistics(); LOG_INFO("Total Account Output: " << gBandwidth->totalInterServerOut() << " Bytes"); @@ -429,14 +431,14 @@ int main(int argc, char *argv[]) } // Try to reconnect every 200 ticks - if (worldTime % 200 == 0) + if (currentTick % 200 == 0) { accountHandler->start(options.port); } } gameHandler->process(); // Update all active objects/beings - GameState::update(worldTime); + GameState::update(currentTick); // Send potentially urgent outgoing messages gameHandler->flush(); } diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp index ec9db792..30c38da9 100644 --- a/src/game-server/monster.cpp +++ b/src/game-server/monster.cpp @@ -122,13 +122,13 @@ void Monster::update() { Being::update(); - if (isTimerJustFinished(T_M_KILLSTEAL_PROTECTED)) + if (mKillStealProtectedTimeout.justFinished()) mOwner = NULL; // If dead, remove it if (mAction == DEAD) { - if (!isTimerRunning(T_M_DECAY)) + if (mDecayTimeout.expired()) GameState::enqueueRemove(this); return; @@ -144,7 +144,7 @@ void Monster::update() } // Cancel the rest when we are currently performing an attack - if (isTimerRunning(T_M_ATTACK_TIME)) + if (!mAttackTimeout.expired()) return; refreshTarget(); @@ -152,9 +152,9 @@ void Monster::update() if (!mTarget) { // We have no target - let's wander around - if (!isTimerRunning(T_M_STROLL) && getPosition() == getDestination()) + if (mStrollTimeout.expired() && getPosition() == getDestination()) { - if (!isTimerRunning(T_M_KILLSTEAL_PROTECTED)) + if (mKillStealProtectedTimeout.expired()) { unsigned range = mSpecy->getStrollRange(); if (range) @@ -168,7 +168,7 @@ void Monster::update() if (randomPos.x >= 0 && randomPos.y >= 0) setDestination(randomPos); } - setTimerHard(T_M_STROLL, 10 + rand() % 10); + mStrollTimeout.set(10 + rand() % 10); } } } @@ -293,8 +293,8 @@ void Monster::processAttack() if (!mCurrentAttack) return; - setTimerHard(T_M_ATTACK_TIME, mCurrentAttack->aftDelay - + mCurrentAttack->preDelay); + mAttackTimeout.set(mCurrentAttack->aftDelay + + mCurrentAttack->preDelay); float damageFactor = mCurrentAttack->damageFactor; @@ -421,13 +421,12 @@ int Monster::damage(Actor *source, const Damage &damage) Character *s = static_cast< Character * >(source); mExpReceivers[s].insert(damage.skill); - if (!isTimerRunning(T_M_KILLSTEAL_PROTECTED) || mOwner == s + if (mKillStealProtectedTimeout.expired() || mOwner == s || mOwner->getParty() == s->getParty()) { mOwner = s; mLegalExpReceivers.insert(s); - setTimerHard(T_M_KILLSTEAL_PROTECTED, - KILLSTEAL_PROTECTION_TIME); + mKillStealProtectedTimeout.set(KILLSTEAL_PROTECTION_TIME); } } @@ -451,7 +450,7 @@ void Monster::died() if (mAction == DEAD) return; Being::died(); - setTimerHard(T_M_DECAY, Monster::DECAY_TIME); + mDecayTimeout.set(DECAY_TIME); if (mExpReceivers.size() > 0) { diff --git a/src/game-server/monster.h b/src/game-server/monster.h index afa93e71..75ea1e83 100644 --- a/src/game-server/monster.h +++ b/src/game-server/monster.h @@ -21,16 +21,16 @@ #ifndef MONSTER_H #define MONSTER_H -#include <map> -#include <vector> -#include <string> - #include "game-server/being.h" #include "game-server/eventlistener.h" #include "common/defines.h" #include "scripting/script.h" #include "utils/string.h" +#include <map> +#include <vector> +#include <string> + class ItemClass; class Script; @@ -385,6 +385,15 @@ class Monster : public Being */ std::list<AttackPosition> mAttackPositions; + /** Time until monster strolls to new location */ + Timeout mStrollTimeout; + /** Kill steal protection time */ + Timeout mKillStealProtectedTimeout; + /** Time until dead monster is removed */ + Timeout mDecayTimeout; + /** Time until monster can attack again */ + Timeout mAttackTimeout; + friend struct MonsterTargetEventDispatch; }; diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp index 843bfadb..249040a8 100644 --- a/src/game-server/state.cpp +++ b/src/game-server/state.cpp @@ -18,8 +18,6 @@ * along with The Mana Server. If not, see <http://www.gnu.org/licenses/>. */ -#include <cassert> - #include "game-server/state.h" #include "common/configuration.h" @@ -42,6 +40,8 @@ #include "utils/point.h" #include "utils/speedconv.h" +#include <cassert> + enum { EVENT_REMOVE = 0, @@ -61,6 +61,11 @@ struct DelayedEvent typedef std::map< Actor *, DelayedEvent > DelayedEvents; /** + * The current world time in ticks since server start. + */ +static int currentTick; + +/** * List of delayed events. */ static DelayedEvents delayedEvents; @@ -123,7 +128,7 @@ static void serializeLooks(Character *ch, MessageOut &msg) /** * Informs a player of what happened around the character. */ -static void informPlayer(MapComposite *map, Character *p, int worldTime) +static void informPlayer(MapComposite *map, Character *p) { MessageOut moveMsg(GPMSG_BEINGS_MOVE); MessageOut damageMsg(GPMSG_BEINGS_DAMAGE); @@ -273,7 +278,7 @@ static void informPlayer(MapComposite *map, Character *p, int worldTime) if (opos != oold) { // Add position check coords every 5 seconds. - if (worldTime % 50 == 0) + if (currentTick % 50 == 0) flags |= MOVING_POSITION; flags |= MOVING_DESTINATION; @@ -411,11 +416,13 @@ static void informPlayer(MapComposite *map, Character *p, int worldTime) static bool dbgLockObjects; #endif -void GameState::update(int worldTime) +void GameState::update(int tick) { -# ifndef NDEBUG + currentTick = tick; + +#ifndef NDEBUG dbgLockObjects = true; -# endif +#endif ScriptManager::currentState()->update(); @@ -432,7 +439,7 @@ void GameState::update(int worldTime) for (CharacterIterator p(map->getWholeMapIterator()); p; ++p) { - informPlayer(map, *p, worldTime); + informPlayer(map, *p); } for (ActorIterator it(map->getWholeMapIterator()); it; ++it) @@ -573,6 +580,11 @@ bool GameState::insert(Entity *ptr) return true; } +int GameState::getCurrentTick() +{ + return currentTick; +} + bool GameState::insertOrDelete(Entity *ptr) { if (insert(ptr)) return true; diff --git a/src/game-server/state.h b/src/game-server/state.h index ba87a767..34eb8814 100644 --- a/src/game-server/state.h +++ b/src/game-server/state.h @@ -34,7 +34,9 @@ namespace GameState /** * Updates game state (contains core server logic). */ - void update(int worldTime); + void update(int tick); + + int getCurrentTick(); /** * Inserts an entity in the game world. diff --git a/src/game-server/timeout.cpp b/src/game-server/timeout.cpp new file mode 100644 index 00000000..02edbb5f --- /dev/null +++ b/src/game-server/timeout.cpp @@ -0,0 +1,42 @@ +/* + * The Mana Server + * Copyright (C) 2004-2010 The Mana World Development Team + * Copyright (C) 2010-2012 The Mana Developers + * + * This file is part of The Mana Server. + * + * The Mana Server 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 + * any later version. + * + * The Mana Server 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 The Mana Server. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "timeout.h" + +#include "game-server/state.h" + +void Timeout::set(int ticks) +{ + mReference = GameState::getCurrentTick() + ticks; +} + +void Timeout::setSoft(int ticks) +{ + int time = GameState::getCurrentTick(); + int newReference = time + ticks; + if (mReference < time || mReference < newReference) + mReference = newReference; +} + +int Timeout::remaining() const +{ + return mReference - GameState::getCurrentTick(); +} diff --git a/src/game-server/timeout.h b/src/game-server/timeout.h new file mode 100644 index 00000000..49805c0a --- /dev/null +++ b/src/game-server/timeout.h @@ -0,0 +1,76 @@ +/* + * The Mana Server + * Copyright (C) 2004-2010 The Mana World Development Team + * Copyright (C) 2010-2012 The Mana Developers + * + * This file is part of The Mana Server. + * + * The Mana Server 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 + * any later version. + * + * The Mana Server 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 The Mana Server. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TIMEOUT_H +#define TIMEOUT_H + +/** + * @brief A timeout is used to count down to a point of time in the future. + * + * This class is actually a passive time keeper. It does not physically count, + * but it stores a reference time against which the current time is compared. + * + * The timeout works in terms of server ticks, which take 100 ms. + */ +class Timeout +{ + public: + /** + * @brief Constructs a timeout. + * + * By default, the timeout has expired when the server was started. + */ + Timeout() + : mReference(0) + {} + + /** + * Sets the timeout a given amount of \a ticks in the future. + */ + void set(int ticks); + + /** + * Sets the timeout a given amount of \a ticks in the future, unless + * the timeout is already set to a higher value. + */ + void setSoft(int ticks); + + /** + * Returns the number of ticks remaining to the next timeout. Negative + * when the timeout has already happened. + */ + int remaining() const; + + /** + * Returns whether the timeout has expired. + */ + bool expired() const { return remaining() < 0; } + + /** + * Returns whether the timeout was reached in the current tick. + */ + bool justFinished() const { return remaining() == 0; } + + private: + int mReference; +}; + +#endif // TIMEOUT_H |