mirror of
https://github.com/opentibiabr/canary
synced 2026-08-16 06:26:09 -04:00
Update current client protocol compatibility to 15.25 byte contract This commit updates the current client runtime profile to match the Tibia 15.25 byte contract and keeps the changes behind explicit runtime protocol feature flags. The goal is to make the current client able to log in and keep running without message boundary debug errors while preserving the existing multiprotocol structure. This is a compatibility update focused on sending and consuming the bytes expected by the current client. It does not implement the full gameplay systems behind the new official windows dialogs rewards shops progression or balance features. The current profile now enables versioned payload flags for the confirmed 15.25 differences. These flags gate the new packet shapes so the modern client can receive the expected payloads while older profiles do not automatically inherit incompatible message layouts. The update also adds minimal byte compatible shims for new current client module windows and side dialogs. Taskboard and Soul Seals now have official client packet shims that respond with structurally valid empty windows where the gameplay system is not fully implemented yet. This keeps the client protocol stable without pretending that the complete feature set exists server side. Several current client payloads were aligned with the 15.25 format. This includes resource balances graphical effects vocation specific data skill wheel weapon proficiency game events quest related payloads store summary parsing and related request parsers. Main changes included in this commit • Updates the current client runtime profile to the 15.25 byte contract • Adds runtime feature flags for confirmed current client payload differences • Gates 15.25 specific packet layouts behind explicit ProtocolFeature flags • Adds support for official skill wheel payload differences • Adds support for official weapon proficiency payload differences • Adds support for graphical effect source byte differences • Adds support for official vocation specific player data • Adds support for official Taskboard packet family handling • Adds support for official Soul Seals packet family handling • Adds minimal byte compatible Taskboard shims for the current client • Adds minimal byte compatible Soul Seals shims for the current client • Adds explicit parsers for several previously unhandled current client opcodes • Aligns resource balance request parsing with the current client payload • Aligns graphical effect payloads with the current client format • Aligns vocation specific data payloads with the current client format • Aligns skill wheel payloads including quest bonus and gem list layout • Aligns weapon proficiency payloads including detail list support • Aligns game event payloads and related request handling • Expands GameStore parsing for offer descriptions and events • Adds stricter packet parsing and trailing byte handling where needed • Improves protocol aware login logging with richer asset signature details • Adds a god level protocol probe command for live protocol and message testing • Documents the 15.25 compatibility scope and versioned payload flags Protocol profile changes The current profile mask now includes the new protocol feature flags required by the 15.25 byte contract. These flags allow the server to describe exactly which current client payloads are active instead of tying every behavior only to a raw client version number. This keeps the compatibility layer safer for multiprotocol support because older profiles can continue using their own packet shapes while the current profile enables the official 15.25 payload differences. Module shim changes Taskboard support was added as a minimal official client shim. The server consumes the expected current client packet shape and returns structurally valid empty Taskboard windows. This keeps the client UI protocol satisfied while leaving the full Taskboard gameplay implementation for future work. Soul Seals support was also added as a minimal official client shim. The server reads the expected request data validates the packet shape and responds with a structurally valid empty placeholder response. This prevents message boundary issues for the current client without implementing the complete Soul Seals system yet. Payload compatibility changes The current client expects several packet layouts that differ from older protocol profiles. This commit updates the server to match those confirmed layouts for the active current profile. The affected areas include skill wheel payloads weapon proficiency details vocation specific player data resource balance requests graphical effects game events store parsing quest related payloads and related packet parsers. These changes are focused on byte compatibility. They make the packet boundaries and payload shapes stable so the current client can operate without protocol debug breaks. Bug fixes and robustness improvements This commit also includes several protocol adjacent fixes found during the compatibility work. Packet parsing was made stricter in selected paths. Quest tracker validation and logging were updated. Store parser state handling was improved by avoiding shared global mutation for the default entries per page value. The update also fixes precision and argument handling issues in related current client payload paths including level percent casting and forge skill stat argument placement. Protocol probe tooling A god only protocol probe command was added for live protocol testing. This gives maintainers a way to test selected protocol and message flows in game while keeping the command restricted to god group access. The probe tool includes built in probes and file driven local probes, making it useful for reproducing current client packet behavior without exposing the tool to normal players. Documentation changes The systems documentation was updated with the 15.25 compatibility scope and multiprotocol feature notes. The documentation explains that this PR is a byte compatibility update and not a full gameplay implementation for every new current client window or system. It also documents the versioned payload flags so future protocol updates can continue using explicit feature gated packet differences instead of mixing incompatible layouts into shared paths. Validation performed • Tested current client login locally • Tested key current client UI surfaces locally while fixing reported client debug cases • Confirmed fixes for skill wheel payload boundaries • Confirmed fixes for character stats payload boundaries • Confirmed fixes for store summary payload boundaries • Confirmed fixes for defense stats payload boundaries • Confirmed fixes for game event payload boundaries • Confirmed fixes for graphical effect payload boundaries • Confirmed fixes for related current client request parsers • Full compile and build validation was not run Known scope limitation This commit intentionally does not implement the full gameplay systems behind the new current client windows dialogs rewards shops progression systems or balance features. The purpose is to stabilize the message shape first. Full gameplay behavior can be implemented later on top of the now compatible packet structure. Overall this commit brings the current client protocol path in line with the Tibia 15.25 byte contract. It adds explicit feature gated compatibility for confirmed payload differences introduces minimal shims for new official client windows improves parser coverage and documents the compatibility boundary while preserving the existing multiprotocol architecture.
221 lines
5.6 KiB
Lua
221 lines
5.6 KiB
Lua
local ClientPackets = {
|
|
Taskboard = 0x5F,
|
|
}
|
|
|
|
local ServerPackets = {
|
|
Taskboard = 0x5B,
|
|
}
|
|
|
|
local OutboundWindow = {
|
|
Bounty = 0x00,
|
|
Weekly = 0x01,
|
|
Shop = 0x02,
|
|
}
|
|
|
|
local ClientAction = {
|
|
Bounty = 0x00,
|
|
Weekly = 0x01,
|
|
BountyDifficulty = 0x02,
|
|
BountyReroll = 0x03,
|
|
ClaimDailyReroll = 0x04,
|
|
BountySelect = 0x05,
|
|
BountyClaimReward = 0x06,
|
|
TalismanUpgrade = 0x07,
|
|
WeeklyDelivery = 0x08,
|
|
WeeklyDifficulty = 0x09,
|
|
Shop = 0x0A,
|
|
ShopBuy = 0x0B,
|
|
UnlockPreferenceSlot = 0x0C,
|
|
ClearPreferred = 0x0D,
|
|
ClearUnwanted = 0x0E,
|
|
AssignPreferred = 0x0F,
|
|
AssignUnwanted = 0x10,
|
|
}
|
|
|
|
local OneBytePayloadActions = {
|
|
[ClientAction.BountyDifficulty] = true,
|
|
[ClientAction.BountySelect] = true,
|
|
[ClientAction.TalismanUpgrade] = true,
|
|
[ClientAction.WeeklyDelivery] = true,
|
|
[ClientAction.WeeklyDifficulty] = true,
|
|
}
|
|
|
|
local OneU16PayloadActions = {
|
|
[ClientAction.ShopBuy] = true,
|
|
[ClientAction.UnlockPreferenceSlot] = true,
|
|
[ClientAction.ClearPreferred] = true,
|
|
[ClientAction.ClearUnwanted] = true,
|
|
}
|
|
|
|
local TwoU16PayloadActions = {
|
|
[ClientAction.AssignPreferred] = true,
|
|
[ClientAction.AssignUnwanted] = true,
|
|
}
|
|
|
|
local BountyResponseActions = {
|
|
[ClientAction.Bounty] = true,
|
|
[ClientAction.BountyDifficulty] = true,
|
|
[ClientAction.BountyReroll] = true,
|
|
[ClientAction.ClaimDailyReroll] = true,
|
|
[ClientAction.BountySelect] = true,
|
|
[ClientAction.BountyClaimReward] = true,
|
|
[ClientAction.TalismanUpgrade] = true,
|
|
[ClientAction.UnlockPreferenceSlot] = true,
|
|
[ClientAction.ClearPreferred] = true,
|
|
[ClientAction.ClearUnwanted] = true,
|
|
[ClientAction.AssignPreferred] = true,
|
|
[ClientAction.AssignUnwanted] = true,
|
|
}
|
|
|
|
local WeeklyResponseActions = {
|
|
[ClientAction.Weekly] = true,
|
|
[ClientAction.WeeklyDelivery] = true,
|
|
[ClientAction.WeeklyDifficulty] = true,
|
|
}
|
|
|
|
local ShopResponseActions = {
|
|
[ClientAction.Shop] = true,
|
|
[ClientAction.ShopBuy] = true,
|
|
}
|
|
|
|
-- Official-client packet shim for 15.25 Taskboard traffic.
|
|
-- This intentionally sends empty but structurally valid 0x5B windows. Full
|
|
-- task state, rewards, shop contents and Soulpit behavior should be added on
|
|
-- top of these byte writers instead of changing the packet contract.
|
|
|
|
local function readU8(msg)
|
|
if msg:getUnreadBytes() < 1 then
|
|
return nil
|
|
end
|
|
|
|
return msg:getByte()
|
|
end
|
|
|
|
local function readU16(msg)
|
|
if msg:getUnreadBytes() < 2 then
|
|
return nil
|
|
end
|
|
|
|
return msg:getU16()
|
|
end
|
|
|
|
local function consumeU8(msg)
|
|
return readU8(msg) ~= nil
|
|
end
|
|
|
|
local function consumeU16(msg)
|
|
return readU16(msg) ~= nil
|
|
end
|
|
|
|
local function addEmptyBountyTalismanLine(msg)
|
|
msg:addU16(0)
|
|
msg:addByte(0)
|
|
msg:addU16(0)
|
|
end
|
|
|
|
local function sendBountyWindow(player)
|
|
local msg = NetworkMessage()
|
|
msg:addByte(ServerPackets.Taskboard)
|
|
msg:addByte(OutboundWindow.Bounty)
|
|
msg:addByte(0) -- bounty task count
|
|
msg:addByte(0) -- daily rerolls
|
|
msg:addByte(0) -- reroll state
|
|
msg:addByte(0) -- current difficulty
|
|
addEmptyBountyTalismanLine(msg)
|
|
addEmptyBountyTalismanLine(msg)
|
|
addEmptyBountyTalismanLine(msg)
|
|
addEmptyBountyTalismanLine(msg)
|
|
msg:addByte(0) -- preferred/unwanted slot count
|
|
msg:sendToPlayer(player)
|
|
end
|
|
|
|
local function sendWeeklyWindow(player)
|
|
local msg = NetworkMessage()
|
|
msg:addByte(ServerPackets.Taskboard)
|
|
msg:addByte(OutboundWindow.Weekly)
|
|
msg:addU16(0) -- any creature required amount
|
|
msg:addU16(0) -- any creature current amount
|
|
msg:addByte(0) -- weekly kill task count
|
|
msg:addByte(0) -- weekly item task count
|
|
msg:addByte(0) -- current difficulty
|
|
msg:addU32(0) -- kill experience reward
|
|
msg:addU32(0) -- item delivery experience reward
|
|
msg:addByte(0) -- completed kill tasks
|
|
msg:addByte(0) -- completed item tasks
|
|
msg:addByte(0) -- difficulty selection available
|
|
msg:addByte(0) -- suggested difficulty
|
|
msg:addU32(0) -- next reset timestamp
|
|
msg:addByte(0) -- third weekly slot unlocked
|
|
msg:addU32(0) -- task hunting points reward
|
|
msg:addU32(0) -- soulseals reward tail for current official clients
|
|
msg:sendToPlayer(player)
|
|
end
|
|
|
|
local function sendShopWindow(player)
|
|
local msg = NetworkMessage()
|
|
msg:addByte(ServerPackets.Taskboard)
|
|
msg:addByte(OutboundWindow.Shop)
|
|
msg:addByte(0) -- offer count
|
|
msg:sendToPlayer(player)
|
|
end
|
|
|
|
local function sendWindow(player, window)
|
|
if window == OutboundWindow.Weekly then
|
|
sendWeeklyWindow(player)
|
|
elseif window == OutboundWindow.Shop then
|
|
sendShopWindow(player)
|
|
else
|
|
sendBountyWindow(player)
|
|
end
|
|
end
|
|
|
|
local function consumeActionPayload(msg, action)
|
|
if OneBytePayloadActions[action] then
|
|
return consumeU8(msg)
|
|
end
|
|
|
|
if OneU16PayloadActions[action] then
|
|
return consumeU16(msg)
|
|
end
|
|
|
|
if TwoU16PayloadActions[action] then
|
|
return consumeU16(msg) and consumeU16(msg)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function onRecvbyte(player, msg, byte)
|
|
if byte ~= ClientPackets.Taskboard then
|
|
return
|
|
end
|
|
|
|
local action = readU8(msg)
|
|
if not action then
|
|
logger.debug("[Taskboard] ignored malformed 0x5F packet from player='{}': missing action", player:getName())
|
|
return
|
|
end
|
|
|
|
if not consumeActionPayload(msg, action) then
|
|
logger.debug("[Taskboard] ignored malformed 0x5F packet from player='{}': incomplete action {}", player:getName(), action)
|
|
return
|
|
end
|
|
|
|
local trailingBytes = msg:getUnreadBytes()
|
|
if trailingBytes > 0 then
|
|
logger.debug("[Taskboard] ignored malformed 0x5F packet from player='{}': action={} unexpected trailing bytes={}", player:getName(), action, trailingBytes)
|
|
return
|
|
end
|
|
|
|
if BountyResponseActions[action] then
|
|
sendWindow(player, OutboundWindow.Bounty)
|
|
elseif WeeklyResponseActions[action] then
|
|
sendWindow(player, OutboundWindow.Weekly)
|
|
elseif ShopResponseActions[action] then
|
|
sendWindow(player, OutboundWindow.Shop)
|
|
else
|
|
sendWindow(player, OutboundWindow.Bounty)
|
|
end
|
|
|
|
logger.debug("[Taskboard] player='{}' action={} handled by minimal official packet shim.", player:getName(), action)
|
|
end
|