Itutorial
Legendary OT User
- Joined
- Dec 23, 2014
- Messages
- 2,339
- Solutions
- 68
- Reaction score
- 1,024
Okay, there aren't any compile errors and the code runs through (stable enough). The issue is no data is being saved into the database. I must not be saving or creating data in the correct way for this to work. Here is the code involved.
Its possible my loop to go through each tile on the map is incorrect. (seen in Map::getAllTiles)
Save tiles and populate database query
Map::getAllTiles()
Would even be willing to pay for the solution.
I GOT IT SAVING... okay, now its not loading the items in when the server starts up.
I think the issue is in the loadItems function. All items should be treated the same.
Its possible my loop to go through each tile on the map is incorrect. (seen in Map::getAllTiles)
Save tiles and populate database query
C++:
bool IOMapSerialize::saveMapItems()
{
int64_t start = OTSYS_TIME();
Database& db = Database::getInstance();
//Start the transaction
DBTransaction transaction;
if (!transaction.begin()) {
return false;
}
//clear old tile data
if (!db.executeQuery("DELETE FROM `map_tiles`")) {
return false;
}
// Create database query to save tile information
DBInsert stmt("INSERT INTO `map_tiles` (`data`) VALUES ");
PropWriteStream stream;
// Loop through tile vector and add tile information to query
for (Tile* tile : g_game.map.getAllTiles(0, 15)) {
if (tile) {
saveTile(stream, tile);
size_t attributesSize;
const char* attributes = stream.getStream(attributesSize);
if (attributesSize > 0) {
if (!stmt.addRow(fmt::format("{:s}", db.escapeBlob(attributes, attributesSize)))) {
return false;
}
stream.clear();
}
}
}
if (!stmt.execute()) {
return false;
}
//End the transaction
bool success = transaction.commit();
std::cout << "> Saved map items in: " <<
(OTSYS_TIME() - start) / (1000.) << " s" << std::endl;
return success;
}
Map::getAllTiles()
C++:
std::vector<Tile*> Map::getAllTiles(uint8_t floorMin, uint8_t floorMax) const
{
if (floorMax >= MAP_MAX_LAYERS) {
floorMax = MAP_MAX_LAYERS;
}
if (floorMin < 0) {
floorMin = 0;
}
uint16_t maxX = 5000;
uint16_t maxY = 5000;
uint8_t currentZ = 0;
uint8_t cFloorMax = 0;
if (floorMin) {
currentZ = floorMin;
}
if (floorMax) {
cFloorMax = floorMax;
}
std::vector<Tile*> tileVec;
for (currentZ; currentZ <= cFloorMax; currentZ++) {
for (uint16_t currentY = 0; currentY < maxY; currentY++) {
for (uint16_t currentX = 0; currentX < maxX; currentX++) {
if (currentX == maxX && currentY == maxY && currentZ == cFloorMax) {
break;
}
if (currentX > maxX) {
currentX = maxX;
}
if (currentY > maxY) {
currentY = maxY;
}
const QTreeLeafNode* leaf = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, currentX, currentY);
if (leaf) {
const Floor* floor = leaf->getFloor(currentZ);
if (floor) {
tileVec.push_back(floor->tiles[currentX & FLOOR_MASK][currentY & FLOOR_MASK]);
}
}
}
}
}
return tileVec;
}
Would even be willing to pay for the solution.
Post automatically merged:
I GOT IT SAVING... okay, now its not loading the items in when the server starts up.
C++:
void IOMapSerialize::loadMapItems(Map* map)
{
int64_t start = OTSYS_TIME();
DBResult_ptr result = Database::getInstance().storeQuery("SELECT `data` FROM `map_tiles`");
if (!result) {
return;
}
do {
unsigned long attrSize;
const char* attr = result->getStream("data", attrSize);
PropStream propStream;
propStream.init(attr, attrSize);
uint16_t x, y;
uint8_t z;
if (!propStream.read<uint16_t>(x) || !propStream.read<uint16_t>(y) || !propStream.read<uint8_t>(z)) {
continue;
}
Tile* tile = map->getTile(x, y, z);
if (!tile) {
continue;
}
uint32_t item_count;
if (!propStream.read<uint32_t>(item_count)) {
continue;
}
while (item_count--) {
loadItem(propStream, tile);
}
} while (result->next());
std::cout << "> Loaded map items in: " << (OTSYS_TIME() - start) / (1000.) << " s" << std::endl;
}
Post automatically merged:
I think the issue is in the loadItems function. All items should be treated the same.
C++:
bool IOMapSerialize::loadItem(PropStream& propStream, Cylinder* parent)
{
uint16_t id;
if (!propStream.read<uint16_t>(id)) {
return false;
}
Tile* tile = nullptr;
if (parent->getParent() == nullptr) {
tile = parent->getTile();
}
const ItemType& iType = Item::items[id];
if (iType.moveable || iType.forceSerialize || !tile) {
//create a new item
Item* item = Item::CreateItem(id);
if (item) {
if (item->unserializeAttr(propStream)) {
Container* container = item->getContainer();
if (container && !loadContainer(propStream, container)) {
delete item;
return false;
}
parent->internalAddThing(item);
item->startDecaying();
} else {
std::cout << "WARNING: Unserialization error in IOMapSerialize::loadItem()" << id << std::endl;
delete item;
return false;
}
}
} else {
// Stationary items like doors/beds/blackboards/bookcases
Item* item = nullptr;
if (const TileItemVector* items = tile->getItemList()) {
for (Item* findItem : *items) {
if (findItem->getID() == id) {
item = findItem;
break;
} else if (iType.isDoor() && findItem->getDoor()) {
item = findItem;
break;
} else if (iType.isBed() && findItem->getBed()) {
item = findItem;
break;
}
}
}
if (item) {
if (item->unserializeAttr(propStream)) {
Container* container = item->getContainer();
if (container && !loadContainer(propStream, container)) {
return false;
}
g_game.transformItem(item, id);
} else {
std::cout << "WARNING: Unserialization error in IOMapSerialize::loadItem()" << id << std::endl;
}
} else {
//The map changed since the last save, just read the attributes
std::unique_ptr<Item> dummy(Item::CreateItem(id));
if (dummy) {
dummy->unserializeAttr(propStream);
Container* container = dummy->getContainer();
if (container) {
if (!loadContainer(propStream, container)) {
return false;
}
} else if (BedItem* bedItem = dynamic_cast<BedItem*>(dummy.get())) {
uint32_t sleeperGUID = bedItem->getSleeper();
if (sleeperGUID != 0) {
g_game.removeBedSleeper(sleeperGUID);
}
}
}
}
}
return true;
}
Last edited: