Skip to content
Merged
Prev Previous commit
Next Next commit
feat: remote horses are now synced
  • Loading branch information
RobbeBryssinck committed Jan 3, 2022
commit a8a267a9229e8a239bd6d6411590b2171d1d0871
11 changes: 11 additions & 0 deletions Code/client/Events/MountEvent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

struct MountEvent
{
MountEvent(uint32_t aRiderID, uint32_t aMountID)
: RiderID(aRiderID), MountID(aMountID)
{}

uint32_t RiderID;
uint32_t MountID;
};
3 changes: 3 additions & 0 deletions Code/client/Games/Skyrim/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <Events/HealthChangeEvent.h>
#include <Events/InventoryChangeEvent.h>
#include <Events/MountEvent.h>

#include <World.h>
#include <Services/PapyrusService.h>
Expand Down Expand Up @@ -679,12 +680,14 @@ bool TP_MAKE_THISCALL(HookInitiateMountPackage, Actor, Actor* apMount)
return ThisCall(RealInitiateMountPackage, apThis, apMount);
}

// TODO: dont cancel, request ownership
if (ActorExtension* pMountExt = apMount->GetExtension())
{
if (pMountExt->IsRemote())
return false;
}

World::Get().GetRunner().Trigger(MountEvent(apThis->formID, apMount->formID));
return ThisCall(RealInitiateMountPackage, apThis, apMount);
}

Expand Down
6 changes: 6 additions & 0 deletions Code/client/Services/CharacterService.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ struct AddTargetEvent;
struct NotifyAddTarget;
struct ProjectileLaunchedEvent;
struct NotifyProjectileLaunch;
struct MountEvent;
struct NotifyMount;

struct Actor;
struct World;
Expand Down Expand Up @@ -50,6 +52,8 @@ struct CharacterService
void OnRemoteSpawnDataReceived(const NotifySpawnData& acEvent) const noexcept;
void OnProjectileLaunchedEvent(const ProjectileLaunchedEvent& acEvent) const noexcept;
void OnNotifyProjectileLaunch(const NotifyProjectileLaunch& acMessage) const noexcept;
void OnMountEvent(const MountEvent& acEvent) const noexcept;
void OnNotifyMount(const NotifyMount& acMessage) const noexcept;

private:

Expand Down Expand Up @@ -82,4 +86,6 @@ struct CharacterService
entt::scoped_connection m_remoteSpawnDataReceivedConnection;
entt::scoped_connection m_projectileLaunchedConnection;
entt::scoped_connection m_projectileLaunchConnection;
entt::scoped_connection m_mountConnection;
entt::scoped_connection m_notifyMountConnection;
};
89 changes: 89 additions & 0 deletions Code/client/Services/Generic/CharacterService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <Events/EquipmentChangeEvent.h>
#include <Events/UpdateEvent.h>
#include <Events/ProjectileLaunchedEvent.h>
#include <Events/MountEvent.h>

#include <Structs/ActionEvent.h>
#include <Messages/CancelAssignmentRequest.h>
Expand All @@ -50,6 +51,8 @@
#include <Messages/RequestOwnershipClaim.h>
#include <Messages/ProjectileLaunchRequest.h>
#include <Messages/NotifyProjectileLaunch.h>
#include <Messages/MountRequest.h>
#include <Messages/NotifyMount.h>

#include <World.h>
#include <Games/TES.h>
Expand Down Expand Up @@ -79,8 +82,12 @@ CharacterService::CharacterService(World& aWorld, entt::dispatcher& aDispatcher,
m_ownershipTransferConnection = m_dispatcher.sink<NotifyOwnershipTransfer>().connect<&CharacterService::OnOwnershipTransfer>(this);
m_removeCharacterConnection = m_dispatcher.sink<NotifyRemoveCharacter>().connect<&CharacterService::OnRemoveCharacter>(this);
m_remoteSpawnDataReceivedConnection = m_dispatcher.sink<NotifySpawnData>().connect<&CharacterService::OnRemoteSpawnDataReceived>(this);

m_projectileLaunchedConnection = m_dispatcher.sink<ProjectileLaunchedEvent>().connect<&CharacterService::OnProjectileLaunchedEvent>(this);
m_projectileLaunchConnection = m_dispatcher.sink<NotifyProjectileLaunch>().connect<&CharacterService::OnNotifyProjectileLaunch>(this);

m_mountConnection = m_dispatcher.sink<MountEvent>().connect<&CharacterService::OnMountEvent>(this);
m_notifyMountConnection = m_dispatcher.sink<NotifyMount>().connect<&CharacterService::OnNotifyMount>(this);
}

