summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/account-server/flooritem.h66
-rw-r--r--src/account-server/serverhandler.cpp52
-rw-r--r--src/account-server/storage.cpp87
-rw-r--r--src/account-server/storage.h33
-rw-r--r--src/common/manaserv_protocol.h6
-rw-r--r--src/game-server/accountconnection.cpp64
-rw-r--r--src/game-server/accountconnection.h15
-rw-r--r--src/game-server/gamehandler.cpp29
-rw-r--r--src/sql/mysql/createTables.sql18
-rw-r--r--src/sql/mysql/updates/update_16_to_17.sql19
-rw-r--r--src/sql/sqlite/createTables.sql14
-rw-r--r--src/sql/sqlite/updates/update_16_to_17.sql16
13 files changed, 407 insertions, 13 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fe5b0788..03b2b5ce 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -149,6 +149,7 @@ SET(SRCS_MANASERVACCOUNT
account-server/accounthandler.cpp
account-server/character.h
account-server/character.cpp
+ account-server/flooritem.h
account-server/serverhandler.h
account-server/serverhandler.cpp
account-server/storage.h
diff --git a/src/account-server/flooritem.h b/src/account-server/flooritem.h
new file mode 100644
index 00000000..436dedbc
--- /dev/null
+++ b/src/account-server/flooritem.h
@@ -0,0 +1,66 @@
+/*
+ * The Mana Server
+ * Copyright (C) 2011 The Mana 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 FLOOR_ITEM_H
+#define FLOOR_ITEM_H
+
+class FloorItem
+{
+public:
+ FloorItem():
+ mItemId(0), mItemAmount(0), mPosX(0), mPosY(0)
+ {}
+
+ FloorItem(int itemId, int itemAmount, int posX, int posY):
+ mItemId(itemId), mItemAmount(itemAmount), mPosX(posX), mPosY(posY)
+ {}
+
+ /**
+ * Returns the item id
+ */
+ int getItemId() const
+ { return mItemId; }
+
+ /**
+ * Returns the amount of items
+ */
+ int getItemAmount() const
+ { return mItemAmount; }
+
+ /**
+ * Returns the position x of the item(s)
+ */
+ int getPosX() const
+ { return mPosX; }
+
+ /**
+ * Returns the position x of the item(s)
+ */
+ int getPosY() const
+ { return mPosY; }
+
+private:
+ int mItemId;
+ int mItemAmount;
+ int mPosX;
+ int mPosY;
+};
+
+#endif // FLOOR_ITEM_H
diff --git a/src/account-server/serverhandler.cpp b/src/account-server/serverhandler.cpp
index e5bfdc40..6a41d715 100644
--- a/src/account-server/serverhandler.cpp
+++ b/src/account-server/serverhandler.cpp
@@ -27,6 +27,7 @@
#include "account-server/accountclient.h"
#include "account-server/accounthandler.h"
#include "account-server/character.h"
+#include "account-server/flooritem.h"
#include "account-server/storage.h"
#include "chat-server/chathandler.h"
#include "chat-server/post.h"
@@ -241,9 +242,15 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
else
{
MessageOut outMsg(AGMSG_ACTIVE_MAP);
+
+ // Map variables
outMsg.writeInt16(id);
std::map<std::string, std::string> variables;
variables = storage->getAllWorldStateVars(id);
+
+ // Map vars number
+ outMsg.writeInt16(variables.size());
+
for (std::map<std::string, std::string>::iterator i = variables.begin();
i != variables.end();
i++)
@@ -251,6 +258,23 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
outMsg.writeString(i->first);
outMsg.writeString(i->second);
}
+
+ // Persistent Floor Items
+ std::list<FloorItem> items;
+ items = storage->getFloorItemsFromMap(id);
+
+ outMsg.writeInt16(items.size()); //number of floor items
+
+ // Send each map item: item_id, amount, pos_x, pos_y
+ for (std::list<FloorItem>::iterator i = items.begin();
+ i != items.end(); ++i)
+ {
+ outMsg.writeInt32(i->getItemId());
+ outMsg.writeInt16(i->getItemAmount());
+ outMsg.writeInt16(i->getPosX());
+ outMsg.writeInt16(i->getPosY());
+ }
+
comp->send(outMsg);
MapStatistics &m = server->maps[id];
m.nbThings = 0;
@@ -549,6 +573,34 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
chatHandler->handlePartyInvite(msg);
break;
+ case GAMSG_CREATE_ITEM_ON_MAP:
+ {
+ int mapId = msg.readInt32();
+ int itemId = msg.readInt32();
+ int amount = msg.readInt16();
+ int posX = msg.readInt16();
+ int posY = msg.readInt16();
+
+ LOG_DEBUG("Gameserver create item " << itemId
+ << " on map " << mapId);
+
+ storage->addFloorItem(mapId, itemId, amount, posX, posY);
+ } break;
+
+ case GAMSG_REMOVE_ITEM_ON_MAP:
+ {
+ int mapId = msg.readInt32();
+ int itemId = msg.readInt32();
+ int amount = msg.readInt16();
+ int posX = msg.readInt16();
+ int posY = msg.readInt16();
+
+ LOG_DEBUG("Gameserver removed item " << itemId
+ << " from map " << mapId);
+
+ storage->removeFloorItem(mapId, itemId, amount, posX, posY);
+ } break;
+
default:
LOG_WARN("ServerHandler::processMessage, Invalid message type: "
<< msg.getId());
diff --git a/src/account-server/storage.cpp b/src/account-server/storage.cpp
index 4f22964b..a1d1694b 100644
--- a/src/account-server/storage.cpp
+++ b/src/account-server/storage.cpp
@@ -24,6 +24,7 @@
#include "account-server/storage.h"
#include "account-server/account.h"
+#include "account-server/flooritem.h"
#include "chat-server/chatchannel.h"
#include "chat-server/guild.h"
#include "chat-server/post.h"
@@ -90,6 +91,7 @@ static const char *AUCTION_TBL_NAME = "mana_auctions";
static const char *AUCTION_BIDS_TBL_NAME = "mana_auction_bids";
static const char *ONLINE_USERS_TBL_NAME = "mana_online_list";
static const char *TRANSACTION_TBL_NAME = "mana_transactions";
+static const char *FLOOR_ITEMS_TBL_NAME = "mana_floor_items";
Storage::Storage()
: mDb(dal::DataProviderFactory::createDataProvider()),
@@ -138,6 +140,15 @@ void Storage::open()
std::ostringstream sql;
sql << "DELETE FROM " << ONLINE_USERS_TBL_NAME;
mDb->execSql(sql.str());
+
+ // In case where the server shouldn't keep floor item in database,
+ // we remove remnants at startup
+ if (Configuration::getValue("game_floorItemDecayTime", 0) > 0)
+ {
+ sql.clear();
+ sql << "DELETE FROM " << FLOOR_ITEMS_TBL_NAME;
+ mDb->execSql(sql.str());
+ }
}
catch (const DbConnectionFailure& e)
{
@@ -1376,6 +1387,82 @@ void Storage::removeGuildMember(int guildId, int memberId)
}
}
+void Storage::addFloorItem(int mapId, int itemId, int amount,
+ int posX, int posY)
+{
+ try
+ {
+ std::ostringstream sql;
+ sql << "INSERT INTO " << FLOOR_ITEMS_TBL_NAME
+ << " (map_id, item_id, amount, pos_x, pos_y)"
+ << " VALUES ("
+ << mapId << ", "
+ << itemId << ", "
+ << amount << ", "
+ << posX << ", "
+ << posY << ");";
+ mDb->execSql(sql.str());
+ }
+ catch (const dal::DbSqlQueryExecFailure& e)
+ {
+ utils::throwError("(DALStorage::addFloorItem) SQL query failure: ", e);
+ }
+}
+
+void Storage::removeFloorItem(int mapId, int itemId, int amount,
+ int posX, int posY)
+{
+ try
+ {
+ std::ostringstream sql;
+ sql << "DELETE FROM " << FLOOR_ITEMS_TBL_NAME
+ << " WHERE map_id = "
+ << mapId << " AND item_id = "
+ << itemId << " AND amount = "
+ << amount << " AND pos_x = "
+ << posX << " AND pos_y = "
+ << posY << ";";
+ mDb->execSql(sql.str());
+ }
+ catch (const dal::DbSqlQueryExecFailure& e)
+ {
+ utils::throwError("(DALStorage::removeFloorItem) SQL query failure: ",
+ e);
+ }
+}
+
+std::list<FloorItem> Storage::getFloorItemsFromMap(int mapId)
+{
+ std::list<FloorItem> floorItems;
+
+ try
+ {
+ std::ostringstream sql;
+ sql << "SELECT * FROM " << FLOOR_ITEMS_TBL_NAME
+ << " WHERE map_id = " << mapId;
+
+ string_to< unsigned > toUint;
+ const dal::RecordSet &itemInfo = mDb->execSql(sql.str());
+ if (!itemInfo.isEmpty())
+ {
+ for (int k = 0, size = itemInfo.rows(); k < size; ++k)
+ {
+ floorItems.push_back(FloorItem(toUint(itemInfo(k, 2)),
+ toUint(itemInfo(k, 3)),
+ toUint(itemInfo(k, 4)),
+ toUint(itemInfo(k, 5))));
+ }
+ }
+ }
+ catch (const dal::DbSqlQueryExecFailure &e)
+ {
+ utils::throwError("DALStorage::getFloorItemsFromMap "
+ "SQL query failure: ", e);
+ }
+
+ return floorItems;
+}
+
void Storage::setMemberRights(int guildId, int memberId, int rights)
{
try
diff --git a/src/account-server/storage.h b/src/account-server/storage.h
index a44156a4..3c629920 100644
--- a/src/account-server/storage.h
+++ b/src/account-server/storage.h
@@ -32,6 +32,7 @@
class Account;
class Character;
class ChatChannel;
+class FloorItem;
class Guild;
class Letter;
class Post;
@@ -288,6 +289,38 @@ class Storage
std::list<Guild*> getGuildList();
/**
+ * Add a floor item to map.
+ *
+ * Used to keep the floor item persistently between two server restart.
+ *
+ * @param mapId The map id
+ * @param itemId The item id
+ * @param posX Position X of the item in pixels
+ * @param posY Position Y of the item in pixels
+ */
+ void addFloorItem(int mapId, int itemId, int amount,
+ int posX, int posY);
+
+ /**
+ * Remove item from map persistence
+ *
+ * @param mapId The map id
+ * @param itemId The item id
+ * @param posX Position X of the item in pixels
+ * @param posY Position Y of the item in pixels
+ */
+ void removeFloorItem(int mapId, int itemId, int amount,
+ int posX, int posY);
+
+
+ /**
+ * Get all persistent items from the given map id
+ *
+ * @param mapId The map id
+ */
+ std::list<FloorItem> getFloorItemsFromMap(int mapId);
+
+ /**
* Update an account to the database.
*
* @param Account object to update.
diff --git a/src/common/manaserv_protocol.h b/src/common/manaserv_protocol.h
index 56319b69..532eff6f 100644
--- a/src/common/manaserv_protocol.h
+++ b/src/common/manaserv_protocol.h
@@ -26,7 +26,7 @@ namespace ManaServ {
enum {
PROTOCOL_VERSION = 1,
- SUPPORTED_DB_VERSION = 16
+ SUPPORTED_DB_VERSION = 17
};
/**
@@ -232,7 +232,7 @@ enum {
// Inter-server
GAMSG_REGISTER = 0x0500, // S address, W port, S password, D items db revision, { W map id }*
AGMSG_REGISTER_RESPONSE = 0x0501, // C item version, C password response, { S globalvar_key, S globalvar_value }
- AGMSG_ACTIVE_MAP = 0x0502, // W map id, { S mapvar_key, S mapvar_value }
+ AGMSG_ACTIVE_MAP = 0x0502, // W map id, W Number of mapvar_key mapvar_value sent, { S mapvar_key, S mapvar_value }, W Number of map items, { D item Id, W amount, W posX, W posY }
AGMSG_PLAYER_ENTER = 0x0510, // B*32 token, D id, S name, serialised character data
GAMSG_PLAYER_DATA = 0x0520, // D id, serialised character data
GAMSG_REDIRECT = 0x0530, // D id
@@ -258,6 +258,8 @@ enum {
GCMSG_STORE_POST = 0x05A5, // D sender id, S receiver name, S letter, { W attachment item id, W quantity }
CGMSG_STORE_POST_RESPONSE = 0x05A6, // D id, B error
GAMSG_TRANSACTION = 0x0600, // D character id, D action, S message
+ GAMSG_CREATE_ITEM_ON_MAP = 0x0601, // D map id, D item id, W amount, W pos x, W pos y
+ GAMSG_REMOVE_ITEM_ON_MAP = 0x0602, // D map id, D item id, W amount, W pos x, W pos y
XXMSG_INVALID = 0x7FFF
};
diff --git a/src/game-server/accountconnection.cpp b/src/game-server/accountconnection.cpp
index 927b5c15..874bf3e4 100644
--- a/src/game-server/accountconnection.cpp
+++ b/src/game-server/accountconnection.cpp
@@ -26,6 +26,7 @@
#include "game-server/map.h"
#include "game-server/mapcomposite.h"
#include "game-server/mapmanager.h"
+#include "game-server/item.h"
#include "game-server/itemmanager.h"
#include "game-server/postman.h"
#include "game-server/quest.h"
@@ -158,18 +159,45 @@ void AccountConnection::processMessage(MessageIn &msg)
case AGMSG_ACTIVE_MAP:
{
- int id = msg.readInt16();
- if (MapManager::raiseActive(id))
+ int mapId = msg.readInt16();
+ if (MapManager::raiseActive(mapId))
{
- // set map variables
- MapComposite *m = MapManager::getMap(id);
- while (msg.getUnreadLength())
+ // Set map variables
+ MapComposite *m = MapManager::getMap(mapId);
+ int mapVarsNumber = msg.readInt16();
+ for(int i = 0; i < mapVarsNumber; ++i)
{
std::string key = msg.readString();
std::string value = msg.readString();
if (!key.empty() && !value.empty())
- {
m->setVariableFromDbserver(key, value);
+ }
+
+ // Recreate potential persistent floor items
+ LOG_DEBUG("Recreate persistant items on map " << mapId);
+ int floorItemsNumber = msg.readInt16();
+
+ for(int i = 0; i < floorItemsNumber; i += 4)
+ {
+ int itemId = msg.readInt32();
+ int amount = msg.readInt16();
+ int posX = msg.readInt16();
+ int posY = msg.readInt16();
+
+ if (ItemClass *ic = itemManager->getItem(itemId))
+ {
+ Item *item = new Item(ic, amount);
+ item->setMap(m);
+ Point dst(posX, posY);
+ item->setPosition(dst);
+
+ if (!GameState::insertOrDelete(item))
+ {
+ // The map is full.
+ LOG_WARN("Couldn't add floor item(s) " << itemId
+ << " into map " << mapId);
+ return;
+ }
}
}
}
@@ -466,3 +494,27 @@ void AccountConnection::sendTransaction(int id, int action, const std::string &m
msg.writeString(message);
send(msg);
}
+
+void AccountConnection::createFloorItems(int mapId, int itemId, int amount,
+ int posX, int posY)
+{
+ MessageOut msg(GAMSG_CREATE_ITEM_ON_MAP);
+ msg.writeInt32(mapId);
+ msg.writeInt32(itemId);
+ msg.writeInt16(amount);
+ msg.writeInt16(posX);
+ msg.writeInt16(posY);
+ send(msg);
+}
+
+void AccountConnection::removeFloorItems(int mapId, int itemId, int amount,
+ int posX, int posY)
+{
+ MessageOut msg(GAMSG_REMOVE_ITEM_ON_MAP);
+ msg.writeInt32(mapId);
+ msg.writeInt32(itemId);
+ msg.writeInt16(amount);
+ msg.writeInt16(posX);
+ msg.writeInt16(posY);
+ send(msg);
+}
diff --git a/src/game-server/accountconnection.h b/src/game-server/accountconnection.h
index 4e763158..a144a1d1 100644
--- a/src/game-server/accountconnection.h
+++ b/src/game-server/accountconnection.h
@@ -160,6 +160,21 @@ class AccountConnection : public Connection
void updateOnlineStatus(int charId, bool online);
/**
+ * Adds floor items info on database.
+ *
+ * This is used to make them potentially persistent between two server
+ * restart.
+ */
+ void createFloorItems(int mapId, int itemId, int amount,
+ int posX, int posY);
+
+ /**
+ * Remove floor items from the database
+ */
+ void removeFloorItems(int mapId, int itemId, int amount,
+ int posX, int posY);
+
+ /**
* Send transaction to account server
*/
void sendTransaction(int id, int action, const std::string &message);
diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp
index 92971903..e6c4737f 100644
--- a/src/game-server/gamehandler.cpp
+++ b/src/game-server/gamehandler.cpp
@@ -472,11 +472,22 @@ void GameHandler::handlePickup(GameClient &client, MessageIn &message)
{
Item *item = static_cast< Item * >(o);
ItemClass *ic = item->getItemClass();
+ int amount = item->getAmount();
if (!Inventory(client.character).insert(ic->getDatabaseID(),
- item->getAmount()))
+ amount))
{
-
GameState::remove(item);
+
+ // We only do this when items are to be kept in memory
+ // between two server restart.
+ if (!Configuration::getValue("game_floorItemDecayTime", 0))
+ {
+ // Remove the floor item from map
+ accountHandler->removeFloorItems(map->getID(),
+ ic->getDatabaseID(),
+ amount, x, y);
+ }
+
// log transaction
std::stringstream str;
str << "User picked up item " << ic->getDatabaseID()
@@ -531,8 +542,20 @@ void GameHandler::handleDrop(GameClient &client, MessageIn &message)
delete item;
return;
}
- // log transaction
+
Point pt = client.character->getPosition();
+
+ // We store the item in database only when the floor items are meant
+ // to be persistent between two server restarts.
+ if (!Configuration::getValue("game_floorItemDecayTime", 0))
+ {
+ // Create the floor item on map
+ accountHandler->createFloorItems(client.character->getMap()->getID(),
+ ic->getDatabaseID(),
+ amount, pt.x, pt.y);
+ }
+
+ // log transaction
std::stringstream str;
str << "User dropped item " << ic->getDatabaseID()
<< " at " << pt.x << "x" << pt.y;
diff --git a/src/sql/mysql/createTables.sql b/src/sql/mysql/createTables.sql
index f6365031..b75fc0ed 100644
--- a/src/sql/mysql/createTables.sql
+++ b/src/sql/mysql/createTables.sql
@@ -179,6 +179,22 @@ DEFAULT CHARSET=utf8
AUTO_INCREMENT=1 ;
--
+-- table: `mana_floor_items`
+--
+CREATE TABLE IF NOT EXISTS `mana_floor_items` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `map_id` int(10) unsigned NOT NULL,
+ `item_id` int(10) unsigned NOT NULL,
+ `amount` smallint(5) unsigned NOT NULL,
+ `pos_x` smallint(5) unsigned NOT NULL,
+ `pos_y` smallint(5) unsigned NOT NULL,
+ --
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB
+DEFAULT CHARSET=utf8
+AUTO_INCREMENT=1 ;
+
+--
-- table: `mana_char_equips`
--
CREATE TABLE IF NOT EXISTS `mana_char_equips` (
@@ -421,7 +437,7 @@ AUTO_INCREMENT=0 ;
INSERT INTO mana_world_states VALUES('accountserver_startup',NULL,NULL, NOW());
INSERT INTO mana_world_states VALUES('accountserver_version',NULL,NULL, NOW());
-INSERT INTO mana_world_states VALUES('database_version', NULL,'16', NOW());
+INSERT INTO mana_world_states VALUES('database_version', NULL,'17', NOW());
-- all known transaction codes
diff --git a/src/sql/mysql/updates/update_16_to_17.sql b/src/sql/mysql/updates/update_16_to_17.sql
new file mode 100644
index 00000000..008983aa
--- /dev/null
+++ b/src/sql/mysql/updates/update_16_to_17.sql
@@ -0,0 +1,19 @@
+-- Create the new floor item table
+CREATE TABLE IF NOT EXISTS `mana_floor_items` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `map_id` int(10) unsigned NOT NULL,
+ `item_id` int(10) unsigned NOT NULL,
+ `amount` smallint(5) unsigned NOT NULL,
+ `pos_x` smallint(5) unsigned NOT NULL,
+ `pos_y` smallint(5) unsigned NOT NULL,
+ --
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB
+DEFAULT CHARSET=utf8
+AUTO_INCREMENT=1 ;
+
+-- Update database version.
+UPDATE mana_world_states
+SET value = '17',
+moddate = UNIX_TIMESTAMP()
+WHERE state_name = 'database_version';
diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql
index f353b8e1..2d7360da 100644
--- a/src/sql/sqlite/createTables.sql
+++ b/src/sql/sqlite/createTables.sql
@@ -173,6 +173,18 @@ CREATE INDEX mana_item_attributes_item ON mana_item_attributes ( item_id );
-----------------------------------------------------------------------------
+CREATE TABLE mana_floor_items
+(
+ id INTEGER PRIMARY KEY,
+ map_id INTEGER NOT NULL,
+ item_id INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ pos_x INTEGER NOT NULL,
+ pos_y INTEGER NOT NULL
+);
+
+-----------------------------------------------------------------------------
+
CREATE TABLE mana_char_equips
(
id INTEGER PRIMARY KEY,
@@ -407,7 +419,7 @@ AS
INSERT INTO mana_world_states VALUES('accountserver_startup',NULL,NULL, strftime('%s','now'));
INSERT INTO mana_world_states VALUES('accountserver_version',NULL,NULL, strftime('%s','now'));
-INSERT INTO mana_world_states VALUES('database_version', NULL,'16', strftime('%s','now'));
+INSERT INTO mana_world_states VALUES('database_version', NULL,'17', strftime('%s','now'));
-- all known transaction codes
diff --git a/src/sql/sqlite/updates/update_16_to_17.sql b/src/sql/sqlite/updates/update_16_to_17.sql
new file mode 100644
index 00000000..769c26da
--- /dev/null
+++ b/src/sql/sqlite/updates/update_16_to_17.sql
@@ -0,0 +1,16 @@
+-- Create the new floor item table
+CREATE TABLE mana_floor_items
+(
+ id INTEGER PRIMARY KEY,
+ map_id INTEGER NOT NULL,
+ item_id INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ pos_x INTEGER NOT NULL,
+ pos_y INTEGER NOT NULL
+);
+
+-- Update the database version, and set date of update
+UPDATE mana_world_states
+ SET value = '17',
+ moddate = strftime('%s','now')
+ WHERE state_name = 'database_version';