tibia-rme/source/live_socket.cpp

401 lines
10 KiB
C++
Raw Permalink Normal View History

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
2020-07-30 11:42:28 -03:00
// Remere's Map Editor 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 3 of the License, or
// (at your option) any later version.
//
// Remere's Map Editor 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 this program. If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////
#include "main.h"
#include "live_socket.h"
#include "map_region.h"
#include "iomap_otbm.h"
#include "live_tab.h"
#include "editor.h"
LiveSocket::LiveSocket() :
cursors(), mapReader(nullptr, 0), mapWriter(),
mapVersion(MapVersion(MAP_OTBM_4, CLIENT_VERSION_NONE)), log(nullptr),
2023-10-09 19:12:16 -07:00
name("User"), password("") {
//
}
2023-10-09 19:12:16 -07:00
LiveSocket::~LiveSocket() {
//
}
2023-10-09 19:12:16 -07:00
wxString LiveSocket::getName() const {
return name;
}
2023-10-09 19:12:16 -07:00
bool LiveSocket::setName(const wxString &newName) {
if (newName.empty()) {
2016-11-05 15:28:14 +01:00
setLastError("Must provide a name.");
return false;
2023-10-09 19:12:16 -07:00
} else if (newName.length() > 32) {
2016-11-05 15:28:14 +01:00
setLastError("Name is too long.");
return false;
}
name = newName;
return true;
}
2023-10-09 19:12:16 -07:00
wxString LiveSocket::getPassword() const {
return password;
}
2023-10-09 19:12:16 -07:00
bool LiveSocket::setPassword(const wxString &newPassword) {
if (newPassword.length() > 32) {
2016-11-05 15:28:14 +01:00
setLastError("Password is too long.");
return false;
}
password = newPassword;
return true;
}
2023-10-09 19:12:16 -07:00
wxString LiveSocket::getLastError() const {
return lastError;
}
2023-10-09 19:12:16 -07:00
void LiveSocket::setLastError(const wxString &error) {
lastError = error;
}
2023-10-09 19:12:16 -07:00
std::string LiveSocket::getHostName() const {
return "?";
}
2023-10-09 19:12:16 -07:00
std::vector<LiveCursor> LiveSocket::getCursorList() const {
std::vector<LiveCursor> cursorList;
2023-10-09 19:12:16 -07:00
for (auto &cursorEntry : cursors) {
cursorList.push_back(cursorEntry.second);
}
return cursorList;
}
2023-10-09 19:12:16 -07:00
void LiveSocket::logMessage(const wxString &message) {
wxTheApp->CallAfter([this, message]() {
2023-10-09 19:12:16 -07:00
if (log) {
log->Message(message);
}
});
}
2023-10-09 19:12:16 -07:00
void LiveSocket::receiveNode(NetworkMessage &message, Editor &editor, Action* action, int32_t ndx, int32_t ndy, bool underground) {
feat: synchronizing commits with the official rme repository (#36) * Show indicators for pickupable and moveable items * Fix: drawing always refreshing ui * Fix crash on invalid friend for wallbrush * Option to remove empty spawns * Draws position indicator, some code cleanup * Teleport copy/paste improvements * Fix flood fill * Add function to get minimap/8bit color * Small code cleanup * Cleanup Position * Code cleanup and small optimizations * Code cleanup * Code cleanup and small optimizations (#406) * Cleanup and cast functions. * Avoid adding a new Unique ID if it already exists * Code cleanup and small optimizations * More changes and cleanup * Changes and cleanup * Some changes * Fix copy position. * Only show uid/aid alert if it really changed * Add actions history panel * Does not draw tooltips on minimap mode * Use constexpr * Replace items fix (#408) * Draw grid small optimization * Small change in selection box and Fix #409 * Fix some xpm * Ingame box improvements, add lights support. * Fix go to previous position (#410) * Fix depot crash (#411) * Fix XPMs * Export minimap as .otmm (otclient format) or .png (#413) * Fix glitch after drawing secondary map * fix * Update about_window.cpp * sonar * fix Minimap and progress bar * fix erro load items.xml * fix * fix doodad brush * fix: slightly more accurate house size estimation * feat: update items.otb and items.xml * fix: bad merge * Revert "feat: update items.otb and items.xml" This reverts commit 40f1edc70f17c423282d546a41541a8fe9b92dcc. --------- Co-authored-by: Nailson <Mignari@users.noreply.github.com> Co-authored-by: wtver <51377408+maattch@users.noreply.github.com> Co-authored-by: Majesty <32709570+majestyotbr@users.noreply.github.com> Co-authored-by: Luan Santos <github@luan.sh>
2023-10-09 23:02:37 -03:00
QTreeNode* node = editor.getMap().getLeaf(ndx * 4, ndy * 4);
2023-10-09 19:12:16 -07:00
if (!node) {
2016-11-05 15:28:14 +01:00
log->Message("Warning: Received update for unknown tile (" + std::to_string(ndx * 4) + "/" + std::to_string(ndy * 4) + "/" + (underground ? "true" : "false") + ")");
return;
}
node->setRequested(underground, false);
node->setVisible(underground, true);
uint16_t floorBits = message.read<uint16_t>();
2023-10-09 19:12:16 -07:00
if (floorBits == 0) {
return;
}
2023-10-09 19:12:16 -07:00
for (uint_fast8_t z = 0; z < 16; ++z) {
if (testFlags(floorBits, static_cast<uint64_t>(1) << z)) {
receiveFloor(message, editor, action, ndx, ndy, z, node, node->getFloor(z));
}
}
}
2023-10-09 19:12:16 -07:00
void LiveSocket::sendNode(uint32_t clientId, QTreeNode* node, int32_t ndx, int32_t ndy, uint32_t floorMask) {
bool underground;
2023-10-09 19:12:16 -07:00
if (floorMask & 0xFF00) {
if (floorMask & 0x00FF) {
underground = false;
} else {
underground = true;
}
} else {
underground = false;
}
node->setVisible(clientId, underground, true);
// Send message
NetworkMessage message;
message.write<uint8_t>(PACKET_NODE);
message.write<uint32_t>((ndx << 18) | (ndy << 4) | ((floorMask & 0xFF00) ? 1 : 0));
2023-10-09 19:12:16 -07:00
if (!node) {
message.write<uint8_t>(0x00);
} else {
Floor** floors = node->getFloors();
uint16_t sendMask = 0;
2023-10-09 19:12:16 -07:00
for (uint32_t z = 0; z < 16; ++z) {
uint32_t bit = 1 << z;
2023-10-09 19:12:16 -07:00
if (floors[z] && testFlags(floorMask, bit)) {
sendMask |= bit;
}
}
message.write<uint16_t>(sendMask);
2023-10-09 19:12:16 -07:00
for (uint32_t z = 0; z < 16; ++z) {
if (testFlags(sendMask, static_cast<uint64_t>(1) << z)) {
sendFloor(message, floors[z]);
}
}
}
send(message);
}
2023-10-09 19:12:16 -07:00
void LiveSocket::receiveFloor(NetworkMessage &message, Editor &editor, Action* action, int32_t ndx, int32_t ndy, int32_t z, QTreeNode* node, Floor* floor) {
Map &map = editor.getMap();
uint16_t tileBits = message.read<uint16_t>();
2023-10-09 19:12:16 -07:00
if (tileBits == 0) {
for (uint_fast8_t x = 0; x < 4; ++x) {
for (uint_fast8_t y = 0; y < 4; ++y) {
action->addChange(new Change(map.allocator(node->createTile(ndx * 4 + x, ndy * 4 + y, z))));
}
}
return;
}
2016-09-29 19:24:45 -03:00
// -1 on address since we skip the first START_NODE when sending
2023-10-09 19:12:16 -07:00
const std::string &data = message.read<std::string>();
mapReader.assign(reinterpret_cast<const uint8_t*>(data.c_str() - 1), data.size());
BinaryNode* rootNode = mapReader.getRootNode();
BinaryNode* tileNode = rootNode->getChild();
Position position(0, 0, z);
2023-10-09 19:12:16 -07:00
for (uint_fast8_t x = 0; x < 4; ++x) {
for (uint_fast8_t y = 0; y < 4; ++y) {
position.x = (ndx * 4) + x;
position.y = (ndy * 4) + y;
2023-10-09 19:12:16 -07:00
if (testFlags(tileBits, static_cast<uint64_t>(1) << ((x * 4) + y))) {
receiveTile(tileNode, editor, action, &position);
tileNode->advance();
} else {
action->addChange(new Change(map.allocator(node->createTile(position.x, position.y, z))));
}
}
}
mapReader.close();
}
2023-10-09 19:12:16 -07:00
void LiveSocket::sendFloor(NetworkMessage &message, Floor* floor) {
uint16_t tileBits = 0;
2023-10-09 19:12:16 -07:00
for (uint_fast8_t x = 0; x < 4; ++x) {
for (uint_fast8_t y = 0; y < 4; ++y) {
uint_fast8_t index = (x * 4) + y;
Tile* tile = floor->locs[index].get();
2023-10-09 19:12:16 -07:00
if (tile && tile->size() > 0) {
tileBits |= (1 << index);
}
}
}
message.write<uint16_t>(tileBits);
2023-10-09 19:12:16 -07:00
if (tileBits == 0) {
return;
}
mapWriter.reset();
2023-10-09 19:12:16 -07:00
for (uint_fast8_t x = 0; x < 4; ++x) {
for (uint_fast8_t y = 0; y < 4; ++y) {
uint_fast8_t index = (x * 4) + y;
2023-10-09 19:12:16 -07:00
if (testFlags(tileBits, static_cast<uint64_t>(1) << index)) {
sendTile(mapWriter, floor->locs[index].get(), nullptr);
}
}
}
mapWriter.endNode();
std::string stream(
reinterpret_cast<char*>(mapWriter.getMemory()),
mapWriter.getSize()
);
message.write<std::string>(stream);
}
2023-10-09 19:12:16 -07:00
void LiveSocket::receiveTile(BinaryNode* node, Editor &editor, Action* action, const Position* position) {
ASSERT(node != nullptr);
Tile* tile = readTile(node, editor, position);
2023-10-09 19:12:16 -07:00
if (tile) {
action->addChange(newd Change(tile));
}
}
2023-10-09 19:12:16 -07:00
void LiveSocket::sendTile(MemoryNodeFileWriteHandle &writer, Tile* tile, const Position* position) {
writer.addNode(tile->isHouseTile() ? OTBM_HOUSETILE : OTBM_TILE);
2023-10-09 19:12:16 -07:00
if (position) {
writer.addU16(position->x);
writer.addU16(position->y);
writer.addU8(position->z);
}
2023-10-09 19:12:16 -07:00
if (tile->isHouseTile()) {
writer.addU32(tile->getHouseID());
}
2023-10-09 19:12:16 -07:00
if (tile->getMapFlags()) {
writer.addByte(OTBM_ATTR_TILE_FLAGS);
writer.addU32(tile->getMapFlags());
}
Item* ground = tile->ground;
2023-10-09 19:12:16 -07:00
if (ground) {
if (ground->isComplex()) {
ground->serializeItemNode_OTBM(mapVersion, writer);
} else {
writer.addByte(OTBM_ATTR_ITEM);
ground->serializeItemCompact_OTBM(mapVersion, writer);
}
}
2023-10-09 19:12:16 -07:00
for (Item* item : tile->items) {
item->serializeItemNode_OTBM(mapVersion, writer);
}
writer.endNode();
}
2023-10-09 19:12:16 -07:00
Tile* LiveSocket::readTile(BinaryNode* node, Editor &editor, const Position* position) {
ASSERT(node != nullptr);
2023-10-09 19:12:16 -07:00
Map &map = editor.getMap();
uint8_t tileType;
node->getByte(tileType);
2023-10-09 19:12:16 -07:00
if (tileType != OTBM_TILE && tileType != OTBM_HOUSETILE) {
return nullptr;
}
Position pos;
2023-10-09 19:12:16 -07:00
if (position) {
pos = *position;
} else {
2023-10-13 20:26:41 -03:00
uint16_t x = 0; // Inicializar com valor padrão
uint16_t y = 0; // Inicializar com valor padrão
uint8_t z = 0; // Inicializar com valor padrão
if (node->getU16(x) && node->getU16(y) && node->getU8(z)) {
pos.x = x;
pos.y = y;
pos.z = z;
} else {
// Tratar erro: os métodos getU16 ou getU8 falharam
}
}
Tile* tile = map.allocator(
map.createTileL(pos)
);
2023-10-09 19:12:16 -07:00
if (tileType == OTBM_HOUSETILE) {
uint32_t houseId;
2023-10-09 19:12:16 -07:00
if (!node->getU32(houseId)) {
// warning("House tile without house data, discarding tile");
delete tile;
return nullptr;
}
2023-10-09 19:12:16 -07:00
if (houseId) {
House* house = map.houses.getHouse(houseId);
2023-10-09 19:12:16 -07:00
if (house) {
tile->setHouse(house);
}
} else {
2023-10-09 19:12:16 -07:00
// warning("Invalid house id from tile %d:%d:%d", pos.x, pos.y, pos.z);
}
}
uint8_t attribute;
2023-10-09 19:12:16 -07:00
while (node->getU8(attribute)) {
switch (attribute) {
case OTBM_ATTR_TILE_FLAGS: {
uint32_t flags = 0;
2023-10-09 19:12:16 -07:00
if (!node->getU32(flags)) {
// warning("Invalid tile flags of tile on %d:%d:%d", pos.x, pos.y, pos.z);
}
tile->setMapFlags(flags);
break;
}
case OTBM_ATTR_ITEM: {
Item* item = Item::Create_OTBM(mapVersion, node);
2023-10-09 19:12:16 -07:00
if (!item) {
// warning("Invalid item at tile %d:%d:%d", pos.x, pos.y, pos.z);
}
tile->addItem(item);
break;
}
default:
2023-10-09 19:12:16 -07:00
// warning("Unknown tile attribute at %d:%d:%d", pos.x, pos.y, pos.z);
break;
}
}
2023-10-09 19:12:16 -07:00
// for(BinaryNode* itemNode = node->getChild(); itemNode; itemNode->advance()) {
BinaryNode* itemNode = node->getChild();
2023-10-09 19:12:16 -07:00
if (itemNode) {
do {
uint8_t itemType;
if (!itemNode->getByte(itemType)) {
// warning("Unknown item type %d:%d:%d", pos.x, pos.y, pos.z);
delete tile;
return nullptr;
}
2023-10-09 19:12:16 -07:00
if (itemType == OTBM_ITEM) {
Item* item = Item::Create_OTBM(mapVersion, itemNode);
if (item) {
if (!item->unserializeItemNode_OTBM(mapVersion, itemNode)) {
// warning("Couldn't unserialize item attributes at %d:%d:%d", pos.x, pos.y, pos.z);
}
tile->addItem(item);
}
2023-10-09 19:12:16 -07:00
} else {
// warning("Unknown type of tile child node");
}
2023-10-09 19:12:16 -07:00
//}
} while (itemNode->advance());
}
return tile;
}
2023-10-09 19:12:16 -07:00
LiveCursor LiveSocket::readCursor(NetworkMessage &message) {
LiveCursor cursor;
cursor.id = message.read<uint32_t>();
2016-09-29 19:24:45 -03:00
uint8_t r = message.read<uint8_t>();
uint8_t g = message.read<uint8_t>();
uint8_t b = message.read<uint8_t>();
uint8_t a = message.read<uint8_t>();
cursor.color = wxColor(r, g, b, a);
cursor.pos = message.read<Position>();
return cursor;
}
2023-10-09 19:12:16 -07:00
void LiveSocket::writeCursor(NetworkMessage &message, const LiveCursor &cursor) {
message.write<uint32_t>(cursor.id);
message.write<uint8_t>(cursor.color.Red());
message.write<uint8_t>(cursor.color.Green());
message.write<uint8_t>(cursor.color.Blue());
message.write<uint8_t>(cursor.color.Alpha());
message.write<Position>(cursor.pos);
}