diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 7dd7b657708..b91216e62ad 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -43,12 +43,12 @@ jobs: uses: gittools/actions/gitversion/execute@v0.9.15 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3.7.1 with: install: true - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -73,6 +73,8 @@ jobs: tags: ghcr.io/${{ github.repository }}:${{ steps.gitversion.outputs.semVer }} cache-from: type=gha, scope=${{ github.workflow }} cache-to: type=gha, scope=${{ github.workflow }} + secrets: | + DEBUG=1 - name: Image digest if: ${{ github.event_name == 'push' }} @@ -97,7 +99,7 @@ jobs: uses: gittools/actions/gitversion/execute@v0.9.15 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3.7.1 with: install: true diff --git a/data-otservbr-global/monster/magicals/burning_book.lua b/data-otservbr-global/monster/magicals/burning_book.lua index f12bbab7a25..e9199c7e332 100644 --- a/data-otservbr-global/monster/magicals/burning_book.lua +++ b/data-otservbr-global/monster/magicals/burning_book.lua @@ -2,7 +2,7 @@ local mType = Game.createMonsterType("Burning Book") local monster = {} monster.description = "a burning book" -monster.experience = 11934 +monster.experience = 13200 monster.outfit = { lookType = 1061, lookHead = 79, diff --git a/data-otservbr-global/monster/magicals/forest_fury.lua b/data-otservbr-global/monster/magicals/forest_fury.lua index fc5a688e39f..1048a4d26b7 100644 --- a/data-otservbr-global/monster/magicals/forest_fury.lua +++ b/data-otservbr-global/monster/magicals/forest_fury.lua @@ -2,7 +2,7 @@ local mType = Game.createMonsterType("Forest Fury") local monster = {} monster.description = "a forest fury" -monster.experience = 235 +monster.experience = 330 monster.outfit = { lookType = 569, lookHead = 0, diff --git a/data-otservbr-global/monster/magicals/guardian_of_tales.lua b/data-otservbr-global/monster/magicals/guardian_of_tales.lua index 01ee4a29711..3c18f324049 100644 --- a/data-otservbr-global/monster/magicals/guardian_of_tales.lua +++ b/data-otservbr-global/monster/magicals/guardian_of_tales.lua @@ -2,7 +2,7 @@ local mType = Game.createMonsterType("Guardian of Tales") local monster = {} monster.description = "a guardian of tales" -monster.experience = 9204 +monster.experience = 10600 monster.outfit = { lookType = 1063, lookHead = 92, diff --git a/data-otservbr-global/monster/magicals/rage_squid.lua b/data-otservbr-global/monster/magicals/rage_squid.lua index 0bbd087da45..661ecbf0011 100644 --- a/data-otservbr-global/monster/magicals/rage_squid.lua +++ b/data-otservbr-global/monster/magicals/rage_squid.lua @@ -2,7 +2,7 @@ local mType = Game.createMonsterType("Rage Squid") local monster = {} monster.description = "a rage squid" -monster.experience = 14820 +monster.experience = 16300 monster.outfit = { lookType = 1059, lookHead = 94, diff --git a/data-otservbr-global/monster/plants/wilting_leaf_golem.lua b/data-otservbr-global/monster/plants/wilting_leaf_golem.lua index c9c4fd36e88..c6e8e4793ca 100644 --- a/data-otservbr-global/monster/plants/wilting_leaf_golem.lua +++ b/data-otservbr-global/monster/plants/wilting_leaf_golem.lua @@ -2,7 +2,7 @@ local mType = Game.createMonsterType("Wilting Leaf Golem") local monster = {} monster.description = "a wilting leaf golem" -monster.experience = 145 +monster.experience = 225 monster.outfit = { lookType = 573, lookHead = 0, diff --git a/data/items/appearances.dat b/data/items/appearances.dat index e26d139005d..8b9c47a9d32 100644 Binary files a/data/items/appearances.dat and b/data/items/appearances.dat differ diff --git a/data/scripts/talkactions/god/icons_functions.lua b/data/scripts/talkactions/god/icons_functions.lua index 059d7ac6ed9..b3951edb0b5 100644 --- a/data/scripts/talkactions/god/icons_functions.lua +++ b/data/scripts/talkactions/god/icons_functions.lua @@ -13,16 +13,16 @@ end function Player:sendNormalIcons(icons) local msg = NetworkMessage() msg:addByte(0xA2) - msg:addU32(icons) + msg:addU64(icons) msg:addByte(0) msg:sendToPlayer(self) end function Player:sendIconBakragore(specialIcon) local msg = NetworkMessage() - msg:addByte(0xA3) - msg:addU32(specialIcon) - msg:addByte(0) + msg:addByte(0xA2) + msg:addU64(0) + msg:addByte(specialIcon) msg:sendToPlayer(self) end diff --git a/src/core.hpp b/src/core.hpp index 6352118840f..0babca44c07 100644 --- a/src/core.hpp +++ b/src/core.hpp @@ -15,7 +15,7 @@ static constexpr auto AUTHENTICATOR_PERIOD = 30U; // SERVER_MAJOR_VERSION is the actual full version of the server, including minor and patch numbers. // This is intended for internal use to identify the exact state of the server (release) software. static constexpr auto SERVER_RELEASE_VERSION = "3.1.2"; -static constexpr auto CLIENT_VERSION = 1340; +static constexpr auto CLIENT_VERSION = 1405; #define CLIENT_VERSION_UPPER (CLIENT_VERSION / 100) #define CLIENT_VERSION_LOWER (CLIENT_VERSION % 100) diff --git a/src/server/network/connection/connection.cpp b/src/server/network/connection/connection.cpp index 76c954af41c..8a8f9b16d1a 100644 --- a/src/server/network/connection/connection.cpp +++ b/src/server/network/connection/connection.cpp @@ -15,6 +15,7 @@ #include "server/network/protocol/protocol.hpp" #include "game/scheduling/dispatcher.hpp" #include "server/network/message/networkmessage.hpp" +#include "server/network/protocol/protocolgame.hpp" #include "server/server.hpp" #include "utils/tools.hpp" @@ -105,7 +106,7 @@ void Connection::closeSocket() { void Connection::accept(Protocol_ptr protocolPtr) { connectionState = CONNECTION_STATE_IDENTIFYING; protocol = std::move(protocolPtr); - g_dispatcher().addEvent([protocol = protocol] { protocol->onConnect(); }, __FUNCTION__, std::chrono::milliseconds(CONNECTION_WRITE_TIMEOUT * 1000).count()); + g_dispatcher().addEvent([eventProtocol = protocol] { eventProtocol->sendLoginChallenge(); }, __FUNCTION__, std::chrono::milliseconds(CONNECTION_WRITE_TIMEOUT * 1000).count()); acceptInternal(false); } @@ -134,7 +135,7 @@ void Connection::parseProxyIdentification(const std::error_code &error) { if (error || connectionState == CONNECTION_STATE_CLOSED) { if (error != asio::error::operation_aborted && error != asio::error::eof && error != asio::error::connection_reset) { - g_logger().error("[Connection::parseProxyIdentification] - Read error: {}", error.message()); + g_logger().debug("[Connection::parseProxyIdentification] - Read error: {}", error.message()); } close(FORCE_CLOSE); return; @@ -209,6 +210,10 @@ void Connection::parseHeader(const std::error_code &error) { } uint16_t size = m_msg.getLengthHeader(); + if (std::dynamic_pointer_cast(protocol)) { + size = (size * 8) + 4; + } + if (size == 0 || size > INPUTMESSAGE_MAXSIZE) { close(FORCE_CLOSE); return; @@ -234,7 +239,7 @@ void Connection::parsePacket(const std::error_code &error) { if (error || connectionState == CONNECTION_STATE_CLOSED) { if (error) { - g_logger().error("[Connection::parsePacket] - Read error: {}", error.message()); + g_logger().debug("[Connection::parsePacket] - Read error: {}", error.message()); } close(FORCE_CLOSE); return; @@ -272,7 +277,7 @@ void Connection::parsePacket(const std::error_code &error) { // it doesn't generate any problem because olders protocol don't use 'server sends first' feature m_msg.get(); // Skip protocol ID - m_msg.skipBytes(1); + m_msg.skipBytes(2); } protocol->onRecvFirstMessage(m_msg); diff --git a/src/server/network/connection/connection.hpp b/src/server/network/connection/connection.hpp index 139bfc73024..5a1b94544d1 100644 --- a/src/server/network/connection/connection.hpp +++ b/src/server/network/connection/connection.hpp @@ -18,6 +18,8 @@ static constexpr int32_t CONNECTION_READ_TIMEOUT = 30; class Protocol; using Protocol_ptr = std::shared_ptr; +class ProtocolGame; +using ProtocolGame_ptr = std::shared_ptr; class OutputMessage; using OutputMessage_ptr = std::shared_ptr; class Connection; diff --git a/src/server/network/message/networkmessage.hpp b/src/server/network/message/networkmessage.hpp index f738de8506b..c1295c6aad2 100644 --- a/src/server/network/message/networkmessage.hpp +++ b/src/server/network/message/networkmessage.hpp @@ -24,8 +24,8 @@ class NetworkMessage { // Headers: // 2 bytes for unencrypted message size // 4 bytes for checksum - // 2 bytes for encrypted message size - static constexpr MsgSize_t INITIAL_BUFFER_POSITION = 8; + // 1 byte for padding message size + static constexpr MsgSize_t INITIAL_BUFFER_POSITION = 7; int32_t decodeHeader(); diff --git a/src/server/network/message/outputmessage.hpp b/src/server/network/message/outputmessage.hpp index 291ceb335ef..a94e35f3e87 100644 --- a/src/server/network/message/outputmessage.hpp +++ b/src/server/network/message/outputmessage.hpp @@ -26,8 +26,14 @@ class OutputMessage : public NetworkMessage { return buffer.data() + outputBufferStart; } + void writePaddingAmount() { + uint8_t paddingAmount = 8 - (info.length % 8) - 1; + addPaddingBytes(paddingAmount); + add_header(paddingAmount); + } + void writeMessageLength() { - add_header(info.length); + add_header(static_cast((info.length - 4) / 8)); } void addCryptoHeader(bool addChecksum, uint32_t checksum) { diff --git a/src/server/network/protocol/protocol.cpp b/src/server/network/protocol/protocol.cpp index 61eda412147..8088f159b10 100644 --- a/src/server/network/protocol/protocol.cpp +++ b/src/server/network/protocol/protocol.cpp @@ -23,12 +23,13 @@ void Protocol::onSendMessage(const OutputMessage_ptr &msg) { if (!rawMessages) { const uint32_t sendMessageChecksum = msg->getLength() >= 128 && compression(*msg) ? (1U << 31) : 0; - msg->writeMessageLength(); - if (!encryptionEnabled) { + msg->writeMessageLength(); return; } + msg->writePaddingAmount(); + XTEA_encrypt(*msg); if (checksumMethod == CHECKSUM_METHOD_NONE) { msg->addCryptoHeader(false, 0); @@ -209,12 +210,12 @@ bool Protocol::XTEA_decrypt(NetworkMessage &msg) const { XTEA_transform(buffer, messageLength, false); - uint16_t innerLength = msg.get(); - if (std::cmp_greater(innerLength, msgLength - 2)) { + uint8_t paddingSize = msg.getByte(); + if (std::cmp_greater(paddingSize, msgLength - 1)) { return false; } - msg.setLength(innerLength); + msg.setLength(messageLength - paddingSize); return true; } diff --git a/src/server/network/protocol/protocol.hpp b/src/server/network/protocol/protocol.hpp index 172c9afba32..11db15ffcb9 100644 --- a/src/server/network/protocol/protocol.hpp +++ b/src/server/network/protocol/protocol.hpp @@ -35,7 +35,7 @@ class Protocol : public std::enable_shared_from_this { bool onRecvMessage(NetworkMessage &msg); bool sendRecvMessageCallback(NetworkMessage &msg); virtual void onRecvFirstMessage(NetworkMessage &msg) = 0; - virtual void onConnect() { } + virtual void sendLoginChallenge() { } bool isConnectionExpired() const; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 9c09f5ead38..acc61715763 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -863,7 +863,7 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage &msg) { g_dispatcher().addEvent([self = getThis(), characterName, accountId, operatingSystem] { self->login(characterName, accountId, operatingSystem); }, __FUNCTION__); } -void ProtocolGame::onConnect() { +void ProtocolGame::sendLoginChallenge() { auto output = OutputMessagePool::getOutputMessage(); static std::random_device rd; static std::ranlux24 generator(rd()); @@ -873,15 +873,15 @@ void ProtocolGame::onConnect() { output->skipBytes(sizeof(uint32_t)); // Packet length & type - output->add(0x0006); + output->addByte(0x01); output->addByte(0x1F); - // Add timestamp & random number challengeTimestamp = static_cast(time(nullptr)); output->add(challengeTimestamp); challengeRandom = randNumber(generator); output->addByte(challengeRandom); + output->addByte(0x71); // Go back and write checksum output->skipBytes(-12); @@ -1612,7 +1612,7 @@ void ProtocolGame::parseOpenPrivateChannel(NetworkMessage &msg) { void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { uint8_t numdirs = msg.getByte(); - if (numdirs == 0 || (msg.getBufferPosition() + numdirs) != (msg.getLength() + 8)) { + if (numdirs == 0 || (msg.getBufferPosition() + numdirs) != (msg.getLength() + 6)) { return; } @@ -4646,8 +4646,8 @@ void ProtocolGame::sendIcons(const std::unordered_set &iconSet, cons // Send as uint16_t in old protocol msg.add(static_cast(icons)); } else { - // Send as uint32_t in new protocol - msg.add(icons); + // Send as uint64_t in new protocol + msg.add(icons); msg.addByte(enumToValue(iconBakragore)); // Icons Bakragore } @@ -4657,7 +4657,7 @@ void ProtocolGame::sendIcons(const std::unordered_set &iconSet, cons void ProtocolGame::sendIconBakragore(const IconBakragore icon) { NetworkMessage msg; msg.addByte(0xA2); - msg.add(0); // Send empty normal icons + msg.add(0); // Send empty normal icons msg.addByte(enumToValue(icon)); writeToOutputBuffer(msg); } @@ -8582,7 +8582,6 @@ void ProtocolGame::sendOpenStash() { msg.add(item.first); msg.add(item.second); } - msg.add(static_cast(g_configManager().getNumber(STASH_ITEMS) - getStashSize(list))); writeToOutputBuffer(msg); } diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 2048bea7c16..de1495d60cb 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -129,7 +129,7 @@ class ProtocolGame final : public Protocol { void parsePacket(NetworkMessage &msg) override; void parsePacketFromDispatcher(NetworkMessage &msg, uint8_t recvbyte); void onRecvFirstMessage(NetworkMessage &msg) override; - void onConnect() override; + void sendLoginChallenge() override; // Parse methods void parseAutoWalk(NetworkMessage &msg);