mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
feat(rails): answer RequestRailActivatorState
The client's rail activator sends RequestRailActivatorState (1479, no payload) when it is added to the world (LWORailActivatorComponent:: SendMessage 0x00c00da0) and live answered with NotifyRailActivatorStateChange (1478, bActive) to that client; the client stores rail_activator_active and updates the rail's pick type (usable or not). Live: 152 requests, 413 answers, every one bActive = true. DLU dropped the request and never answered. RailActivatorComponent keeps the level key rail_activator_active (default true; every rail in the live levels sets it to 1) and the request is answered with it. Check in game: in Ninjago Monastery and Nimbus Station, rails (spinjitzu posts, the Nexus Tower rails) show as usable and work as before when first loading the world and after zone changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,7 @@ RailActivatorComponent::RailActivatorComponent(Entity* parent, const int32_t com
|
||||
m_NotifyArrived = parent->GetVar<bool>(u"rail_notify_activator_arrived");
|
||||
m_ShowNameBillboard = levelOr(u"rail_show_name_billboard", tableData.showNameBillboard);
|
||||
m_UseDB = parent->GetVar<bool>(u"rail_use_db");
|
||||
m_Active = levelOr(u"rail_activator_active", true);
|
||||
m_CameraLocked = tableData.cameraLocked;
|
||||
m_CollisionEnabled = tableData.playerCollision;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,11 @@ public:
|
||||
void OnCancelRailMovement(Entity* originator);
|
||||
|
||||
bool GetDamageImmune() const { return m_DamageImmune; }
|
||||
|
||||
/**
|
||||
* Whether the rail can be used (level key rail_activator_active; every rail in the live levels has it set)
|
||||
*/
|
||||
bool GetActive() const { return m_Active; }
|
||||
bool GetNoAggro() const { return m_NoAggro; }
|
||||
bool GetShowNameBillboard() const { return m_ShowNameBillboard; }
|
||||
private:
|
||||
@@ -111,6 +116,8 @@ private:
|
||||
*/
|
||||
bool m_DamageImmune;
|
||||
|
||||
bool m_Active{ true };
|
||||
|
||||
/**
|
||||
* Client flag
|
||||
*/
|
||||
|
||||
@@ -215,6 +215,7 @@ namespace {
|
||||
{ CLIENT_RAIL_MOVEMENT_READY, []() { return std::make_unique<ClientRailMovementReady>(); } },
|
||||
{ CANCEL_RAIL_MOVEMENT, []() { return std::make_unique<CancelRailMovement>(); } },
|
||||
{ PLAYER_RAIL_ARRIVED_NOTIFICATION, []() { return std::make_unique<PlayerRailArrivedNotification>(); } },
|
||||
{ REQUEST_RAIL_ACTIVATOR_STATE, []() { return std::make_unique<RequestRailActivatorState>(); } },
|
||||
{ DISMOUNT_COMPLETE, []() { return std::make_unique<DismountComplete>(); } },
|
||||
{ ACKNOWLEDGE_POSSESSION, []() { return std::make_unique<AcknowledgePossession>(); } },
|
||||
{ TOGGLE_GHOST_REFERENCE_OVERRIDE, []() { return std::make_unique<ToggleGhostReferenceOverride>(); } },
|
||||
|
||||
@@ -295,6 +295,24 @@ namespace GameMessages {
|
||||
}
|
||||
}
|
||||
|
||||
void RequestRailActivatorState::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
||||
const auto* const rail = entity.GetComponent<RailActivatorComponent>();
|
||||
if (!rail) return;
|
||||
NotifyRailActivatorStateChange notify;
|
||||
notify.target = entity.GetObjectID();
|
||||
notify.bActive = rail->GetActive();
|
||||
notify.SendToClient(sysAddr);
|
||||
}
|
||||
|
||||
void NotifyRailActivatorStateChange::Serialize(RakNet::BitStream& bitStream) const {
|
||||
bitStream.Write(bActive);
|
||||
}
|
||||
|
||||
bool NotifyRailActivatorStateChange::Deserialize(RakNet::BitStream& bitStream) {
|
||||
VALIDATE_READ(bitStream.Read(bActive));
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlayerRailArrivedNotification::Serialize(RakNet::BitStream& bitStream) const {
|
||||
BitStreamUtils::WriteLengthPrefixed<uint32_t>(bitStream, pathName);
|
||||
bitStream.Write(waypointNumber);
|
||||
|
||||
@@ -197,6 +197,22 @@ namespace GameMessages {
|
||||
bool bImmediate{};
|
||||
};
|
||||
|
||||
// Client -> server, no payload. The client's rail activator asks for its state when it is added to the world
|
||||
// (LWORailActivatorComponent::SendMessage 0x00c00da0); live answered NotifyRailActivatorStateChange to that client.
|
||||
struct RequestRailActivatorState : public NetGameMsg {
|
||||
RequestRailActivatorState() : NetGameMsg(MessageType::Game::REQUEST_RAIL_ACTIVATOR_STATE) {}
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
};
|
||||
|
||||
// Server -> client. The client sets rail_activator_active and updates the rail's pick type (usable or not).
|
||||
struct NotifyRailActivatorStateChange : public NetGameMsg {
|
||||
NotifyRailActivatorStateChange() : NetGameMsg(MessageType::Game::NOTIFY_RAIL_ACTOVATOR_STATE_CHANGE) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
bool Deserialize(RakNet::BitStream& bitStream) override;
|
||||
|
||||
bool bActive{ true };
|
||||
};
|
||||
|
||||
// Client -> server.
|
||||
struct PlayerRailArrivedNotification : public NetGameMsg {
|
||||
PlayerRailArrivedNotification() : NetGameMsg(MessageType::Game::PLAYER_RAIL_ARRIVED_NOTIFICATION) {}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "CDRailActivatorComponent.h"
|
||||
#include "Entity.h"
|
||||
#include "MovementMessages.h"
|
||||
#include "dGameMessagesTests/GameMessageTestUtils.h"
|
||||
#include "RailActivatorComponent.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
@@ -57,3 +59,26 @@ TEST_F(RailActivatorComponentTests, NoRowAndNoKeysIsNotImmune) {
|
||||
EXPECT_FALSE(rail->GetDamageImmune());
|
||||
EXPECT_FALSE(rail->GetNoAggro());
|
||||
}
|
||||
|
||||
// Live answered the client's RequestRailActivatorState (1479, no payload; 152 packets) with
|
||||
// NotifyRailActivatorStateChange (1478) to that client: every one of the 413 live packets was bActive = true (80).
|
||||
TEST_F(RailActivatorComponentTests, RequestRailActivatorStateIsAnswered) {
|
||||
using namespace GameMessageTestUtils;
|
||||
entity->AddComponent<RailActivatorComponent>(COMPONENT_ID);
|
||||
GameMessages::RequestRailActivatorState request;
|
||||
const auto packets = Capture([&] { request.Handle(*entity, ClientAddress()); });
|
||||
ASSERT_EQ(packets.size(), 1u);
|
||||
EXPECT_EQ(packets[0].sysAddr, ClientAddress());
|
||||
EXPECT_FALSE(packets[0].broadcast);
|
||||
EXPECT_PACKET_EQ(FromHex("53 05 00 0c 00 00 00 00 01 00 00 00 00 00 00 00 c6 05 80", 145), FromCapture(packets[0]));
|
||||
}
|
||||
|
||||
TEST_F(RailActivatorComponentTests, InactiveRailIsReportedInactive) {
|
||||
using namespace GameMessageTestUtils;
|
||||
entity->SetVar<bool>(u"rail_activator_active", false);
|
||||
const auto* const rail = entity->AddComponent<RailActivatorComponent>(COMPONENT_ID);
|
||||
EXPECT_FALSE(rail->GetActive());
|
||||
GameMessages::NotifyRailActivatorStateChange notify;
|
||||
notify.bActive = false;
|
||||
EXPECT_FALSE(RoundTrip(notify).bActive);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user