summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gameserver.cbp2
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/game-server/being.cpp49
-rw-r--r--src/game-server/being.h34
-rw-r--r--src/game-server/character.h6
-rw-r--r--src/game-server/main-game.cpp82
-rw-r--r--src/game-server/monster.cpp23
-rw-r--r--src/game-server/monster.h17
-rw-r--r--src/game-server/state.cpp28
-rw-r--r--src/game-server/state.h4
-rw-r--r--src/game-server/timeout.cpp42
-rw-r--r--src/game-server/timeout.h76
12 files changed, 223 insertions, 142 deletions
diff --git a/gameserver.cbp b/gameserver.cbp
index f89db174..15688b96 100644
--- a/gameserver.cbp
+++ b/gameserver.cbp
@@ -173,6 +173,8 @@
<Unit filename="src\game-server\statuseffect.h" />
<Unit filename="src\game-server\statusmanager.cpp" />
<Unit filename="src\game-server\statusmanager.h" />
+ <Unit filename="src\game-server\timeout.cpp" />
+ <Unit filename="src\game-server\timeout.h" />
<Unit filename="src\game-server\trade.cpp" />
<Unit filename="src\game-server\trade.h" />
<Unit filename="src\game-server\trigger.cpp" />
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