From 77c009864eee163a2721d0c8976259a8ad781970 Mon Sep 17 00:00:00 2001 From: Robbe Bryssinck Date: Sun, 29 May 2022 01:49:33 +0200 Subject: [PATCH] fix: the door problem (again) --- Code/client/Services/CharacterService.h | 6 ++ .../Services/Generic/CharacterService.cpp | 83 ++++++++++++++----- .../encoding/Messages/NotifyActorTeleport.cpp | 19 +++++ Code/encoding/Messages/NotifyActorTeleport.h | 31 +++++++ .../Messages/RequestOwnershipTransfer.cpp | 6 ++ .../Messages/RequestOwnershipTransfer.h | 14 +++- Code/encoding/Messages/ServerMessageFactory.h | 4 +- Code/encoding/Opcodes.h | 1 + Code/server/Services/CharacterService.cpp | 26 +++++- 9 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 Code/encoding/Messages/NotifyActorTeleport.cpp create mode 100644 Code/encoding/Messages/NotifyActorTeleport.h diff --git a/Code/client/Services/CharacterService.h b/Code/client/Services/CharacterService.h index e0ebf3cb7..c108c3e40 100644 --- a/Code/client/Services/CharacterService.h +++ b/Code/client/Services/CharacterService.h @@ -37,6 +37,7 @@ struct DialogueEvent; struct NotifyDialogue; struct SubtitleEvent; struct NotifySubtitle; +struct NotifyActorTeleport; struct Actor; struct World; @@ -79,9 +80,13 @@ struct CharacterService void OnNotifyDialogue(const NotifyDialogue& acMessage) noexcept; void OnSubtitleEvent(const SubtitleEvent& acEvent) noexcept; void OnNotifySubtitle(const NotifySubtitle& acMessage) noexcept; + void OnNotifyActorTeleport(const NotifyActorTeleport& acMessage) noexcept; private: + void MoveActor(const Actor* apActor, const GameId& acWorldSpaceId, const GameId& acCellId, + const Vector3_NetQuantize& acPosition) const noexcept; + void ProcessNewEntity(entt::entity aEntity) const noexcept; void RequestServerAssignment(entt::entity aEntity) const noexcept; void CancelServerAssignment(entt::entity aEntity, uint32_t aFormId) const noexcept; @@ -130,4 +135,5 @@ struct CharacterService entt::scoped_connection m_dialogueSyncConnection; entt::scoped_connection m_subtitleEventConnection; entt::scoped_connection m_subtitleSyncConnection; + entt::scoped_connection m_actorTeleportConnection; }; diff --git a/Code/client/Services/Generic/CharacterService.cpp b/Code/client/Services/Generic/CharacterService.cpp index 2e3ef20bf..1a1414373 100644 --- a/Code/client/Services/Generic/CharacterService.cpp +++ b/Code/client/Services/Generic/CharacterService.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -112,6 +113,8 @@ CharacterService::CharacterService(World& aWorld, entt::dispatcher& aDispatcher, m_subtitleEventConnection = m_dispatcher.sink().connect<&CharacterService::OnSubtitleEvent>(this); m_subtitleSyncConnection = m_dispatcher.sink().connect<&CharacterService::OnNotifySubtitle>(this); + + m_actorTeleportConnection = m_dispatcher.sink().connect<&CharacterService::OnNotifyActorTeleport>(this); } void CharacterService::OnActorAdded(const ActorAddedEvent& acEvent) noexcept @@ -302,23 +305,7 @@ void CharacterService::OnAssignCharacter(const AssignCharacterResponse& acMessag if (pActor->actorState.IsWeaponDrawn() != acMessage.IsWeaponDrawn) m_weaponDrawUpdates[pActor->formID] = {0, acMessage.IsWeaponDrawn}; - const uint32_t cCellId = m_world.GetModSystem().GetGameId(acMessage.CellId); - TESObjectCELL* pCell = Cast(TESForm::GetById(cCellId)); - - // In case of lazy-loading of exterior cells - if (!pCell) - { - const uint32_t cWorldSpaceId = m_world.GetModSystem().GetGameId(acMessage.WorldSpaceId); - TESWorldSpace* const pWorldSpace = Cast(TESForm::GetById(cWorldSpaceId)); - if (pWorldSpace) - { - GridCellCoords coordinates = GridCellCoords::CalculateGridCellCoords(acMessage.Position); - pCell = pWorldSpace->LoadCell(coordinates.X, coordinates.Y); - } - } - - if (pCell) - pActor->MoveTo(pCell, acMessage.Position); + MoveActor(pActor, acMessage.WorldSpaceId, acMessage.CellId, acMessage.Position); } } @@ -586,7 +573,7 @@ void CharacterService::OnOwnershipTransfer(const NotifyOwnershipTransfer& acMess spdlog::warn("Actor for ownership transfer not found {:X}", acMessage.ServerId); - RequestOwnershipTransfer request; + RequestOwnershipTransfer request{}; request.ServerId = acMessage.ServerId; m_transport.Send(request); @@ -1126,6 +1113,42 @@ void CharacterService::OnNotifySubtitle(const NotifySubtitle& acMessage) noexcep SubtitleManager::Get()->ShowSubtitle(pActor, acMessage.Text.c_str()); } +void CharacterService::OnNotifyActorTeleport(const NotifyActorTeleport& acMessage) noexcept +{ + auto& modSystem = m_world.GetModSystem(); + + const uint32_t cActorId = World::Get().GetModSystem().GetGameId(acMessage.FormId); + Actor* pActor = Cast(TESForm::GetById(cActorId)); + if (!pActor) + { + spdlog::error(__FUNCTION__ ": failed to retrieve actor to teleport."); + return; + } + + MoveActor(pActor, acMessage.WorldSpaceId, acMessage.CellId, acMessage.Position); +} + +void CharacterService::MoveActor(const Actor* apActor, const GameId& acWorldSpaceId, const GameId& acCellId, const Vector3_NetQuantize& acPosition) const noexcept +{ + const uint32_t cCellId = m_world.GetModSystem().GetGameId(acCellId); + TESObjectCELL* pCell = Cast(TESForm::GetById(cCellId)); + + // In case of lazy-loading of exterior cells + if (!pCell) + { + const uint32_t cWorldSpaceId = m_world.GetModSystem().GetGameId(acWorldSpaceId); + TESWorldSpace* const pWorldSpace = Cast(TESForm::GetById(cWorldSpaceId)); + if (pWorldSpace) + { + GridCellCoords coordinates = GridCellCoords::CalculateGridCellCoords(acPosition); + pCell = pWorldSpace->LoadCell(coordinates.X, coordinates.Y); + } + } + + if (pCell) + apActor->MoveTo(pCell, acPosition); +} + void CharacterService::ProcessNewEntity(entt::entity aEntity) const noexcept { if (!m_transport.IsOnline()) @@ -1338,9 +1361,31 @@ void CharacterService::CancelServerAssignment(const entt::entity aEntity, const { auto& localComponent = m_world.get(aEntity); - RequestOwnershipTransfer request; + RequestOwnershipTransfer request{}; request.ServerId = localComponent.Id; + if (Actor* pActor = Cast(TESForm::GetById(aFormId))) + { + if (pActor->IsTemporary()) + { + auto& modSystem = m_world.GetModSystem(); + + if (TESWorldSpace* pWorldSpace = pActor->GetWorldSpace()) + { + if (!modSystem.GetServerModId(pWorldSpace->formID, request.WorldSpaceId)) + spdlog::error("World space id not found, despite having a world space, {:X}", pWorldSpace->formID); + } + + if (TESObjectCELL* pCell = pActor->GetParentCell()) + { + if (!modSystem.GetServerModId(pCell->formID, request.CellId)) + spdlog::error("Cell id not found, despite having a cell, {:X}", pCell->formID); + } + + request.Position = pActor->position; + } + } + m_transport.Send(request); m_world.remove(aEntity); diff --git a/Code/encoding/Messages/NotifyActorTeleport.cpp b/Code/encoding/Messages/NotifyActorTeleport.cpp new file mode 100644 index 000000000..9ce2da41d --- /dev/null +++ b/Code/encoding/Messages/NotifyActorTeleport.cpp @@ -0,0 +1,19 @@ +#include + +void NotifyActorTeleport::SerializeRaw(TiltedPhoques::Buffer::Writer& aWriter) const noexcept +{ + FormId.Serialize(aWriter); + WorldSpaceId.Serialize(aWriter); + CellId.Serialize(aWriter); + Position.Serialize(aWriter); +} + +void NotifyActorTeleport::DeserializeRaw(TiltedPhoques::Buffer::Reader& aReader) noexcept +{ + ServerMessage::DeserializeRaw(aReader); + + FormId.Deserialize(aReader); + WorldSpaceId.Deserialize(aReader); + CellId.Deserialize(aReader); + Position.Deserialize(aReader); +} diff --git a/Code/encoding/Messages/NotifyActorTeleport.h b/Code/encoding/Messages/NotifyActorTeleport.h new file mode 100644 index 000000000..f1e3c1ca0 --- /dev/null +++ b/Code/encoding/Messages/NotifyActorTeleport.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Message.h" +#include +#include + +struct NotifyActorTeleport final : ServerMessage +{ + static constexpr ServerOpcode Opcode = kNotifyActorTeleport; + + NotifyActorTeleport() : ServerMessage(Opcode) + { + } + + void SerializeRaw(TiltedPhoques::Buffer::Writer& aWriter) const noexcept override; + void DeserializeRaw(TiltedPhoques::Buffer::Reader& aReader) noexcept override; + + bool operator==(const NotifyActorTeleport& acRhs) const noexcept + { + return GetOpcode() == acRhs.GetOpcode() && + FormId == acRhs.FormId && + WorldSpaceId == acRhs.WorldSpaceId && + CellId == acRhs.CellId && + Position == acRhs.Position; + } + + GameId FormId{}; + GameId WorldSpaceId{}; + GameId CellId{}; + Vector3_NetQuantize Position{}; +}; diff --git a/Code/encoding/Messages/RequestOwnershipTransfer.cpp b/Code/encoding/Messages/RequestOwnershipTransfer.cpp index 6027cbb2c..b3e060d36 100644 --- a/Code/encoding/Messages/RequestOwnershipTransfer.cpp +++ b/Code/encoding/Messages/RequestOwnershipTransfer.cpp @@ -3,6 +3,9 @@ void RequestOwnershipTransfer::SerializeRaw(TiltedPhoques::Buffer::Writer& aWriter) const noexcept { Serialization::WriteVarInt(aWriter, ServerId); + WorldSpaceId.Serialize(aWriter); + CellId.Serialize(aWriter); + Position.Serialize(aWriter); } void RequestOwnershipTransfer::DeserializeRaw(TiltedPhoques::Buffer::Reader& aReader) noexcept @@ -10,4 +13,7 @@ void RequestOwnershipTransfer::DeserializeRaw(TiltedPhoques::Buffer::Reader& aRe ClientMessage::DeserializeRaw(aReader); ServerId = Serialization::ReadVarInt(aReader) & 0xFFFFFFFF; + WorldSpaceId.Deserialize(aReader); + CellId.Deserialize(aReader); + Position.Deserialize(aReader); } diff --git a/Code/encoding/Messages/RequestOwnershipTransfer.h b/Code/encoding/Messages/RequestOwnershipTransfer.h index 86bfdb1dc..d1ac8fa61 100644 --- a/Code/encoding/Messages/RequestOwnershipTransfer.h +++ b/Code/encoding/Messages/RequestOwnershipTransfer.h @@ -2,6 +2,9 @@ #include "Message.h" +#include +#include + struct RequestOwnershipTransfer final : ClientMessage { static constexpr ClientOpcode Opcode = kRequestOwnershipTransfer; @@ -17,8 +20,15 @@ struct RequestOwnershipTransfer final : ClientMessage bool operator==(const RequestOwnershipTransfer& achRhs) const noexcept { - return ServerId == achRhs.ServerId && GetOpcode() == achRhs.GetOpcode(); + return GetOpcode() == achRhs.GetOpcode() && + ServerId == achRhs.ServerId && + WorldSpaceId == achRhs.WorldSpaceId && + CellId == achRhs.CellId && + Position == achRhs.Position; } - uint32_t ServerId; + uint32_t ServerId{}; + GameId WorldSpaceId{}; + GameId CellId{}; + Vector3_NetQuantize Position{}; }; diff --git a/Code/encoding/Messages/ServerMessageFactory.h b/Code/encoding/Messages/ServerMessageFactory.h index 1bb17a35f..6772859f6 100644 --- a/Code/encoding/Messages/ServerMessageFactory.h +++ b/Code/encoding/Messages/ServerMessageFactory.h @@ -46,6 +46,7 @@ #include #include #include +#include using TiltedPhoques::UniquePtr; @@ -65,7 +66,8 @@ struct ServerMessageFactory NotifyObjectInventoryChanges, NotifySpellCast, NotifyProjectileLaunch, NotifyInterruptCast, NotifyAddTarget, NotifyScriptAnimation, NotifyDrawWeapon, NotifyMount, NotifyNewPackage, NotifyRespawn, NotifySyncExperience, NotifyEquipmentChanges, NotifyChatMessageBroadcast, - TeleportCommandResponse, NotifyPlayerRespawn, NotifyDialogue, NotifySubtitle, NotifyPlayerDialogue>; + TeleportCommandResponse, NotifyPlayerRespawn, NotifyDialogue, NotifySubtitle, NotifyPlayerDialogue, + NotifyActorTeleport>; return s_visitor(std::forward(func)); } diff --git a/Code/encoding/Opcodes.h b/Code/encoding/Opcodes.h index d8575e4f4..5f6ace77a 100644 --- a/Code/encoding/Opcodes.h +++ b/Code/encoding/Opcodes.h @@ -93,5 +93,6 @@ enum ServerOpcode : unsigned char kNotifyDialogue, kNotifySubtitle, kNotifyPlayerDialogue, + kNotifyActorTeleport, kServerOpcodeMax }; diff --git a/Code/server/Services/CharacterService.cpp b/Code/server/Services/CharacterService.cpp index 4a83d4756..0968b9c16 100644 --- a/Code/server/Services/CharacterService.cpp +++ b/Code/server/Services/CharacterService.cpp @@ -40,6 +40,7 @@ #include #include #include +#include CharacterService::CharacterService(World& aWorld, entt::dispatcher& aDispatcher) noexcept : m_world(aWorld) @@ -229,7 +230,7 @@ void CharacterService::OnOwnershipTransferRequest(const PacketEvent view(m_world, acMessage.GetSender()); + OwnerView view(m_world, acMessage.GetSender()); const auto it = view.find(static_cast(message.ServerId)); if (it == view.end()) @@ -238,6 +239,26 @@ void CharacterService::OnOwnershipTransferRequest(const PacketEvent(*it); + + NotifyActorTeleport notify{}; + notify.FormId = formIdComponent.Id; + notify.WorldSpaceId = message.WorldSpaceId; + notify.CellId = message.CellId; + notify.Position = message.Position; + + auto& cellIdComponent = view.get(*it); + cellIdComponent.WorldSpaceId = message.WorldSpaceId; + cellIdComponent.Cell = message.CellId; + cellIdComponent.CenterCoords = GridCellCoords::CalculateGridCellCoords(message.Position); + + auto& movementComponent = view.get(*it); + movementComponent.Position = message.Position; + movementComponent.Sent = true; + } + auto& characterOwnerComponent = view.get(*it); characterOwnerComponent.InvalidOwners.push_back(acMessage.pPlayer); @@ -613,8 +634,7 @@ void CharacterService::CreateCharacter(const PacketEvent if (message.WorldSpaceId != GameId{}) { cellIdComponent.WorldSpaceId = message.WorldSpaceId; - auto coords = GridCellCoords::CalculateGridCellCoords(message.Position.x, message.Position.y); - cellIdComponent.CenterCoords = coords; + cellIdComponent.CenterCoords = GridCellCoords::CalculateGridCellCoords(message.Position); } auto& characterComponent = m_world.emplace(cEntity);