void CharacterService::OnFormIdComponentAdded(entt::registry& aRegistry, const entt::entity aEntity) const noexcept
Expand Down Expand Up @@ -1136,3 +1143,85 @@ void CharacterService::OnNotifyProjectileLaunch(const NotifyProjectileLaunch& ac
Projectile::Launch(&result, launchData);
}

void CharacterService::OnMountEvent(const MountEvent& acEvent) const noexcept
{
auto view = m_world.view<FormIdComponent>();

const auto riderIt = std::find_if(std::begin(view), std::end(view), [id = acEvent.RiderID, view](auto entity) {
return view.get<FormIdComponent>(entity).Id == id;
});

if (riderIt == std::end(view))
{
spdlog::warn("Rider not found, form id: {:X}", acEvent.RiderID);
return;
}

const entt::entity cRiderEntity = *riderIt;

std::optional<uint32_t> riderServerIdRes = utils::GetServerId(cRiderEntity);
if (!riderServerIdRes.has_value())
return;

const auto mountIt = std::find_if(std::begin(view), std::end(view), [id = acEvent.MountID, view](auto entity) {
return view.get<FormIdComponent>(entity).Id == id;
});

if (mountIt == std::end(view))
{
spdlog::warn("Mount not found, form id: {:X}", acEvent.MountID);
return;
}

const entt::entity cMountEntity = *mountIt;

std::optional<uint32_t> mountServerIdRes = utils::GetServerId(cMountEntity);
if (!mountServerIdRes.has_value())
return;

MountRequest request;
request.MountId = mountServerIdRes.value();
request.RiderId = riderServerIdRes.value();

m_transport.Send(request);
}

void CharacterService::OnNotifyMount(const NotifyMount& acMessage) const noexcept
{
auto remoteView = m_world.view<RemoteComponent, FormIdComponent>();

const auto riderIt = std::find_if(std::begin(remoteView), std::end(remoteView), [remoteView, Id = acMessage.RiderId](auto entity)
{
return remoteView.get<RemoteComponent>(entity).Id == Id;
});

if (riderIt == std::end(remoteView))
{
spdlog::warn("Rider with remote id {:X} not found.", acMessage.RiderId);
return;
}

auto riderFormIdComponent = remoteView.get<FormIdComponent>(*riderIt);
TESForm* pRiderForm = TESForm::GetById(riderFormIdComponent.Id);
Actor* pRider = RTTI_CAST(pRiderForm, TESForm, Actor);

const auto mountIt = std::find_if(std::begin(remoteView), std::end(remoteView), [remoteView, Id = acMessage.MountId](auto entity)
{
return remoteView.get<RemoteComponent>(entity).Id == Id;
});

if (mountIt == std::end(remoteView))
{
spdlog::warn("Mount with remote id {:X} not found.", acMessage.MountId);
return;
}

auto mountFormIdComponent = remoteView.get<FormIdComponent>(*mountIt);
TESForm* pMountForm = TESForm::GetById(mountFormIdComponent.Id);
Actor* pMount = RTTI_CAST(pMountForm, TESForm, Actor);

pRider->InitiateMountPackage(pMount);

spdlog::info("Rider mounted actor.");
}

3 changes: 2 additions & 1 deletion Code/encoding/Messages/ClientMessageFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <Messages/ProjectileLaunchRequest.h>
#include <Messages/ScriptAnimationRequest.h>
#include <Messages/DrawWeaponRequest.h>
#include <Messages/MountRequest.h>

using TiltedPhoques::UniquePtr;

