mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 19:03:43 +00:00
fix(wire): write SetStatusImmunity flags in the client's order
WIRE FIX. The 1.10.64 client writes and reads the immunity flags in alphabetical order after the u32 state (GameMessage::SetStatusImmunity:: Serialize @ 0x00d8f140; the field offsets are named by the Flash export at 0x00d8f410): BasicAttack, DOT, ImaginationGain, ImaginationLoss, Interrupt, Knockback, PullToPoint, QuickbuildInterrupt, Speed. DLU wrote them in declaration order, so e.g. a knockback immunity reached the client as an imagination-gain immunity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -273,29 +273,30 @@ namespace GameMessages {
|
||||
}
|
||||
|
||||
void SetStatusImmunity::Serialize(RakNet::BitStream& bitStream) const {
|
||||
// The client's order (0x00d8f140): alphabetical.
|
||||
bitStream.Write(StateChangeType);
|
||||
bitStream.Write(bImmuneToBasicAttack);
|
||||
bitStream.Write(bImmuneToDOT);
|
||||
bitStream.Write(bImmuneToKnockback);
|
||||
bitStream.Write(bImmuneToInterrupt);
|
||||
bitStream.Write(bImmuneToSpeed);
|
||||
bitStream.Write(bImmuneToImaginationGain);
|
||||
bitStream.Write(bImmuneToImaginationLoss);
|
||||
bitStream.Write(bImmuneToQuickbuildInterrupt);
|
||||
bitStream.Write(bImmuneToInterrupt);
|
||||
bitStream.Write(bImmuneToKnockback);
|
||||
bitStream.Write(bImmuneToPullToPoint);
|
||||
bitStream.Write(bImmuneToQuickbuildInterrupt);
|
||||
bitStream.Write(bImmuneToSpeed);
|
||||
}
|
||||
|
||||
bool SetStatusImmunity::Deserialize(RakNet::BitStream& bitStream) {
|
||||
VALIDATE_READ(bitStream.Read(StateChangeType));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToBasicAttack));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToDOT));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToKnockback));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToInterrupt));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToSpeed));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToImaginationGain));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToImaginationLoss));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToQuickbuildInterrupt));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToInterrupt));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToKnockback));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToPullToPoint));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToQuickbuildInterrupt));
|
||||
VALIDATE_READ(bitStream.Read(bImmuneToSpeed));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -173,8 +173,9 @@ namespace GameMessages {
|
||||
};
|
||||
|
||||
// Server -> client.
|
||||
// NOTE: DLU writes the flags in this order; the client reads them in alphabetical order
|
||||
// (GameMessage::SetStatusImmunity::Serialize @ 00d8f140 in 1.10.64). Kept as DLU sent it in this conversion.
|
||||
// WIRE FIX: the flags go on the wire in alphabetical order, as the client's Serialize writes them
|
||||
// (GameMessage::SetStatusImmunity::Serialize @ 00d8f140 in 1.10.64; field offsets named by its Flash export
|
||||
// @ 00d8f410). DLU used to write them in the declaration order below.
|
||||
struct SetStatusImmunity : public NetGameMsg {
|
||||
SetStatusImmunity() : NetGameMsg(MessageType::Game::SET_STATUS_IMMUNITY) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
|
||||
@@ -312,7 +312,7 @@ the 1.10.64 client.
|
||||
| `NotifyNotEnoughInvSpace` | Fixed (wire fix): used to be sent with message ID `VEHICLE_NOTIFY_FINISHED_RACE` (1396). | Its ID is `NOTIFY_NOT_ENOUGH_INV_SPACE` (1516, `0x00545c90`); payload read at `0x00d8b850`. |
|
||||
| `MoveInventoryBatch` | Now follows the client layout. | |
|
||||
| `UnEquipInventory` | The trailing optional `replacementObjectID` is never read. | The client can send it. |
|
||||
| `SetStatusImmunity` | Writes the flags in DLU's order. | The client reads DOT, ImaginationGain, ImaginationLoss, Interrupt, Knockback, PullToPoint, QuickbuildInterrupt, Speed, BasicAttack (`0x00d8f140`). |
|
||||
| `SetStatusImmunity` | Fixed (wire fix): used to write the flags in DLU's order (BasicAttack, DOT, Knockback, Interrupt, Speed, ImaginationGain, ImaginationLoss, QuickbuildInterrupt, PullToPoint). | The client uses alphabetical order: BasicAttack, DOT, ImaginationGain, ImaginationLoss, Interrupt, Knockback, PullToPoint, QuickbuildInterrupt, Speed (`0x00d8f140`; field offsets named by `0x00d8f410`). |
|
||||
| `RequestDie` | Read with the `Die` layout. | Starts with one `bDieAccepted` bit and has a mandatory `lootOwnerID` (`0x00e02d90`). |
|
||||
| `SetCurrency` | `sourceTradeID` is an optional `int32_t`. | lu_packets has an object ID (8 bytes). DLU only ever sends 0 (flag bit 0), so no bytes differ today. |
|
||||
| `FireEventClientSide` | Never writes `param1`/`param2` (both flag bits 0), whatever the caller passed: `RocketEquipped` loses the clone ID. | Optional `i64 param1` (default 0) and `i32 param2` (default -1). |
|
||||
|
||||
@@ -264,9 +264,7 @@ TEST_F(CombatMessagesTests, StunsAndImmunitiesMatchLegacy) {
|
||||
status.bImmuneToImaginationLoss = Bit(mask, 6);
|
||||
status.bImmuneToQuickbuildInterrupt = Bit(mask, 7);
|
||||
status.bImmuneToPullToPoint = Bit(mask, 8);
|
||||
ExpectSameAsLegacy([&](const SystemAddress& a) {
|
||||
LegacyGameMessages::SendSetStatusImmunity(target, state, a, Bit(mask, 0), Bit(mask, 1), Bit(mask, 2), Bit(mask, 3), Bit(mask, 4), Bit(mask, 5), Bit(mask, 6), Bit(mask, 7), Bit(mask, 8));
|
||||
}, status);
|
||||
// WIRE FIX: the legacy bytes use DLU's flag order; see SetStatusImmunityUsesClientOrder.
|
||||
EXPECT_EQ(RoundTrip(status).bImmuneToPullToPoint, Bit(mask, 8));
|
||||
}
|
||||
}
|
||||
@@ -379,3 +377,36 @@ TEST_F(CombatMessagesTests, GoldenBytes) {
|
||||
remove.uiBuffID = 3;
|
||||
EXPECT_PACKET_EQ(FromHex("20 60 00 00 00", 35), Payload(remove));
|
||||
}
|
||||
|
||||
// WIRE FIX: the client writes and reads the immunity flags in alphabetical order after the u32 state
|
||||
// (GameMessage::SetStatusImmunity::Serialize @ 0x00d8f140). Setting one flag at a time must set exactly that bit.
|
||||
TEST_F(CombatMessagesTests, SetStatusImmunityUsesClientOrder) {
|
||||
using Flag = bool GameMessages::SetStatusImmunity::*;
|
||||
const std::array<Flag, 9> clientOrder = {
|
||||
&GameMessages::SetStatusImmunity::bImmuneToBasicAttack,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToDOT,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToImaginationGain,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToImaginationLoss,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToInterrupt,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToKnockback,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToPullToPoint,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToQuickbuildInterrupt,
|
||||
&GameMessages::SetStatusImmunity::bImmuneToSpeed,
|
||||
};
|
||||
for (size_t i = 0; i < clientOrder.size(); i++) {
|
||||
GameMessages::SetStatusImmunity msg;
|
||||
msg.StateChangeType = eStateChangeType::POP;
|
||||
msg.*clientOrder[i] = true;
|
||||
RakNet::BitStream bitStream;
|
||||
msg.Serialize(bitStream);
|
||||
ASSERT_EQ(bitStream.GetNumberOfBitsUsed(), 32 + 9);
|
||||
uint32_t state{};
|
||||
ASSERT_TRUE(bitStream.Read(state));
|
||||
EXPECT_EQ(state, 1u);
|
||||
for (size_t bit = 0; bit < clientOrder.size(); bit++) {
|
||||
bool value{};
|
||||
ASSERT_TRUE(bitStream.Read(value));
|
||||
EXPECT_EQ(value, bit == i) << "flag " << i << ", bit " << bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user