summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrzemysław Grzywacz <nexather@gmail.com>2013-04-28 16:15:20 +0200
committerErik Schilling <ablu.erikschilling@googlemail.com>2013-04-29 22:43:54 +0200
commit647cebfdf11c2482e5b4bbaad4aa411cdd4bb2cc (patch)
treeed63cbbde80f2d39175cac4544217ec7d6cdf8e6
parenta8defa22243de756842a78fe36a4b76091915987 (diff)
downloadmanaserv-647cebfdf11c2482e5b4bbaad4aa411cdd4bb2cc.tar.gz
manaserv-647cebfdf11c2482e5b4bbaad4aa411cdd4bb2cc.tar.xz
manaserv-647cebfdf11c2482e5b4bbaad4aa411cdd4bb2cc.zip
Single xml solution
Mana-mantis: #506.
-rw-r--r--example/settings.xml10
-rw-r--r--example/skills.xml12
-rw-r--r--example/specials.xml4
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/common/defines.h8
-rw-r--r--src/common/resourcemanager.cpp107
-rw-r--r--src/common/resourcemanager.h4
-rw-r--r--src/game-server/attributemanager.cpp103
-rw-r--r--src/game-server/attributemanager.h11
-rw-r--r--src/game-server/emotemanager.cpp44
-rw-r--r--src/game-server/emotemanager.h10
-rw-r--r--src/game-server/itemmanager.cpp134
-rw-r--r--src/game-server/itemmanager.h18
-rw-r--r--src/game-server/main-game.cpp28
-rw-r--r--src/game-server/monstermanager.cpp453
-rw-r--r--src/game-server/monstermanager.h11
-rw-r--r--src/game-server/settingsmanager.cpp191
-rw-r--r--src/game-server/settingsmanager.h51
-rw-r--r--src/game-server/skillmanager.cpp53
-rw-r--r--src/game-server/skillmanager.h13
-rw-r--r--src/game-server/specialmanager.cpp72
-rw-r--r--src/game-server/specialmanager.h9
-rw-r--r--src/game-server/statusmanager.cpp124
-rw-r--r--src/game-server/statusmanager.h7
24 files changed, 902 insertions, 577 deletions
diff --git a/example/settings.xml b/example/settings.xml
new file mode 100644
index 0000000..5641d71
--- /dev/null
+++ b/example/settings.xml
@@ -0,0 +1,10 @@
+<settings>
+ <include file="attributes.xml" />
+ <include file="skills.xml" />
+ <include file="specials.xml" />
+ <include file="equip.xml" />
+ <include file="items.xml" />
+ <include file="monsters.xml" />
+ <include file="emotes.xml" />
+ <include file="status-effects.xml" />
+</settings> \ No newline at end of file
diff --git a/example/skills.xml b/example/skills.xml
index 340d903..7019759 100644
--- a/example/skills.xml
+++ b/example/skills.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<skills>
- <set name="Weapons">
+ <skill-set name="Weapons">
<skill id="100" name="Unarmed" icon="graphics/skills/unarmed.png" default="true" />
<skill id="101" name="Knife" icon="graphics/skills/knife.png" />
<skill id="102" name="Sword" icon="graphics/skills/sword.png" />
@@ -12,11 +12,11 @@
<skill id="108" name="Mace" icon="graphics/skills/mace.png" />
<skill id="109" name="Axe" icon="graphics/skills/axe.png" />
<skill id="110" name="Thrown" icon="graphics/skills/thrown.png" />
- </set>
- <set name="Magic">
+ </skill-set>
+ <skill-set name="Magic">
<skill id="200" name="Magic Example" />
- </set>
- <set name="Crafts">
+ </skill-set>
+ <skill-set name="Crafts">
<skill id="300" name="Craft Example" />
- </set>
+ </skill-set>
</skills>
diff --git a/example/specials.xml b/example/specials.xml
index 2c1d61a..dfcfab7 100644
--- a/example/specials.xml
+++ b/example/specials.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<specials>
- <set name="Magic">
+ <special-set name="Magic">
<special
id="1"
name="Test Spell 1"
@@ -24,5 +24,5 @@
rechargespeed="10"
target="point"
/>
- </set>
+ </special-set>
</specials>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8fc5f6e..5a92e29 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -253,6 +253,8 @@ SET(SRCS_MANASERVGAME
game-server/postman.h
game-server/quest.h
game-server/quest.cpp
+ game-server/settingsmanager.h
+ game-server/settingsmanager.cpp
game-server/skillmanager.h
game-server/skillmanager.cpp
game-server/spawnareacomponent.h
diff --git a/src/common/defines.h b/src/common/defines.h
index 4ba77a1..40be064 100644
--- a/src/common/defines.h
+++ b/src/common/defines.h
@@ -30,16 +30,10 @@
#define WORLD_TICK_MS 100
// Files
+#define DEFAULT_SETTINGS_FILE "settings.xml"
#define DEFAULT_MAPSDB_FILE "maps.xml"
#define DEFAULT_ITEMSDB_FILE "items.xml"
-#define DEFAULT_EQUIPDB_FILE "equip.xml"
-#define DEFAULT_SKILLSDB_FILE "skills.xml"
-#define DEFAULT_ATTRIBUTEDB_FILE "attributes.xml"
-#define DEFAULT_MONSTERSDB_FILE "monsters.xml"
-#define DEFAULT_STATUSDB_FILE "status-effects.xml"
#define DEFAULT_PERMISSION_FILE "permissions.xml"
-#define DEFAULT_SPECIALSDB_FILE "specials.xml"
-#define DEFAULT_EMOTESDB_FILE "emotes.xml"
/**
* Exit value codes are thrown back at servers exit to reflect their exit state.
diff --git a/src/common/resourcemanager.cpp b/src/common/resourcemanager.cpp
index 92a8591..82675c7 100644
--- a/src/common/resourcemanager.cpp
+++ b/src/common/resourcemanager.cpp
@@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <cstdlib>
#include <cstring>
+#include <vector>
#ifdef _WIN32
#include <io.h>
@@ -133,3 +134,109 @@ ResourceManager::splittedPath ResourceManager::splitFileNameAndPath(
return splittedFilePath;
}
+
+/**
+ * Join two path elements into one.
+ *
+ * This function helps build relative paths.
+ *
+ * Examples:
+ *
+ * /foo + bar = /foo/bar
+ * /foo/ + bar = /foo/bar
+ * /foo + /bar = /bar
+ *
+ * This will work for PhysFS paths. Windows style paths (prefixed with drive letters) won't work.
+ *
+ * @return Joined paths or path2 if path2 was an absolute path.
+ */
+std::string ResourceManager::joinPaths(const std::string& path1, const std::string& path2)
+{
+ if (path2.empty())
+ return path1;
+
+ if (path1.empty())
+ return path2;
+
+ // check if path2 is an absolute path that cannot be joined
+ if (path2[0] == '/' || path2[0] == '\\')
+ return path2;
+
+ char p1end = path1[path1.size()-1];
+ if (p1end == '/' || p1end == '\\')
+ {
+ return path1 + path2;
+ }
+ else
+ {
+ return path1 + "/" + path2;
+ }
+}
+
+/**
+ * Removes relative elements from the path.
+ */
+std::string ResourceManager::cleanPath(const std::string& path)
+{
+ size_t prev, cur;
+ std::string part, result;
+ std::vector<std::string> pathStack;
+
+ prev = 0;
+ while (true)
+ {
+ cur = path.find_first_of("/\\", prev);
+ if (cur == std::string::npos)
+ {
+ // FIXME add everything from prev to the end
+ pathStack.push_back(path.substr(prev));
+ break;
+ }
+
+ part = path.substr(prev, cur - prev);
+ if (part == "..")
+ {
+ // go back one level
+ if (!pathStack.empty())
+ {
+ pathStack.pop_back();
+ }
+ }
+ else if (part == ".")
+ {
+ // do nothing
+ }
+ else if (part == "")
+ {
+ if (pathStack.empty() && cur == 0)
+ {
+ // handle first empty match before the root slash
+ pathStack.push_back(std::string());
+ }
+ else
+ {
+ // empty match in the middle of the path should be ignored
+ }
+ }
+ else
+ {
+ // normal path element
+ pathStack.push_back(part);
+ }
+
+ cur++;
+ prev = cur;
+ }
+
+ // join the pathStack into a normal path
+ unsigned int i = 0;
+ for (i = 0; i < pathStack.size(); i++)
+ {
+ result += pathStack[i];
+ if (i < pathStack.size() - 1) {
+ result += "/";
+ }
+ }
+
+ return result;
+}
diff --git a/src/common/resourcemanager.h b/src/common/resourcemanager.h
index 569428d..eea701a 100644
--- a/src/common/resourcemanager.h
+++ b/src/common/resourcemanager.h
@@ -67,6 +67,10 @@ namespace ResourceManager
* and the file name alone.
*/
splittedPath splitFileNameAndPath(const std::string &fullFilePath);
+
+ std::string joinPaths(const std::string& path1, const std::string& path2);
+
+ std::string cleanPath(const std::string& path);
}
#endif
diff --git a/src/game-server/attributemanager.cpp b/src/game-server/attributemanager.cpp
index 42c2624..f71f4fa 100644
--- a/src/game-server/attributemanager.cpp
+++ b/src/game-server/attributemanager.cpp
@@ -35,43 +35,6 @@ void AttributeManager::reload()
mAttributeMap.clear();
for (unsigned i = 0; i < MaxScope; ++i)
mAttributeScopes[i].clear();
-
- readAttributesFile();
-
- LOG_DEBUG("attribute map:");
- LOG_DEBUG("Stackable is " << Stackable << ", NonStackable is " << NonStackable
- << ", NonStackableBonus is " << NonStackableBonus << ".");
- LOG_DEBUG("Additive is " << Additive << ", Multiplicative is " << Multiplicative << ".");
- const std::string *tag;
- unsigned count = 0;
- for (AttributeMap::const_iterator i = mAttributeMap.begin();
- i != mAttributeMap.end(); ++i)
- {
- unsigned lCount = 0;
- LOG_DEBUG(" "<<i->first<<" : ");
- for (std::vector<AttributeModifier>::const_iterator j =
- i->second.modifiers.begin();
- j != i->second.modifiers.end(); ++j)
- {
- tag = getTag(ModifierLocation(i->first, lCount));
- std::string end = tag ? "tag of '" + (*tag) + "'." : "no tag.";
- LOG_DEBUG(" stackableType: " << j->stackableType
- << ", effectType: " << j->effectType << ", and " << end);
- ++lCount;
- ++count;
- }
- }
- LOG_INFO("Loaded '" << mAttributeMap.size() << "' attributes with '"
- << count << "' modifier layers.");
-
- for (TagMap::const_iterator i = mTagMap.begin(), i_end = mTagMap.end();
- i != i_end; ++i)
- {
- LOG_DEBUG("Tag '" << i->first << "': '" << i->second.attributeId
- << "', '" << i->second.layer << "'.");
- }
-
- LOG_INFO("Loaded '" << mTagMap.size() << "' modifier tags.");
}
const std::vector<AttributeModifier> *AttributeManager::getAttributeInfo(int id) const
@@ -112,27 +75,10 @@ const std::string *AttributeManager::getTag(const ModifierLocation &location) co
return 0;
}
-void AttributeManager::readAttributesFile()
-{
- XML::Document doc(mAttributeReferenceFile);
- xmlNodePtr node = doc.rootNode();
-
- if (!node || !xmlStrEqual(node->name, BAD_CAST "attributes"))
- {
- LOG_FATAL("Attribute Manager: " << mAttributeReferenceFile
- << " is not a valid database file!");
- exit(EXIT_XML_BAD_PARAMETER);
- }
-
- LOG_INFO("Loading attribute reference...");
-
- for_each_xml_child_node(childNode, node)
- {
- if (xmlStrEqual(childNode->name, BAD_CAST "attribute"))
- readAttributeNode(childNode);
- }
-}
-
+/**
+ * Read a <attribute> element from settings.
+ * Used by SettingsManager.
+ */
void AttributeManager::readAttributeNode(xmlNodePtr attributeNode)
{
int id = XML::getProperty(attributeNode, "id", 0);
@@ -196,6 +142,47 @@ void AttributeManager::readAttributeNode(xmlNodePtr attributeNode)
}
}
+/**
+ * Check the status of recently loaded configuration.
+ */
+void AttributeManager::checkStatus()
+{
+ LOG_DEBUG("attribute map:");
+ LOG_DEBUG("Stackable is " << Stackable << ", NonStackable is " << NonStackable
+ << ", NonStackableBonus is " << NonStackableBonus << ".");
+ LOG_DEBUG("Additive is " << Additive << ", Multiplicative is " << Multiplicative << ".");
+ const std::string *tag;
+ unsigned count = 0;
+ for (AttributeMap::const_iterator i = mAttributeMap.begin();
+ i != mAttributeMap.end(); ++i)
+ {
+ unsigned lCount = 0;
+ LOG_DEBUG(" "<<i->first<<" : ");
+ for (std::vector<AttributeModifier>::const_iterator j =
+ i->second.modifiers.begin();
+ j != i->second.modifiers.end(); ++j)
+ {
+ tag = getTag(ModifierLocation(i->first, lCount));
+ std::string end = tag ? "tag of '" + (*tag) + "'." : "no tag.";
+ LOG_DEBUG(" stackableType: " << j->stackableType
+ << ", effectType: " << j->effectType << ", and " << end);
+ ++lCount;
+ ++count;
+ }
+ }
+ LOG_INFO("Loaded '" << mAttributeMap.size() << "' attributes with '"
+ << count << "' modifier layers.");
+
+ for (TagMap::const_iterator i = mTagMap.begin(), i_end = mTagMap.end();
+ i != i_end; ++i)
+ {
+ LOG_DEBUG("Tag '" << i->first << "': '" << i->second.attributeId
+ << "', '" << i->second.layer << "'.");
+ }
+
+ LOG_INFO("Loaded '" << mTagMap.size() << "' modifier tags.");
+}
+
void AttributeManager::readModifierNode(xmlNodePtr modifierNode,
int attributeId)
{
diff --git a/src/game-server/attributemanager.h b/src/game-server/attributemanager.h
index 1a55006..9bc40e1 100644
--- a/src/game-server/attributemanager.h
+++ b/src/game-server/attributemanager.h
@@ -105,8 +105,7 @@ class AttributeManager
std::vector<struct AttributeModifier> modifiers;
};
- AttributeManager(const std::string &file) :
- mAttributeReferenceFile(file)
+ AttributeManager()
{}
/**
@@ -132,9 +131,11 @@ class AttributeManager
const std::string *getTag(const ModifierLocation &location) const;
- private:
- void readAttributesFile();
void readAttributeNode(xmlNodePtr attributeNode);
+
+ void checkStatus();
+
+ private:
void readModifierNode(xmlNodePtr modifierNode, int attributeId);
// Attribute id -> { modifiable, min, max, { stackable type, effect type }[] }
@@ -146,8 +147,6 @@ class AttributeManager
AttributeScope mAttributeScopes[MaxScope];
AttributeMap mAttributeMap;
TagMap mTagMap;
-
- const std::string mAttributeReferenceFile;
};
extern AttributeManager *attributeManager;
diff --git a/src/game-server/emotemanager.cpp b/src/game-server/emotemanager.cpp
index 35f0aa4..c412854 100644
--- a/src/game-server/emotemanager.cpp
+++ b/src/game-server/emotemanager.cpp
@@ -26,37 +26,39 @@
void EmoteManager::initialize()
{
clear();
+}
- XML::Document doc(mEmoteFile);
- xmlNodePtr rootNode = doc.rootNode();
+void EmoteManager::reload()
+{
+ clear();
+}
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "emotes"))
+/**
+ * Read a <emote> element from settings.
+ * Used by SettingsManager.
+ */
+void EmoteManager::readEmoteNode(xmlNodePtr node, const std::string &filename)
+{
+ int id = XML::getProperty(node, "id", -1);
+ if (id < 0)
{
- LOG_ERROR("Emote Manager: " << mEmoteFile
- << " is not a valid emote file!");
+ LOG_WARN("The " << filename << " file is containing an invalid id"
+ "(" << id << ") and will be ignored.");
return;
}
- LOG_INFO("Loading emote reference: " << mEmoteFile);
-
- for_each_xml_child_node(emoteNode, rootNode)
- {
- if (!xmlStrEqual(emoteNode->name, BAD_CAST "emote"))
- continue;
-
- int id = XML::getProperty(emoteNode, "id", -1);
- if (id < 0)
- {
- LOG_WARN("The " << mEmoteFile << " file is containing an invalid id"
- "(" << id << ") and will be ignored.");
- continue;
- }
+ mEmoteIds.push_back(id);
+}
- mEmoteIds.push_back(id);
- }
+/**
+ * Check the status of recently loaded configuration.
+ */
+void EmoteManager::checkStatus()
+{
LOG_INFO(mEmoteIds.size() << " emotes available.");
}
+
bool EmoteManager::isIdAvailable(int id) const
{
std::vector<int>::const_iterator it = mEmoteIds.begin();
diff --git a/src/game-server/emotemanager.h b/src/game-server/emotemanager.h
index 42c7168..9470132 100644
--- a/src/game-server/emotemanager.h
+++ b/src/game-server/emotemanager.h
@@ -31,8 +31,7 @@ class EmoteManager
{
public:
- EmoteManager(const std::string &emoteFile):
- mEmoteFile(emoteFile)
+ EmoteManager()
{ }
~EmoteManager()
@@ -43,11 +42,17 @@ public:
*/
void initialize();
+ void reload();
+
/**
* Tells whether the given id is a valid emote one.
*/
bool isIdAvailable(int id) const;
+ void readEmoteNode(xmlNodePtr node, const std::string &filename);
+
+ void checkStatus();
+
private:
/**
* Clears up the emote list.
@@ -55,7 +60,6 @@ private:
void clear()
{ mEmoteIds.clear(); }
- std::string mEmoteFile;
std::vector<int> mEmoteIds;
};
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index 504ba12..05dd0d0 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -42,8 +42,6 @@ void ItemManager::reload()
void ItemManager::initialize()
{
mVisibleEquipSlotCount = 0;
- readEquipSlotsFile();
- readItemsFile();
}
void ItemManager::deinitialize()
@@ -99,111 +97,75 @@ bool ItemManager::isEquipSlotVisible(unsigned id) const
return i != mEquipSlotsInfo.end() ? i->second->visibleSlot : false;
}
-void ItemManager::readEquipSlotsFile()
+
+/**
+ * Check the status of recently loaded configuration.
+ */
+void ItemManager::checkStatus()
+{
+ LOG_INFO("Loaded " << mItemClasses.size() << " items");
+ LOG_INFO("Loaded " << mEquipSlotsInfo.size() << " slot types");
+}
+
+/**
+ * Read a <slot> element from settings.
+ * Used by SettingsManager.
+ */
+void ItemManager::readEquipSlotNode(xmlNodePtr node)
{
- XML::Document doc(mEquipSlotsFile);
- xmlNodePtr rootNode = doc.rootNode();
+ const int slotId = XML::getProperty(node, "id", 0);
+ const std::string name = XML::getProperty(node, "name",
+ std::string());
+ const int capacity = XML::getProperty(node, "capacity", 0);
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "equip-slots"))
+ if (slotId <= 0 || name.empty() || capacity <= 0)
{
- LOG_ERROR("Item Manager: Error while parsing equip slots database ("
- << mEquipSlotsFile << ")!");
+ LOG_WARN("Item Manager: equip slot " << slotId
+ << ": (" << name << ") has no name or zero count. "
+ "The slot has been ignored.");
return;
}
- LOG_INFO("Loading equip slots: " << mEquipSlotsFile);
-
- unsigned totalCapacity = 0;
- unsigned slotCount = 0;
- mVisibleEquipSlotCount = 0;
-
- for_each_xml_child_node(node, rootNode)
+ if (slotId > 255)
{
- if (xmlStrEqual(node->name, BAD_CAST "slot"))
- {
- const int slotId = XML::getProperty(node, "id", 0);
- const std::string name = XML::getProperty(node, "name",
- std::string());
- const int capacity = XML::getProperty(node, "capacity", 0);
-
- if (slotId <= 0 || name.empty() || capacity <= 0)
- {
- LOG_WARN("Item Manager: equip slot " << slotId
- << ": (" << name << ") has no name or zero count. "
- "The slot has been ignored.");
- continue;
- }
-
- if (slotId > 255)
- {
- LOG_WARN("Item Manager: equip slot " << slotId
- << ": (" << name << ") is superior to 255 "
- "and has been ignored.");
- continue;
- }
-
- bool visible = XML::getBoolProperty(node, "visible", false);
- if (visible)
- ++mVisibleEquipSlotCount;
-
- EquipSlotsInfo::iterator i = mEquipSlotsInfo.find(slotId);
-
- if (i != mEquipSlotsInfo.end())
- {
- LOG_WARN("Item Manager: Ignoring duplicate definition "
- "of equip slot '" << slotId << "'!");
- continue;
- }
-
- LOG_DEBUG("Adding equip slot, id: " << slotId << ", name: " << name
- << ", capacity: " << capacity << ", visible? " << visible);
- EquipSlotInfo *equipSlotInfo =
- new EquipSlotInfo(slotId, name, capacity, visible);
- mEquipSlotsInfo.insert(std::make_pair(slotId, equipSlotInfo));
- mNamedEquipSlotsInfo.insert(name, equipSlotInfo);
-
- totalCapacity += capacity;
- ++slotCount;
- }
+ LOG_WARN("Item Manager: equip slot " << slotId
+ << ": (" << name << ") is superior to 255 "
+ "and has been ignored.");
+ return;
}
- LOG_INFO("Loaded '" << slotCount << "' slot types with '"
- << totalCapacity << "' slots.");
-}
+ bool visible = XML::getBoolProperty(node, "visible", false);
+ if (visible)
+ ++mVisibleEquipSlotCount;
-void ItemManager::readItemsFile()
-{
- XML::Document doc2(mItemsFile);
- xmlNodePtr rootNode = doc2.rootNode();
+ EquipSlotsInfo::iterator i = mEquipSlotsInfo.find(slotId);
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "items"))
+ if (i != mEquipSlotsInfo.end())
{
- LOG_ERROR("Item Manager: Error while parsing item database ("
- << mItemsFile << ")!");
+ LOG_WARN("Item Manager: Ignoring duplicate definition "
+ "of equip slot '" << slotId << "'!");
return;
}
- LOG_INFO("Loading item reference: " << mItemsFile);
-
- for_each_xml_child_node(node, rootNode)
- {
- if (xmlStrEqual(node->name, BAD_CAST "item"))
- {
- readItemNode(node);
- }
- }
-
- LOG_INFO("Loaded " << mItemClasses.size() << " items from "
- << mItemsFile << ".");
+ LOG_DEBUG("Adding equip slot, id: " << slotId << ", name: " << name
+ << ", capacity: " << capacity << ", visible? " << visible);
+ EquipSlotInfo *equipSlotInfo =
+ new EquipSlotInfo(slotId, name, capacity, visible);
+ mEquipSlotsInfo.insert(std::make_pair(slotId, equipSlotInfo));
+ mNamedEquipSlotsInfo.insert(name, equipSlotInfo);
}
-void ItemManager::readItemNode(xmlNodePtr itemNode)
+/**
+ * Read an <item> element from settings.
+ * Used by SettingsManager.
+ */
+void ItemManager::readItemNode(xmlNodePtr itemNode, const std::string &filename)
{
const int id = XML::getProperty(itemNode, "id", 0);
if (id < 1)
{
LOG_WARN("Item Manager: Item ID: " << id << " is invalid in "
- << mItemsFile << ", and will be ignored.");
+ << filename << ", and will be ignored.");
return;
}
@@ -225,7 +187,7 @@ void ItemManager::readItemNode(xmlNodePtr itemNode)
if (!maxPerSlot)
{
LOG_WARN("Item Manager: Missing max-per-slot property for "
- "item " << id << " in " << mItemsFile << '.');
+ "item " << id << " in " << filename << '.');
maxPerSlot = 1;
}
diff --git a/src/game-server/itemmanager.h b/src/game-server/itemmanager.h
index 6a1f459..ac3c0b8 100644
--- a/src/game-server/itemmanager.h
+++ b/src/game-server/itemmanager.h
@@ -51,9 +51,7 @@ struct EquipSlotInfo
class ItemManager
{
public:
- ItemManager(const std::string &itemFile, const std::string &equipFile) :
- mItemsFile(itemFile),
- mEquipSlotsFile(equipFile),
+ ItemManager() :
mVisibleEquipSlotCount(0),
mItemDatabaseVersion(0)
{}
@@ -103,13 +101,13 @@ class ItemManager
bool isEquipSlotVisible(unsigned id) const;
- private:
- /** Loads the equip slots that a character has available to them. */
- void readEquipSlotsFile();
+ void readItemNode(xmlNodePtr itemNode, const std::string &filename);
+
+ void readEquipSlotNode(xmlNodePtr node);
- /** Loads the main item database. */
- void readItemsFile();
- void readItemNode(xmlNodePtr itemNode);
+ void checkStatus();
+
+ private:
void readEquipNode(xmlNodePtr equipNode, ItemClass *item);
void readEffectNode(xmlNodePtr effectNode, ItemClass *item);
@@ -127,8 +125,6 @@ class ItemManager
// We only keep a pointer to it: The id map will take care of deletion.
utils::NameMap<EquipSlotInfo* > mNamedEquipSlotsInfo;
- std::string mItemsFile;
- std::string mEquipSlotsFile;
unsigned mVisibleEquipSlotCount; // Cache
/** Version of the loaded items database file.*/
diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp
index 8866a39..e21b1dd 100644
--- a/src/game-server/main-game.cpp
+++ b/src/game-server/main-game.cpp
@@ -35,6 +35,7 @@
#include "game-server/statusmanager.h"
#include "game-server/postman.h"
#include "game-server/state.h"
+#include "game-server/settingsmanager.h"
#include "net/bandwidth.h"
#include "net/connectionhandler.h"
#include "net/messageout.h"
@@ -77,12 +78,14 @@ static bool running = true; /**< Whether the server keeps running */
utils::StringFilter *stringFilter; /**< Slang's Filter */
-AttributeManager *attributeManager = new AttributeManager(DEFAULT_ATTRIBUTEDB_FILE);
-ItemManager *itemManager = new ItemManager(DEFAULT_ITEMSDB_FILE, DEFAULT_EQUIPDB_FILE);
-MonsterManager *monsterManager = new MonsterManager(DEFAULT_MONSTERSDB_FILE);
-SkillManager *skillManager = new SkillManager(DEFAULT_SKILLSDB_FILE);
-SpecialManager *specialManager = new SpecialManager(DEFAULT_SPECIALSDB_FILE);
-EmoteManager *emoteManager = new EmoteManager(DEFAULT_EMOTESDB_FILE);
+AttributeManager *attributeManager = new AttributeManager();
+ItemManager *itemManager = new ItemManager();
+MonsterManager *monsterManager = new MonsterManager();
+SkillManager *skillManager = new SkillManager();
+SpecialManager *specialManager = new SpecialManager();
+EmoteManager *emoteManager = new EmoteManager();
+
+SettingsManager *settingsManager = new SettingsManager(DEFAULT_SETTINGS_FILE);
/** Core game message handler */
GameHandler *gameHandler;
@@ -130,15 +133,13 @@ static void initializeServer()
LOG_FATAL("The Game Server can't find any valid/available maps.");
exit(EXIT_MAP_FILE_NOT_FOUND);
}
- attributeManager->initialize();
- skillManager->initialize();
- specialManager->initialize();
- itemManager->initialize();
- monsterManager->initialize();
- emoteManager->initialize();
- StatusManager::initialize(DEFAULT_STATUSDB_FILE);
+
+ // load game settings files
+ settingsManager->initialize();
+
PermissionManager::initialize(DEFAULT_PERMISSION_FILE);
+
std::string mainScript = Configuration::getValue("script_mainFile",
DEFAULT_MAIN_SCRIPT_FILE);
ScriptManager::loadMainScript(mainScript);
@@ -192,6 +193,7 @@ static void deinitializeServer()
delete skillManager; skillManager = 0;
delete itemManager; itemManager = 0;
delete emoteManager; emoteManager = 0;
+ delete settingsManager; settingsManager = 0;
MapManager::deinitialize();
StatusManager::deinitialize();
ScriptManager::deinitialize();
diff --git a/src/game-server/monstermanager.cpp b/src/game-server/monstermanager.cpp
index bb29bab..3a9d791 100644
--- a/src/game-server/monstermanager.cpp
+++ b/src/game-server/monstermanager.cpp
@@ -26,7 +26,6 @@
#include "game-server/itemmanager.h"
#include "game-server/monster.h"
#include "utils/logger.h"
-#include "utils/xml.h"
#define MAX_MUTATION 99
#define DEFAULT_MONSTER_SIZE 16
@@ -40,278 +39,276 @@ void MonsterManager::reload()
void MonsterManager::initialize()
{
- XML::Document doc(mMonsterReferenceFile);
- xmlNodePtr rootNode = doc.rootNode();
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "monsters"))
+}
+
+void MonsterManager::deinitialize()
+{
+ for (MonsterClasses::iterator i = mMonsterClasses.begin(),
+ i_end = mMonsterClasses.end(); i != i_end; ++i)
+ {
+ delete i->second;
+ }
+ mMonsterClasses.clear();
+ mMonsterClassesByName.clear();
+}
+
+MonsterClass *MonsterManager::getMonsterByName(const std::string &name) const
+{
+ return mMonsterClassesByName.value(name);
+}
+
+MonsterClass *MonsterManager::getMonster(int id) const
+{
+ MonsterClasses::const_iterator i = mMonsterClasses.find(id);
+ return i != mMonsterClasses.end() ? i->second : 0;
+}
+
+/**
+ * Read a <monster> element from settings.
+ * Used by SettingsManager.
+ */
+void MonsterManager::readMonsterNode(xmlNodePtr node, const std::string &filename)
+{
+ if (!xmlStrEqual(node->name, BAD_CAST "monster"))
+ return;
+
+ int id = XML::getProperty(node, "id", 0);
+ std::string name = XML::getProperty(node, "name", std::string());
+
+ if (id < 1)
{
- LOG_ERROR("Monster Manager: Error while parsing monster database ("
- << mMonsterReferenceFile << ")!");
+ LOG_WARN("Monster Manager: Ignoring monster ("
+ << name << ") without Id in "
+ << filename << "! It has been ignored.");
return;
}
- LOG_INFO("Loading monster reference: " << mMonsterReferenceFile);
- int nbMonsters = 0;
- for_each_xml_child_node(node, rootNode)
+ MonsterClasses::iterator i = mMonsterClasses.find(id);
+ if (i != mMonsterClasses.end())
{
- if (!xmlStrEqual(node->name, BAD_CAST "monster"))
- continue;
+ LOG_WARN("Monster Manager: Ignoring duplicate definition of "
+ "monster '" << id << "'!");
+ return;
+ }
- int id = XML::getProperty(node, "id", 0);
- std::string name = XML::getProperty(node, "name", std::string());
+ MonsterClass *monster = new MonsterClass(id);
+ mMonsterClasses[id] = monster;
- if (id < 1)
- {
- LOG_WARN("Monster Manager: Ignoring monster ("
- << name << ") without Id in "
- << mMonsterReferenceFile << "! It has been ignored.");
- continue;
- }
+ if (!name.empty())
+ {
+ monster->setName(name);
- MonsterClasses::iterator i = mMonsterClasses.find(id);
- if (i != mMonsterClasses.end())
- {
- LOG_WARN("Monster Manager: Ignoring duplicate definition of "
- "monster '" << id << "'!");
- continue;
- }
+ if (mMonsterClassesByName.contains(name))
+ LOG_WARN("Monster Manager: Name not unique for monster " << id);
+ else
+ mMonsterClassesByName.insert(name, monster);
+ }
- MonsterClass *monster = new MonsterClass(id);
- mMonsterClasses[id] = monster;
+ MonsterDrops drops;
+ bool attributesSet = false;
+ bool behaviorSet = false;
- if (!name.empty())
+ for_each_xml_child_node(subnode, node)
+ {
+ if (xmlStrEqual(subnode->name, BAD_CAST "drop"))
{
- monster->setName(name);
-
- if (mMonsterClassesByName.contains(name))
- LOG_WARN("Monster Manager: Name not unique for monster " << id);
+ MonsterDrop drop;
+ std::string item = XML::getProperty(subnode, "item",
+ std::string());
+ ItemClass *itemClass;
+ if (utils::isNumeric(item))
+ itemClass = itemManager->getItem(utils::stringToInt(item));
else
- mMonsterClassesByName.insert(name, monster);
- }
+ itemClass = itemManager->getItemByName(item);
- MonsterDrops drops;
- bool attributesSet = false;
- bool behaviorSet = false;
-
- for_each_xml_child_node(subnode, node)
- {
- if (xmlStrEqual(subnode->name, BAD_CAST "drop"))
+ if (!itemClass)
{
- MonsterDrop drop;
- std::string item = XML::getProperty(subnode, "item",
- std::string());
- ItemClass *itemClass;
- if (utils::isNumeric(item))
- itemClass = itemManager->getItem(utils::stringToInt(item));
- else
- itemClass = itemManager->getItemByName(item);
-
- if (!itemClass)
- {
- LOG_WARN("Monster Manager: Invalid item name \"" << item
- << "\"");
- break;
- }
+ LOG_WARN("Monster Manager: Invalid item name \"" << item
+ << "\"");
+ break;
+ }
- drop.item = itemClass;
- drop.probability = XML::getFloatProperty(subnode, "percent",
- 0.0) * 100 + 0.5;
+ drop.item = itemClass;
+ drop.probability = XML::getFloatProperty(subnode, "percent",
+ 0.0) * 100 + 0.5;
- if (drop.probability)
- drops.push_back(drop);
- }
- else if (xmlStrEqual(subnode->name, BAD_CAST "attributes"))
+ if (drop.probability)
+ drops.push_back(drop);
+ }
+ else if (xmlStrEqual(subnode->name, BAD_CAST "attributes"))
+ {
+ attributesSet = true;
+
+ const int hp = XML::getProperty(subnode, "hp", -1);
+ monster->setAttribute(ATTR_MAX_HP, hp);
+ monster->setAttribute(ATTR_HP, hp);
+
+ monster->setAttribute(ATTR_DODGE,
+ XML::getProperty(subnode, "evade", -1));
+ monster->setAttribute(ATTR_MAGIC_DODGE,
+ XML::getProperty(subnode, "magic-evade", -1));
+ monster->setAttribute(ATTR_ACCURACY,
+ XML::getProperty(subnode, "hit", -1));
+ monster->setAttribute(ATTR_DEFENSE,
+ XML::getProperty(subnode, "physical-defence", -1));
+ monster->setAttribute(ATTR_MAGIC_DEFENSE,
+ XML::getProperty(subnode, "magical-defence", -1));
+ monster->setSize(XML::getProperty(subnode, "size", -1));
+ float speed = (XML::getFloatProperty(subnode, "speed", -1.0f));
+ monster->setMutation(XML::getProperty(subnode, "mutation", 0));
+ std::string genderString = XML::getProperty(subnode, "gender",
+ std::string());
+ monster->setGender(getGender(genderString));
+
+ // Checking attributes for completeness and plausibility
+ if (monster->getMutation() > MAX_MUTATION)
{
- attributesSet = true;
-
- const int hp = XML::getProperty(subnode, "hp", -1);
- monster->setAttribute(ATTR_MAX_HP, hp);
- monster->setAttribute(ATTR_HP, hp);
-
- monster->setAttribute(ATTR_DODGE,
- XML::getProperty(subnode, "evade", -1));
- monster->setAttribute(ATTR_MAGIC_DODGE,
- XML::getProperty(subnode, "magic-evade", -1));
- monster->setAttribute(ATTR_ACCURACY,
- XML::getProperty(subnode, "hit", -1));
- monster->setAttribute(ATTR_DEFENSE,
- XML::getProperty(subnode, "physical-defence", -1));
- monster->setAttribute(ATTR_MAGIC_DEFENSE,
- XML::getProperty(subnode, "magical-defence", -1));
- monster->setSize(XML::getProperty(subnode, "size", -1));
- float speed = (XML::getFloatProperty(subnode, "speed", -1.0f));
- monster->setMutation(XML::getProperty(subnode, "mutation", 0));
- std::string genderString = XML::getProperty(subnode, "gender",
- std::string());
- monster->setGender(getGender(genderString));
-
- // Checking attributes for completeness and plausibility
- if (monster->getMutation() > MAX_MUTATION)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": Mutation of monster Id:" << id << " more than "
- << MAX_MUTATION << "%. Defaulted to 0.");
- monster->setMutation(0);
- }
-
- bool attributesComplete = true;
- const AttributeManager::AttributeScope &mobAttr =
- attributeManager->getAttributeScope(MonsterScope);
+ LOG_WARN(filename
+ << ": Mutation of monster Id:" << id << " more than "
+ << MAX_MUTATION << "%. Defaulted to 0.");
+ monster->setMutation(0);
+ }
- for (AttributeManager::AttributeScope::const_iterator it =
- mobAttr.begin(), it_end = mobAttr.end(); it != it_end; ++it)
- {
- if (!monster->mAttributes.count(it->first))
- {
- LOG_WARN(mMonsterReferenceFile << ": No attribute "
- << it->first << " for monster Id: "
- << id << ". Defaulted to 0.");
- attributesComplete = false;
- monster->setAttribute(it->first, 0);
- }
- }
+ bool attributesComplete = true;
+ const AttributeManager::AttributeScope &mobAttr =
+ attributeManager->getAttributeScope(MonsterScope);
- if (monster->getSize() == -1)
+ for (AttributeManager::AttributeScope::const_iterator it =
+ mobAttr.begin(), it_end = mobAttr.end(); it != it_end; ++it)
+ {
+ if (!monster->mAttributes.count(it->first))
{
- LOG_WARN(mMonsterReferenceFile
- << ": No size set for monster Id:" << id << ". "
- << "Defaulted to " << DEFAULT_MONSTER_SIZE
- << " pixels.");
- monster->setSize(DEFAULT_MONSTER_SIZE);
+ LOG_WARN(filename << ": No attribute "
+ << it->first << " for monster Id: "
+ << id << ". Defaulted to 0.");
attributesComplete = false;
+ monster->setAttribute(it->first, 0);
}
+ }
- if (speed == -1.0f)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": No speed set for monster Id:" << id << ". "
- << "Defaulted to " << DEFAULT_MONSTER_SPEED
- << " tiles/second.");
- speed = DEFAULT_MONSTER_SPEED;
- attributesComplete = false;
- }
- monster->setAttribute(ATTR_MOVE_SPEED_TPS, speed);
+ if (monster->getSize() == -1)
+ {
+ LOG_WARN(filename
+ << ": No size set for monster Id:" << id << ". "
+ << "Defaulted to " << DEFAULT_MONSTER_SIZE
+ << " pixels.");
+ monster->setSize(DEFAULT_MONSTER_SIZE);
+ attributesComplete = false;
+ }
- if (!attributesComplete)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": Attributes incomplete for monster Id:" << id
- << ". Defaults values may have been applied!");
- }
+ if (speed == -1.0f)
+ {
+ LOG_WARN(filename
+ << ": No speed set for monster Id:" << id << ". "
+ << "Defaulted to " << DEFAULT_MONSTER_SPEED
+ << " tiles/second.");
+ speed = DEFAULT_MONSTER_SPEED;
+ attributesComplete = false;
+ }
+ monster->setAttribute(ATTR_MOVE_SPEED_TPS, speed);
+ if (!attributesComplete)
+ {
+ LOG_WARN(filename
+ << ": Attributes incomplete for monster Id:" << id
+ << ". Defaults values may have been applied!");
}
- else if (xmlStrEqual(subnode->name, BAD_CAST "exp"))
+
+ }
+ else if (xmlStrEqual(subnode->name, BAD_CAST "exp"))
+ {
+ xmlChar *exp = subnode->xmlChildrenNode->content;
+ monster->setExp(atoi((const char*)exp));
+ monster->setOptimalLevel(XML::getProperty(subnode, "level", 0));
+ }
+ else if (xmlStrEqual(subnode->name, BAD_CAST "behavior"))
+ {
+ behaviorSet = true;
+ if (XML::getBoolProperty(subnode, "aggressive", false))
+ monster->setAggressive(true);
+
+ monster->setTrackRange(
+ XML::getProperty(subnode, "track-range", 1));
+ monster->setStrollRange(
+ XML::getProperty(subnode, "stroll-range", 0));
+ monster->setAttackDistance(
+ XML::getProperty(subnode, "attack-distance", 0));
+ }
+ else if (xmlStrEqual(subnode->name, BAD_CAST "attack"))
+ {
+ AttackInfo *att = AttackInfo::readAttackNode(subnode);
+ bool validMonsterAttack = true;
+
+ if (att->getDamage().id < 1)
{
- xmlChar *exp = subnode->xmlChildrenNode->content;
- monster->setExp(atoi((const char*)exp));
- monster->setOptimalLevel(XML::getProperty(subnode, "level", 0));
+ LOG_WARN(filename
+ << ": Attack without ID for monster Id:"
+ << id << " (" << name << ") - attack ignored");
+ validMonsterAttack = false;
}
- else if (xmlStrEqual(subnode->name, BAD_CAST "behavior"))
+ else if (att->getDamage().element == ELEMENT_ILLEGAL)
{
- behaviorSet = true;
- if (XML::getBoolProperty(subnode, "aggressive", false))
- monster->setAggressive(true);
-
- monster->setTrackRange(
- XML::getProperty(subnode, "track-range", 1));
- monster->setStrollRange(
- XML::getProperty(subnode, "stroll-range", 0));
- monster->setAttackDistance(
- XML::getProperty(subnode, "attack-distance", 0));
+ LOG_WARN(filename
+ << ": Attack with unknown element for monster Id:"
+ << id << " (" << name << ") - attack ignored");
+ validMonsterAttack = false;
}
- else if (xmlStrEqual(subnode->name, BAD_CAST "attack"))
+ else if (att->getDamage().type == DAMAGE_OTHER)
{
- AttackInfo *att = AttackInfo::readAttackNode(subnode);
- bool validMonsterAttack = true;
-
- if (att->getDamage().id < 1)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": Attack without ID for monster Id:"
- << id << " (" << name << ") - attack ignored");
- validMonsterAttack = false;
- }
- else if (att->getDamage().element == ELEMENT_ILLEGAL)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": Attack with unknown element for monster Id:"
- << id << " (" << name << ") - attack ignored");
- validMonsterAttack = false;
- }
- else if (att->getDamage().type == DAMAGE_OTHER)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": Attack with unknown damage type "
- << "for monster Id:" << id
- << " (" << name << ")");
- validMonsterAttack = false;
- }
-
- if (validMonsterAttack)
- {
- monster->addAttack(att);
- }
- else
- {
- delete att;
- att = 0;
- }
+ LOG_WARN(filename
+ << ": Attack with unknown damage type "
+ << "for monster Id:" << id
+ << " (" << name << ")");
+ validMonsterAttack = false;
+ }
+ if (validMonsterAttack)
+ {
+ monster->addAttack(att);
}
- else if (xmlStrEqual(subnode->name, BAD_CAST "vulnerability"))
+ else
{
- Element element = elementFromString(
- XML::getProperty(subnode, "element", std::string()));
- double factor = XML::getFloatProperty(subnode, "factor", 1.0);
- monster->setVulnerability(element, factor);
+ delete att;
+ att = 0;
}
- }
- monster->setDrops(drops);
- if (!attributesSet)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": No attributes defined for monster Id:" << id
- << " (" << name << ")");
- }
- if (!behaviorSet)
- {
- LOG_WARN(mMonsterReferenceFile
- << ": No behavior defined for monster Id:" << id
- << " (" << name << ")");
}
- if (monster->getExp() == -1)
+ else if (xmlStrEqual(subnode->name, BAD_CAST "vulnerability"))
{
- LOG_WARN(mMonsterReferenceFile
- << ": No experience defined for monster Id:" << id
- << " (" << name << ")");
- monster->setExp(0);
+ Element element = elementFromString(
+ XML::getProperty(subnode, "element", std::string()));
+ double factor = XML::getFloatProperty(subnode, "factor", 1.0);
+ monster->setVulnerability(element, factor);
}
- ++nbMonsters;
}
- LOG_INFO("Loaded " << nbMonsters << " monsters from "
- << mMonsterReferenceFile << '.');
-}
-
-void MonsterManager::deinitialize()
-{
- for (MonsterClasses::iterator i = mMonsterClasses.begin(),
- i_end = mMonsterClasses.end(); i != i_end; ++i)
+ monster->setDrops(drops);
+ if (!attributesSet)
{
- delete i->second;
+ LOG_WARN(filename
+ << ": No attributes defined for monster Id:" << id
+ << " (" << name << ")");
+ }
+ if (!behaviorSet)
+ {
+ LOG_WARN(filename
+ << ": No behavior defined for monster Id:" << id
+ << " (" << name << ")");
+ }
+ if (monster->getExp() == -1)
+ {
+ LOG_WARN(filename
+ << ": No experience defined for monster Id:" << id
+ << " (" << name << ")");
+ monster->setExp(0);
}
- mMonsterClasses.clear();
- mMonsterClassesByName.clear();
-}
-
-MonsterClass *MonsterManager::getMonsterByName(const std::string &name) const
-{
- return mMonsterClassesByName.value(name);
}
-MonsterClass *MonsterManager::getMonster(int id) const
+/**
+ * Check the status of recently loaded configuration.
+ */
+void MonsterManager::checkStatus()
{
- MonsterClasses::const_iterator i = mMonsterClasses.find(id);
- return i != mMonsterClasses.end() ? i->second : 0;
+ LOG_INFO("Loaded " << mMonsterClasses.size() << " monsters");
}
diff --git a/src/game-server/monstermanager.h b/src/game-server/monstermanager.h
index 07ebb58..49a6e83 100644
--- a/src/game-server/monstermanager.h
+++ b/src/game-server/monstermanager.h
@@ -24,14 +24,15 @@
#include <string>
#include <map>
#include "utils/string.h"
+#include "utils/xml.h"
+
class MonsterClass;
class MonsterManager
{
public:
- MonsterManager(const std::string &file):
- mMonsterReferenceFile(file)
+ MonsterManager()
{}
~MonsterManager()
@@ -65,13 +66,15 @@ class MonsterManager
*/
MonsterClass *getMonsterByName(const std::string &name) const;
+ void readMonsterNode(xmlNodePtr node, const std::string &filename);
+
+ void checkStatus();
+
private:
typedef std::map< int, MonsterClass * > MonsterClasses;
MonsterClasses mMonsterClasses; /**< Monster reference */
utils::NameMap<MonsterClass*> mMonsterClassesByName;
-
- std::string mMonsterReferenceFile;
};
extern MonsterManager *monsterManager;
diff --git a/src/game-server/settingsmanager.cpp b/src/game-server/settingsmanager.cpp
new file mode 100644
index 0000000..79aade1
--- /dev/null
+++ b/src/game-server/settingsmanager.cpp
@@ -0,0 +1,191 @@
+/*
+ * The Mana Server
+ * Copyright (C) 2013 The Mana World Development Team
+ *
+ * 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 "game-server/settingsmanager.h"
+#include "common/defines.h"
+#include "utils/logger.h"
+#include "utils/xml.h"
+
+#include "common/resourcemanager.h"
+
+#include "game-server/attributemanager.h"
+#include "game-server/skillmanager.h"
+#include "game-server/specialmanager.h"
+#include "game-server/itemmanager.h"
+#include "game-server/monstermanager.h"
+#include "game-server/emotemanager.h"
+#include "game-server/statusmanager.h"
+
+/**
+ * Initialize all managers and load configuration into them.
+ *
+ * Fatal errors will call exit()
+ */
+void SettingsManager::initialize()
+{
+ // initialize all managers in correct order
+ attributeManager->initialize();
+ skillManager->initialize();
+ specialManager->initialize();
+ itemManager->initialize();
+ monsterManager->initialize();
+ emoteManager->initialize();
+ StatusManager::initialize();
+
+ loadFile(mSettingsFile);
+ checkStatus();
+}
+
+/**
+ * Reload managers with new configuration.
+ *
+ * @note This code is untested, some of the managers didn't even have empty implementations
+ * of reload().
+ */
+void SettingsManager::reload()
+{
+ attributeManager->reload();
+ skillManager->reload();
+ specialManager->reload();
+ itemManager->reload();
+ monsterManager->reload();
+ emoteManager->reload();
+ StatusManager::reload();
+
+ loadFile(mSettingsFile);
+ checkStatus();
+}
+
+/**
+ * Load a configuration file.
+ */
+void SettingsManager::loadFile(const std::string &filename)
+{
+ LOG_INFO("Loading game settings from " << filename);
+
+ XML::Document doc(filename);
+ xmlNodePtr node = doc.rootNode();
+
+ // add file to include set
+ mIncludedFiles.insert(filename);
+
+ // FIXME: check root node's name when bjorn decides it's time
+ if (!node /*|| !xmlStrEqual(node->name, BAD_CAST "settings") */)
+ {
+ LOG_FATAL("Settings Manager: " << filename << " is not a valid database file!");
+ exit(EXIT_XML_BAD_PARAMETER);
+ }
+
+
+ // go through every node
+ for_each_xml_child_node(childNode, node)
+ {
+ if (childNode->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrEqual(childNode->name, BAD_CAST "include"))
+ {
+ // include an other file
+ const std::string includeFile = XML::getProperty(childNode, "file", std::string());
+
+ // check if file property was given
+ if (!includeFile.empty())
+ {
+ // build absolute path path
+ const ResourceManager::splittedPath splittedPath = ResourceManager::splitFileNameAndPath(filename);
+ const std::string realIncludeFile = ResourceManager::cleanPath(
+ ResourceManager::joinPaths(splittedPath.path, includeFile));
+
+ // check if we're not entering a loop
+ if (mIncludedFiles.find(realIncludeFile) != mIncludedFiles.end())
+ {
+ LOG_ERROR("Circular include loop detecting while including " << includeFile << " from " << filename);
+ }
+ else
+ {
+ // include that file
+ loadFile(realIncludeFile);
+ }
+ }
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "attribute"))
+ {
+ // attribute config
+ attributeManager->readAttributeNode(childNode);
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "skill-set"))
+ {
+ // skills config
+ skillManager->readSkillSetNode(childNode, filename);
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "special-set"))
+ {
+ // special config
+ specialManager->readSpecialSetNode(childNode, filename);
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "slot"))
+ {
+ // equipement slot config
+ itemManager->readEquipSlotNode(childNode);
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "item"))
+ {
+ // item config
+ itemManager->readItemNode(childNode, filename);
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "monster"))
+ {
+ // monster config
+ monsterManager->readMonsterNode(childNode, filename);
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "emote"))
+ {
+ // emote config
+ emoteManager->readEmoteNode(childNode, filename);
+ }
+ else if (xmlStrEqual(childNode->name, BAD_CAST "status-effect"))
+ {
+ // status effects config
+ StatusManager::readStatusNode(childNode, filename);
+ }
+ else
+ {
+ // since the client and server share settings, don't be too strict
+// LOG_WARN("Unexpected tag <" << childNode->name << "> in " << filename);
+ }
+ }
+
+ // remove this file from include stack
+ mIncludedFiles.erase(filename);
+}
+
+/**
+ * Finalize the configuration loading and check if all managers are happy with it.
+ */
+void SettingsManager::checkStatus()
+{
+ attributeManager->checkStatus();
+ skillManager->checkStatus();
+ specialManager->checkStatus();
+ itemManager->checkStatus();
+ monsterManager->checkStatus();
+ emoteManager->checkStatus();
+ StatusManager::checkStatus();
+}
diff --git a/src/game-server/settingsmanager.h b/src/game-server/settingsmanager.h
new file mode 100644
index 0000000..aa6d272
--- /dev/null
+++ b/src/game-server/settingsmanager.h
@@ -0,0 +1,51 @@
+/*
+ * The Mana Server
+ * Copyright (C) 2013 The Mana World Development Team
+ *
+ * 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 GAMESERVER_SETTINGSMANAGER_H_
+#define GAMESERVER_SETTINGSMANAGER_H_
+
+#include <string>
+#include <list>
+#include <set>
+
+class SettingsManager
+{
+ public:
+ SettingsManager(const std::string &settingsFile):
+ mSettingsFile(settingsFile)
+ {}
+
+ void initialize();
+
+ void reload();
+
+ private:
+ std::string mSettingsFile;
+ std::set<std::string> mIncludedFiles;
+
+ void loadFile(const std::string &filename);
+
+ void checkStatus();
+};
+
+
+extern SettingsManager *settingsManager;
+
+#endif // GAMESERVER_SETTINGSMANAGER_H_
diff --git a/src/game-server/skillmanager.cpp b/src/game-server/skillmanager.cpp
index 69a875e..8ebe18f 100644
--- a/src/game-server/skillmanager.cpp
+++ b/src/game-server/skillmanager.cpp
@@ -34,44 +34,48 @@ void SkillManager::clear()
mSkillsInfo.clear();
mNamedSkillsInfo.clear();
+ mDefaultSkillId = 0;
}
void SkillManager::initialize()
{
clear();
+}
- XML::Document doc(mSkillFile);
- xmlNodePtr rootNode = doc.rootNode();
+void SkillManager::reload()
+{
+ initialize();
+}
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skills"))
+/**
+ * Read a <skill-set> element from settings.
+ * Used by SettingsManager.
+ */
+void SkillManager::readSkillSetNode(xmlNodePtr node, const std::string& filename)
+{
+ std::string setName = XML::getProperty(node, "name", std::string());
+ if (setName.empty())
{
- LOG_ERROR("Skill Manager: " << mSkillFile
- << " is not a valid database file!");
+ LOG_WARN("The " << filename << " file is containing unamed <skill-set> "
+ "tags and will be ignored.");
return;
}
- LOG_INFO("Loading skill reference: " << mSkillFile);
+ setName = utils::toLower(setName);
- for_each_xml_child_node(setNode, rootNode)
+ for_each_xml_child_node(skillNode, node)
{
- // The server will prefix the core name with the set, so we need one.
- if (!xmlStrEqual(setNode->name, BAD_CAST "set"))
- continue;
-
- std::string setName = XML::getProperty(setNode, "name", std::string());
- if (setName.empty())
- {
- LOG_WARN("The " << mSkillFile << " file is containing unamed <set> "
- "tags and will be ignored.");
- continue;
- }
-
- setName = utils::toLower(setName);
-
- for_each_xml_child_node(skillNode, setNode)
+ if (xmlStrEqual(skillNode->name, BAD_CAST "skill")) {
readSkillNode(skillNode, setName);
+ }
}
+}
+/**
+ * Check the status of recently loaded configuration.
+ */
+void SkillManager::checkStatus()
+{
printDebugSkillTable();
if (!mDefaultSkillId)
@@ -79,8 +83,7 @@ void SkillManager::initialize()
"Skill map loading. "
"Players won't be able to earn XP when unarmed.");
- LOG_INFO("Loaded " << mSkillsInfo.size() << " skills from "
- << mSkillFile);
+ LOG_INFO("Loaded " << mSkillsInfo.size() << " skills");
}
void SkillManager::readSkillNode(xmlNodePtr skillNode,
@@ -141,7 +144,7 @@ void SkillManager::printDebugSkillTable()
if (::utils::Logger::mVerbosity >= ::utils::Logger::Debug)
{
std::string lastSet;
- LOG_DEBUG("Skill map in " << mSkillFile << ":"
+ LOG_DEBUG("Skill map:"
<< std::endl << "-----");
for (SkillsInfo::iterator it = mSkillsInfo.begin();
it != mSkillsInfo.end(); ++it)
diff --git a/src/game-server/skillmanager.h b/src/game-server/skillmanager.h
index 85f7f42..12828fe 100644
--- a/src/game-server/skillmanager.h
+++ b/src/game-server/skillmanager.h
@@ -28,8 +28,7 @@
class SkillManager
{
public:
- SkillManager(const std::string & skillFile):
- mSkillFile(skillFile),
+ SkillManager():
mDefaultSkillId(0)
{}
@@ -64,6 +63,11 @@ class SkillManager
unsigned getDefaultSkillId() const
{ return mDefaultSkillId; }
+
+ void readSkillSetNode(xmlNodePtr node, const std::string &filename);
+
+ void checkStatus();
+
private:
struct SkillInfo {
SkillInfo():
@@ -80,12 +84,9 @@ class SkillManager
*/
void clear();
- void readSkillNode(xmlNodePtr skillNode, const std::string& setName);
-
void printDebugSkillTable();
- // The skill file (skills.xml)
- std::string mSkillFile;
+ void readSkillNode(xmlNodePtr skillNode, const std::string& setName);
// The skill map
typedef std::map<unsigned, SkillInfo*> SkillsInfo;
diff --git a/src/game-server/specialmanager.cpp b/src/game-server/specialmanager.cpp
index 39616fa..0840d25 100644
--- a/src/game-server/specialmanager.cpp
+++ b/src/game-server/specialmanager.cpp
@@ -36,6 +36,39 @@ static SpecialManager::TargetMode getTargetByString(const std::string &str)
return SpecialManager::TARGET_BEING;
}
+
+/**
+ * Read a <special> element from settings.
+ * Used by SettingsManager.
+ */
+void SpecialManager::readSpecialSetNode(xmlNodePtr node, const std::string &filename)
+{
+ std::string setName = XML::getProperty(node, "name", std::string());
+ if (setName.empty())
+ {
+ LOG_WARN("The " << filename << " file contains unamed <set> tags and will be ignored.");
+ return;
+ }
+
+ setName = utils::toLower(setName);
+
+ for_each_xml_child_node(specialNode, node)
+ {
+ if (xmlStrEqual(specialNode->name, BAD_CAST "special")) {
+ readSpecialNode(specialNode, setName);
+ }
+ }
+
+}
+
+/**
+ * Check the status of recently loaded configuration.
+ */
+void SpecialManager::checkStatus()
+{
+ LOG_INFO("Loaded " << mSpecialsInfo.size() << " specials");
+}
+
void SpecialManager::readSpecialNode(xmlNodePtr specialNode,
const std::string &setName)
{
@@ -94,42 +127,11 @@ void SpecialManager::readSpecialNode(xmlNodePtr specialNode,
void SpecialManager::initialize()
{
clear();
+}
- XML::Document doc(mSpecialFile);
- xmlNodePtr rootNode = doc.rootNode();
-
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "specials"))
- {
- LOG_ERROR("Special Manager: " << mSpecialFile
- << " is not a valid database file!");
- return;
- }
-
- LOG_INFO("Loading special reference: " << mSpecialFile);
-
- for_each_xml_child_node(setNode, rootNode)
- {
- // The server will prefix the core name with the set, so we need one.
- if (!xmlStrEqual(setNode->name, BAD_CAST "set"))
- continue;
-
- std::string setName = XML::getProperty(setNode, "name", std::string());
- if (setName.empty())
- {
- LOG_WARN("The " << mSpecialFile << " file is containing unamed <set> "
- "tags and will be ignored.");
- continue;
- }
-
- setName = utils::toLower(setName);
-
- for_each_xml_child_node(specialNode, setNode)
- {
- if (!xmlStrEqual(specialNode->name, BAD_CAST "special"))
- continue;
- readSpecialNode(specialNode, setName);
- }
- }
+void SpecialManager::reload()
+{
+ clear();
}
void SpecialManager::clear()
diff --git a/src/game-server/specialmanager.h b/src/game-server/specialmanager.h
index e9203a3..b5ac874 100644
--- a/src/game-server/specialmanager.h
+++ b/src/game-server/specialmanager.h
@@ -59,8 +59,7 @@ public:
Script::Ref useCallback;
};
- SpecialManager(const std::string &specialFile):
- mSpecialFile(specialFile)
+ SpecialManager()
{ }
~SpecialManager()
@@ -92,6 +91,11 @@ public:
SpecialInfo *getSpecialInfo(int id);
+
+ void readSpecialSetNode(xmlNodePtr node, const std::string &filename);
+
+ void checkStatus();
+
private:
/**
* Clears up the special maps.
@@ -101,7 +105,6 @@ private:
void readSpecialNode(xmlNodePtr skillNode,
const std::string &setName);
- std::string mSpecialFile;
typedef std::map<unsigned, SpecialInfo*> SpecialsInfo;
SpecialsInfo mSpecialsInfo;
typedef utils::NameMap<SpecialInfo*> NamedSpecialsInfo;
diff --git a/src/game-server/statusmanager.cpp b/src/game-server/statusmanager.cpp
index 389c4cc..2056b58 100644
--- a/src/game-server/statusmanager.cpp
+++ b/src/game-server/statusmanager.cpp
@@ -32,74 +32,15 @@
typedef std::map< int, StatusEffect * > StatusEffectsMap;
static StatusEffectsMap statusEffects;
static utils::NameMap<StatusEffect*> statusEffectsByName;
-static std::string statusReferenceFile;
-void StatusManager::initialize(const std::string &file)
+void StatusManager::initialize()
{
- statusReferenceFile = file;
- reload();
+
}
void StatusManager::reload()
{
- XML::Document doc(statusReferenceFile);
- xmlNodePtr rootNode = doc.rootNode();
-
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "status-effects"))
- {
- LOG_ERROR("Status Manager: Error while parsing status database ("
- << statusReferenceFile << ")!");
- return;
- }
-
- LOG_INFO("Loading status reference: " << statusReferenceFile);
- for_each_xml_child_node(node, rootNode)
- {
- if (!xmlStrEqual(node->name, BAD_CAST "status-effect"))
- continue;
-
- const int id = XML::getProperty(node, "id", 0);
- if (id < 1)
- {
- LOG_WARN("Status Manager: The status ID: " << id << " in "
- << statusReferenceFile
- << " is invalid and will be ignored.");
- continue;
- }
-
- StatusEffect *statusEffect = new StatusEffect(id);
-
- const std::string name = XML::getProperty(node, "name",
- std::string());
- if (!name.empty())
- {
- if (statusEffectsByName.contains(name))
- {
- LOG_WARN("StatusManager: name not unique for status effect "
- << id);
- }
- else
- {
- statusEffectsByName.insert(name, statusEffect);
- }
- }
-
- //TODO: Get these modifiers
-/*
- modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_MIN, XML::getProperty(node, "attack-min", 0));
- modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_DELTA, XML::getProperty(node, "attack-delta", 0));
- modifiers.setAttributeValue(BASE_ATTR_HP, XML::getProperty(node, "hp", 0));
- modifiers.setAttributeValue(BASE_ATTR_PHY_RES, XML::getProperty(node, "defense", 0));
- modifiers.setAttributeValue(CHAR_ATTR_STRENGTH, XML::getProperty(node, "strength", 0));
- modifiers.setAttributeValue(CHAR_ATTR_AGILITY, XML::getProperty(node, "agility", 0));
- modifiers.setAttributeValue(CHAR_ATTR_DEXTERITY, XML::getProperty(node, "dexterity", 0));
- modifiers.setAttributeValue(CHAR_ATTR_VITALITY, XML::getProperty(node, "vitality", 0));
- modifiers.setAttributeValue(CHAR_ATTR_INTELLIGENCE, XML::getProperty(node, "intelligence", 0));
- modifiers.setAttributeValue(CHAR_ATTR_WILLPOWER, XML::getProperty(node, "willpower", 0));
-*/
-
- statusEffects[id] = statusEffect;
- }
+ deinitialize();
}
void StatusManager::deinitialize()
@@ -123,3 +64,62 @@ StatusEffect *StatusManager::getStatusByName(const std::string &name)
{
return statusEffectsByName.value(name);
}
+
+/**
+ * Read a <attribute> element from settings.
+ * Used by SettingsManager.
+ */
+void StatusManager::readStatusNode(xmlNodePtr node, const std::string &filename)
+{
+ const int id = XML::getProperty(node, "id", 0);
+ if (id < 1)
+ {
+ LOG_WARN("Status Manager: The status ID: " << id << " in "
+ << filename
+ << " is invalid and will be ignored.");
+ return;
+ }
+
+ StatusEffect *statusEffect = new StatusEffect(id);
+
+ const std::string name = XML::getProperty(node, "name",
+ std::string());
+ if (!name.empty())
+ {
+ if (statusEffectsByName.contains(name))
+ {
+ LOG_WARN("StatusManager: name not unique for status effect "
+ << id);
+ }
+ else
+ {
+ statusEffectsByName.insert(name, statusEffect);
+ }
+ }
+
+ //TODO: Get these modifiers
+/*
+ modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_MIN, XML::getProperty(node, "attack-min", 0));
+ modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_DELTA, XML::getProperty(node, "attack-delta", 0));
+ modifiers.setAttributeValue(BASE_ATTR_HP, XML::getProperty(node, "hp", 0));
+ modifiers.setAttributeValue(BASE_ATTR_PHY_RES, XML::getProperty(node, "defense", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_STRENGTH, XML::getProperty(node, "strength", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_AGILITY, XML::getProperty(node, "agility", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_DEXTERITY, XML::getProperty(node, "dexterity", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_VITALITY, XML::getProperty(node, "vitality", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_INTELLIGENCE, XML::getProperty(node, "intelligence", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_WILLPOWER, XML::getProperty(node, "willpower", 0));
+*/
+
+ statusEffects[id] = statusEffect;
+
+}
+
+/**
+ * Check the status of recently loaded configuration.
+ */
+void StatusManager::checkStatus()
+{
+ LOG_INFO("Loaded " << statusEffects.size() << " status effects");
+}
+
diff --git a/src/game-server/statusmanager.h b/src/game-server/statusmanager.h
index 8ab321d..cd34138 100644
--- a/src/game-server/statusmanager.h
+++ b/src/game-server/statusmanager.h
@@ -22,6 +22,7 @@
#define STATUSMANAGER_H
#include <string>
+#include "utils/xml.h"
class StatusEffect;
@@ -30,7 +31,7 @@ namespace StatusManager
/**
* Loads status reference file.
*/
- void initialize(const std::string &);
+ void initialize();
/**
* Reloads status reference file.
@@ -51,6 +52,10 @@ namespace StatusManager
* Gets the status having the given name.
*/
StatusEffect *getStatusByName(const std::string &name);
+
+ void readStatusNode(xmlNodePtr node, const std::string &filename);
+
+ void checkStatus();
}
#endif // STATUSMANAGER_H