Expand All @@ -52,7 +53,7 @@ struct ClientMessageFactory
RequestHealthChangeBroadcast, RequestSpawnData, ActivateRequest, LockChangeRequest,
AssignObjectsRequest, RequestDeathStateChange, ShiftGridCellRequest, RequestOwnershipTransfer,
RequestOwnershipClaim, RequestObjectInventoryChanges, SpellCastRequest, ProjectileLaunchRequest, InterruptCastRequest,
AddTargetRequest, ScriptAnimationRequest, DrawWeaponRequest>;
AddTargetRequest, ScriptAnimationRequest, DrawWeaponRequest, MountRequest>;

return s_visitor(std::forward<T>(func));
}
Expand Down
15 changes: 15 additions & 0 deletions Code/encoding/Messages/MountRequest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <Messages/MountRequest.h>

void MountRequest::SerializeRaw(TiltedPhoques::Buffer::Writer& aWriter) const noexcept
{
Serialization::WriteVarInt(aWriter, RiderId);
Serialization::WriteVarInt(aWriter, MountId);
}

void MountRequest::DeserializeRaw(TiltedPhoques::Buffer::Reader& aReader) noexcept
{
ClientMessage::DeserializeRaw(aReader);

RiderId = Serialization::ReadVarInt(aReader) & 0xFFFFFFFF;
MountId = Serialization::ReadVarInt(aReader) & 0xFFFFFFFF;
}
25 changes: 25 additions & 0 deletions Code/encoding/Messages/MountRequest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include "Message.h"

struct MountRequest final : ClientMessage
{
static constexpr ClientOpcode Opcode = kMountRequest;

MountRequest() : ClientMessage(Opcode)
{
}

void SerializeRaw(TiltedPhoques::Buffer::Writer& aWriter) const noexcept override;
void DeserializeRaw(TiltedPhoques::Buffer::Reader& aReader) noexcept override;

bool operator==(const MountRequest& acRhs) const noexcept
{
return RiderId == acRhs.RiderId &&
MountId == acRhs.MountId &&
GetOpcode() == acRhs.GetOpcode();
}

uint32_t RiderId;
uint32_t MountId;
};
15 changes: 15 additions & 0 deletions Code/encoding/Messages/NotifyMount.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <Messages/NotifyMount.h>

void NotifyMount::SerializeRaw(TiltedPhoques::Buffer::Writer& aWriter) const noexcept
{
Serialization::WriteVarInt(aWriter, RiderId);
Serialization::WriteVarInt(aWriter, MountId);
}

void NotifyMount::DeserializeRaw(TiltedPhoques::Buffer::Reader& aReader) noexcept
{
ServerMessage::DeserializeRaw(aReader);

RiderId = Serialization::ReadVarInt(aReader) & 0xFFFFFFFF;
MountId = Serialization::ReadVarInt(aReader) & 0xFFFFFFFF;
}
25 changes: 25 additions & 0 deletions Code/encoding/Messages/NotifyMount.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include "Message.h"

struct NotifyMount final : ServerMessage
{
static constexpr ServerOpcode Opcode = kNotifyMount;

NotifyMount() : ServerMessage(Opcode)
{
}

void SerializeRaw(TiltedPhoques::Buffer::Writer& aWriter) const noexcept override;
void DeserializeRaw(TiltedPhoques::Buffer::Reader& aReader) noexcept override;

bool operator==(const NotifyMount& acRhs) const noexcept
{
return RiderId == acRhs.RiderId &&
MountId == acRhs.MountId &&
GetOpcode() == acRhs.GetOpcode();
}

uint32_t RiderId;
uint32_t MountId;
};
3 changes: 2 additions & 1 deletion Code/encoding/Messages/ServerMessageFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <Messages/NotifyProjectileLaunch.h>
#include <Messages/NotifyScriptAnimation.h>
#include <Messages/NotifyDrawWeapon.h>
#include <Messages/NotifyMount.h>

using TiltedPhoques::UniquePtr;

