diff options
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/account-server/flooritem.h | 66 | ||||
-rw-r--r-- | src/account-server/serverhandler.cpp | 52 | ||||
-rw-r--r-- | src/account-server/storage.cpp | 87 | ||||
-rw-r--r-- | src/account-server/storage.h | 33 | ||||
-rw-r--r-- | src/common/manaserv_protocol.h | 6 | ||||
-rw-r--r-- | src/game-server/accountconnection.cpp | 64 | ||||
-rw-r--r-- | src/game-server/accountconnection.h | 15 | ||||
-rw-r--r-- | src/game-server/gamehandler.cpp | 29 | ||||
-rw-r--r-- | src/sql/mysql/createTables.sql | 18 | ||||
-rw-r--r-- | src/sql/mysql/updates/update_16_to_17.sql | 19 | ||||
-rw-r--r-- | src/sql/sqlite/createTables.sql | 14 | ||||
-rw-r--r-- | src/sql/sqlite/updates/update_16_to_17.sql | 16 |
13 files changed, 407 insertions, 13 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe5b078..03b2b5c 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 0000000..436dedb --- /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 e5bfdc4..6a41d71 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 4f22964..a1d1694 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 a44156a..3c62992 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 56319b6..532eff6 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 927b5c1..874bf3e 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 4e76315..a144a1d 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 9297190..e6c4737 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 f636503..b75fc0e 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 0000000..008983a --- /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 f353b8e..2d7360d 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 0000000..769c26d --- /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'; |