mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
feat(property): resend the equipment on ResyncEquipment
The property editor sends ResyncEquipment (1238, no payload) after the player picks up or sets down a model they carry: 59 live packets, every one right after PlaceModelResponse. Live answered with no game message, only replica serializations (packet 0x1b), i.e. the player's equipment sent again. DLU dropped it. The handler marks the inventory's equipped items dirty and serializes the player, so everyone gets the equipment again. That live re-sent the inventory part of the replica is inferred: the captures show a serialization but it was not decoded. Check in game: on your property, in build mode, pick up a model from the world and place it again a few times, then leave build mode: your hat, shirt, weapon etc. are all shown on you (and to a second player watching), none invisible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -301,6 +301,11 @@ public:
|
||||
*/
|
||||
void PopEquippedItems();
|
||||
|
||||
/**
|
||||
* Marks the equipped items to be sent again with the next serialization (ResyncEquipment)
|
||||
*/
|
||||
void ResyncEquipment() { m_Dirty = true; }
|
||||
|
||||
/**
|
||||
* Returns if the entity has an item equipped of the given lot
|
||||
* @param lot to lot to search for
|
||||
|
||||
@@ -98,6 +98,7 @@ namespace {
|
||||
{ REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES, []() { return std::make_unique<RequestMoveItemBetweenInventoryTypes>(); } },
|
||||
{ PUSH_EQUIPPED_ITEMS_STATE, []() { return std::make_unique<PushEquippedItemsState>(); } },
|
||||
{ POP_EQUIPPED_ITEMS_STATE, []() { return std::make_unique<PopEquippedItemsState>(); } },
|
||||
{ RESYNC_EQUIPMENT, []() { return std::make_unique<ResyncEquipment>(); } },
|
||||
{ CLIENT_ITEM_CONSUMED, []() { return std::make_unique<ClientItemConsumed>(); } },
|
||||
{ USE_NON_EQUIPMENT_ITEM, []() { return std::make_unique<UseNonEquipmentItem>(); } },
|
||||
{ SET_CONSUMABLE_ITEM, []() { return std::make_unique<SetConsumableItem>(); } },
|
||||
|
||||
@@ -422,6 +422,13 @@ namespace GameMessages {
|
||||
Game::entityManager->SerializeEntity(&entity); // so it updates on client side
|
||||
}
|
||||
|
||||
void ResyncEquipment::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
||||
auto* const inventoryComponent = entity.GetComponent<InventoryComponent>();
|
||||
if (!inventoryComponent) return;
|
||||
inventoryComponent->ResyncEquipment();
|
||||
Game::entityManager->SerializeEntity(&entity);
|
||||
}
|
||||
|
||||
void UpdateInventoryGroup::Serialize(RakNet::BitStream& bitStream) const {
|
||||
BitStreamUtils::WriteLengthPrefixed<uint32_t>(bitStream, action);
|
||||
BitStreamUtils::WriteLengthPrefixed<uint32_t>(bitStream, groupID);
|
||||
|
||||
@@ -288,6 +288,13 @@ namespace GameMessages {
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
};
|
||||
|
||||
// Client -> server. No payload. The property editor sends it after the player picks up or sets down a model
|
||||
// they carry (live: right after PlaceModelResponse). Live answered with a serialization of the player, no message.
|
||||
struct ResyncEquipment : public NetGameMsg {
|
||||
ResyncEquipment() : NetGameMsg(MessageType::Game::RESYNC_EQUIPMENT) {}
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
};
|
||||
|
||||
// Client -> server. Adds, modifies or removes an inventory group.
|
||||
struct UpdateInventoryGroup : public NetGameMsg {
|
||||
UpdateInventoryGroup() : NetGameMsg(MessageType::Game::UPDATE_INVENTORY_GROUP) {}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "SkillComponent.h"
|
||||
#include "SkillMessages.h"
|
||||
#include "Entity.h"
|
||||
#include "InventoryComponent.h"
|
||||
#include "InventoryMessages.h"
|
||||
#include "PlayerMessages.h"
|
||||
|
||||
#include <memory>
|
||||
@@ -121,3 +123,24 @@ TEST_F(ClientMessagesTests, CasterDeadEndsTheDeadCastersSkill) {
|
||||
EXPECT_FALSE(skills->HasSkill(1));
|
||||
EXPECT_TRUE(skills->HasSkill(2));
|
||||
}
|
||||
|
||||
// ResyncEquipment (1238): no payload (59 live packets). The next serialization carries the equipped items again.
|
||||
TEST_F(ClientMessagesTests, ResyncEquipmentResendsTheEquipment) {
|
||||
auto msg = FromLiveClientCapture<GameMessages::ResyncEquipment>(std::string(PLAYER_HEADER) + "d604");
|
||||
CDClientDatabase::Connect(":memory:"); // the inventory looks its component up
|
||||
CDClientDatabase::ExecuteDML("CREATE TABLE ComponentsRegistry (id INTEGER, component_type INTEGER, component_id INTEGER);");
|
||||
auto* const inventory = player->AddComponent<InventoryComponent>(-1);
|
||||
RakNet::BitStream first;
|
||||
inventory->Serialize(first, false); // clears the dirty flag it starts with
|
||||
RakNet::BitStream clean;
|
||||
inventory->Serialize(clean, false);
|
||||
bool equipmentSent = true;
|
||||
ASSERT_TRUE(clean.Read(equipmentSent));
|
||||
EXPECT_FALSE(equipmentSent);
|
||||
|
||||
msg.Handle(*player, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
RakNet::BitStream resent;
|
||||
inventory->Serialize(resent, false);
|
||||
ASSERT_TRUE(resent.Read(equipmentSent));
|
||||
EXPECT_TRUE(equipmentSent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user