Expand All @@ -50,7 +51,7 @@ struct ServerMessageFactory
NotifyActorMaxValueChanges, NotifyHealthChangeBroadcast, NotifySpawnData, NotifyActivate,
NotifyLockChange, AssignObjectsResponse, NotifyDeathStateChange, NotifyOwnershipTransfer,
NotifyObjectInventoryChanges, NotifySpellCast, NotifyProjectileLaunch, NotifyInterruptCast,
NotifyAddTarget, NotifyScriptAnimation, NotifyDrawWeapon>;
NotifyAddTarget, NotifyScriptAnimation, NotifyDrawWeapon, NotifyMount>;

return s_visitor(std::forward<T>(func));
}
Expand Down
2 changes: 2 additions & 0 deletions Code/encoding/Opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum ClientOpcode : unsigned char
kProjectileLaunchRequest,
kScriptAnimationRequest,
kDrawWeaponRequest,
kMountRequest,
kClientOpcodeMax
};

Expand Down Expand Up @@ -69,5 +70,6 @@ enum ServerOpcode : unsigned char
kNotifyProjectileLaunch,
kNotifyScriptAnimation,
kNotifyDrawWeapon,
kNotifyMount,
kServerOpcodeMax
};
15 changes: 15 additions & 0 deletions Code/server/Services/CharacterService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <Messages/RequestOwnershipClaim.h>
#include <Messages/ProjectileLaunchRequest.h>
#include <Messages/NotifyProjectileLaunch.h>
#include <Messages/MountRequest.h>
#include <Messages/NotifyMount.h>

CharacterService::CharacterService(World& aWorld, entt::dispatcher& aDispatcher) noexcept
: m_world(aWorld)
Expand All @@ -47,6 +49,7 @@ CharacterService::CharacterService(World& aWorld, entt::dispatcher& aDispatcher)
, m_factionsChangesConnection(aDispatcher.sink<PacketEvent<RequestFactionsChanges>>().connect<&CharacterService::OnFactionsChanges>(this))
, m_spawnDataConnection(aDispatcher.sink<PacketEvent<RequestSpawnData>>().connect<&CharacterService::OnRequestSpawnData>(this))
, m_projectileLaunchConnection(aDispatcher.sink<PacketEvent<ProjectileLaunchRequest>>().connect<&CharacterService::OnProjectileLaunchRequest>(this))
, m_mountConnection(aDispatcher.sink<PacketEvent<MountRequest>>().connect<CharacterService::OnMountRequest>(this))
{
}

Expand Down Expand Up @@ -699,3 +702,15 @@ void CharacterService::OnProjectileLaunchRequest(const PacketEvent<ProjectileLau
GameServer::Get()->SendToPlayersInRange(notify, cShooterEntity);
}

void CharacterService::OnMountRequest(const PacketEvent<MountRequest>& acMessage) const noexcept
{
auto& message = acMessage.Packet;

NotifyMount notify;
notify.RiderId = message.RiderId;
notify.MountId = message.MountId;

const entt::entity cEntity = static_cast<entt::entity>(message.MountId);
GameServer::Get()->SendToPlayersInRange(notify, cEntity);
}

3 changes: 3 additions & 0 deletions Code/server/Services/CharacterService.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct CharacterExteriorCellChangeEvent;
struct RequestOwnershipClaim;
struct OwnershipTransferEvent;
struct ProjectileLaunchRequest;
struct MountRequest;

struct CharacterService
{
Expand All @@ -43,6 +44,7 @@ struct CharacterService
void OnFactionsChanges(const PacketEvent<RequestFactionsChanges>& acMessage) const noexcept;
void OnRequestSpawnData(const PacketEvent<RequestSpawnData>& acMessage) const noexcept;
void OnProjectileLaunchRequest(const PacketEvent<ProjectileLaunchRequest>& acMessage) const noexcept;
void OnMountRequest(const PacketEvent<MountRequest>& acMessage) const noexcept;

void CreateCharacter(const PacketEvent<AssignCharacterRequest>& acMessage) const noexcept;

Expand All @@ -66,4 +68,5 @@ struct CharacterService
entt::scoped_connection m_factionsChangesConnection;
entt::scoped_connection m_spawnDataConnection;
entt::scoped_connection m_projectileLaunchConnection;
entt::scoped_connection m_mountConnection;
};