mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
The client sends SetLastCustomBuild (890, a u32-length wide string; other references) with its rocket build, e.g. "1:14454;1:4714;1:4715;", when it assembles the rocket the player carries: after EquipInventory at a launchpad and on load when landing (202 live packets). It stores it as lastUsedRocketInfo (LWOCharacterComponent::SendMessage 0x00d34330) and reads it back from char@lcbp on load (0x00ca4910). Live saved lcbp in the same format on every character. DLU dropped the message and only set lcbp when the server equipped the rocket. The handler now keeps the client's build as the rocket config (saved as lcbp). It does not change whether the player lands on the next load: DLU uses an empty config to skip the landing after non-rocket transfers, and that still happens when the server clears it. Check in game: build a new rocket in the rocket builder, launch from a launchpad and land: the rocket shown on landing and the builder's default next time are the new build. Teleport to another world without a rocket (e.g. from a property): no landing animation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
3.5 KiB
C++
85 lines
3.5 KiB
C++
// Client -> server game messages DLU used to drop (docs/CaptureUnknowns.md section 4). Packets are from 2011/2012
|
|
// live captures with the object ID replaced.
|
|
#include "GameDependencies.h"
|
|
#include "GameMessageTestUtils.h"
|
|
|
|
#include "CharacterComponent.h"
|
|
#include "Entity.h"
|
|
#include "PlayerMessages.h"
|
|
|
|
#include <memory>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
using namespace GameMessageTestUtils;
|
|
|
|
namespace {
|
|
// A synthetic player object ID, as the object ID of the live packets below
|
|
constexpr const char* PLAYER_HEADER = "53040005000000000100000000000010";
|
|
}
|
|
|
|
class ClientMessagesTests : public GameDependenciesTest {
|
|
protected:
|
|
std::unique_ptr<Entity> player;
|
|
std::unique_ptr<Character> character;
|
|
|
|
void SetUp() override {
|
|
SetUpDependencies();
|
|
player = std::make_unique<Entity>(0x1000000000000001LL, info);
|
|
character = std::make_unique<Character>(1, nullptr);
|
|
player->AddComponent<CharacterComponent>(-1, character.get(), UNASSIGNED_SYSTEM_ADDRESS);
|
|
}
|
|
|
|
void TearDown() override {
|
|
player.reset();
|
|
character.reset();
|
|
TearDownDependencies();
|
|
}
|
|
};
|
|
|
|
// SetTooltipFlag (469): bFlag, then the tooltip. Both live samples flagged tooltip 24; live saved ttip="16777216".
|
|
TEST_F(ClientMessagesTests, SetTooltipFlagMatchesLiveCapture) {
|
|
auto msg = FromLiveClientCapture<GameMessages::SetTooltipFlag>(std::string(PLAYER_HEADER) + "d501" + "8c00000000");
|
|
EXPECT_TRUE(msg.bFlag);
|
|
EXPECT_EQ(msg.iToolTip, 24);
|
|
EXPECT_EQ(RoundTrip(msg).iToolTip, 24);
|
|
ExpectTruncatedFails(msg);
|
|
|
|
auto* const characterComponent = player->GetComponent<CharacterComponent>();
|
|
msg.Handle(*player, UNASSIGNED_SYSTEM_ADDRESS);
|
|
EXPECT_EQ(characterComponent->GetTooltipFlags(), 16777216u);
|
|
}
|
|
|
|
// The client's bit operations: set shifts 1 by the tooltip; clear masks with ~1 shifted by the tooltip (clearing
|
|
// every lower bit too); shifts of 64 or more give 0; tooltips above 127 are ignored.
|
|
TEST_F(ClientMessagesTests, SetTooltipFlagFollowsTheClient) {
|
|
auto* const characterComponent = player->GetComponent<CharacterComponent>();
|
|
characterComponent->SetTooltipFlag(0, true);
|
|
characterComponent->SetTooltipFlag(3, true);
|
|
characterComponent->SetTooltipFlag(63, true);
|
|
EXPECT_EQ(characterComponent->GetTooltipFlags(), 0x8000000000000009ULL);
|
|
characterComponent->SetTooltipFlag(64, true);
|
|
EXPECT_EQ(characterComponent->GetTooltipFlags(), 0x8000000000000009ULL);
|
|
characterComponent->SetTooltipFlag(128, false);
|
|
EXPECT_EQ(characterComponent->GetTooltipFlags(), 0x8000000000000009ULL);
|
|
characterComponent->SetTooltipFlag(3, false);
|
|
EXPECT_EQ(characterComponent->GetTooltipFlags(), 0x8000000000000000ULL);
|
|
characterComponent->SetTooltipFlag(100, false);
|
|
EXPECT_EQ(characterComponent->GetTooltipFlags(), 0u);
|
|
}
|
|
|
|
// SetLastCustomBuild (890): a u32-length wide string. 202 live packets, sent when the carried rocket is assembled.
|
|
TEST_F(ClientMessagesTests, SetLastCustomBuildMatchesLiveCapture) {
|
|
auto msg = FromLiveClientCapture<GameMessages::SetLastCustomBuild>(std::string(PLAYER_HEADER) + "7a03" +
|
|
"1600000031003a00310034003400350034003b0031003a0034003700310034003b0031003a0034003700310035003b00");
|
|
EXPECT_EQ(msg.tokenizedLOTList, u"1:14454;1:4714;1:4715;");
|
|
EXPECT_EQ(RoundTrip(msg).tokenizedLOTList, msg.tokenizedLOTList);
|
|
ExpectTruncatedFails(msg);
|
|
|
|
// Kept as the rocket config (saved as char@lcbp) without turning on the landing
|
|
auto* const characterComponent = player->GetComponent<CharacterComponent>();
|
|
msg.Handle(*player, UNASSIGNED_SYSTEM_ADDRESS);
|
|
EXPECT_EQ(characterComponent->GetLastRocketConfig(), u"1:14454;1:4714;1:4715;");
|
|
EXPECT_FALSE(characterComponent->GetIsLanding());
|
|
}
|