mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
feat(load): PlayerReady also goes to the zone control object
Live answered PlayerLoaded with PlayerReady to the player and then a second PlayerReady to the zone control object (0x3FFFFFFFFFFE), both to the loading client: 235 of 237 captured loads carry exactly that pair. DLU sent only the first. The zone control object's client-side zone scripts are what can react to it (inferred: the client's component handlers only act on the player's own PlayerReady). Check: load into Avant Gardens, Nimbus Station, a property and an instance (a survival or dragon battle): the zone plays its intro, music and UI as before and nothing is stuck waiting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,11 +35,19 @@ namespace GameMessages {
|
||||
return bitStream.Read(playerID);
|
||||
}
|
||||
|
||||
void SendPlayerReady(const LWOOBJID player, const LWOOBJID zoneControl, const SystemAddress& sysAddr) {
|
||||
PlayerReady playerReady;
|
||||
playerReady.target = player;
|
||||
playerReady.SendToClient(sysAddr);
|
||||
if (zoneControl == LWOOBJID_EMPTY) return;
|
||||
playerReady.target = zoneControl;
|
||||
playerReady.SendToClient(sysAddr);
|
||||
}
|
||||
|
||||
void PlayerLoaded::Handle(Entity& entityRef, const SystemAddress& sysAddr) {
|
||||
auto* entity = &entityRef;
|
||||
PlayerReady playerReady;
|
||||
playerReady.target = entity->GetObjectID();
|
||||
playerReady.SendToClient(sysAddr);
|
||||
const auto* const zoneControlEntity = Game::entityManager->GetZoneControlEntity();
|
||||
SendPlayerReady(entity->GetObjectID(), zoneControlEntity ? zoneControlEntity->GetObjectID() : LWOOBJID_EMPTY, sysAddr);
|
||||
entity->SetPlayerReadyForUpdates();
|
||||
|
||||
auto* ghostComponent = entity->GetComponent<GhostComponent>();
|
||||
|
||||
@@ -33,6 +33,10 @@ namespace GameMessages {
|
||||
PlayerReady() : NetGameMsg(MessageType::Game::PLAYER_READY) {}
|
||||
};
|
||||
|
||||
// Answers PlayerLoaded the way live did (235 of 237 loads): PlayerReady to the player, then to the zone control
|
||||
// object, whose client scripts wait for it. zoneControl is LWOOBJID_EMPTY when the zone has none.
|
||||
void SendPlayerReady(LWOOBJID player, LWOOBJID zoneControl, const SystemAddress& sysAddr);
|
||||
|
||||
// Server -> client, to one client. No payload.
|
||||
struct RestoreToPostLoadStats : public NetGameMsg {
|
||||
RestoreToPostLoadStats() : NetGameMsg(MessageType::Game::RESTORE_TO_POST_LOAD_STATS) {}
|
||||
|
||||
@@ -17,7 +17,8 @@ SET(DGAMEMESSAGES_TESTS
|
||||
"LegacyGameMessageTests.cpp"
|
||||
"GameMessageDecoderTests.cpp"
|
||||
"HotPropertyMessageTests.cpp"
|
||||
"ClientMessagesTests.cpp")
|
||||
"ClientMessagesTests.cpp"
|
||||
"LoadSequenceTests.cpp")
|
||||
|
||||
# Get the folder name and prepend it to the files above
|
||||
get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
|
||||
37
tests/dGameTests/dGameMessagesTests/LoadSequenceTests.cpp
Normal file
37
tests/dGameTests/dGameMessagesTests/LoadSequenceTests.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "GameDependencies.h"
|
||||
#include "GameMessageTestUtils.h"
|
||||
|
||||
#include "ZoneMessages.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace GameMessageTestUtils;
|
||||
|
||||
// What the world sends while a player loads into a zone, compared with the live captures.
|
||||
class LoadSequenceTests : public GameDependenciesTest {
|
||||
protected:
|
||||
void SetUp() override { SetUpDependencies(); }
|
||||
void TearDown() override { TearDownDependencies(); }
|
||||
|
||||
static constexpr LWOOBJID PLAYER = 0x1000000000000001LL;
|
||||
static constexpr LWOOBJID ZONE_CONTROL = 0x3FFF'FFFFFFFELL;
|
||||
};
|
||||
|
||||
// Live: PlayerReady to the player, then to the zone control object, both to the loading client only.
|
||||
// Bytes: the live pair with the player ID replaced.
|
||||
TEST_F(LoadSequenceTests, PlayerReadyGoesToThePlayerThenTheZoneControl) {
|
||||
const auto sent = Capture([&] { GameMessages::SendPlayerReady(PLAYER, ZONE_CONTROL, ClientAddress()); });
|
||||
ASSERT_EQ(sent.size(), 2u);
|
||||
EXPECT_PACKET_EQ(FromHex("53 05 00 0c 00 00 00 00 01 00 00 00 00 00 00 10 fd 01"), FromCapture(sent[0]));
|
||||
EXPECT_PACKET_EQ(FromHex("53 05 00 0c 00 00 00 00 fe ff ff ff ff 3f 00 00 fd 01"), FromCapture(sent[1]));
|
||||
for (const auto& packet : sent) {
|
||||
EXPECT_EQ(packet.sysAddr, ClientAddress());
|
||||
EXPECT_FALSE(packet.broadcast);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LoadSequenceTests, PlayerReadyWithoutZoneControlGoesToThePlayerOnly) {
|
||||
const auto sent = Capture([&] { GameMessages::SendPlayerReady(PLAYER, LWOOBJID_EMPTY, ClientAddress()); });
|
||||
ASSERT_EQ(sent.size(), 1u);
|
||||
EXPECT_PACKET_EQ(FromHex("53 05 00 0c 00 00 00 00 01 00 00 00 00 00 00 10 fd 01"), FromCapture(sent[0]));
|
||||
}
|
||||
Reference in New Issue
Block a user