Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
};
2 changes: 1 addition & 1 deletion Code/client/Games/Primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ struct GamePtr

GamePtr& operator=(GamePtr<T>&& aRhs)
{
std::swap(m_pPointer, acRhs.m_pPointer);
std::swap(m_pPointer, aRhs.m_pPointer);

return *this;
}
Expand Down
25 changes: 24 additions & 1 deletion 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 @@ -465,6 +466,14 @@ void Actor::RemoveFromAllFactions() noexcept
s_pRemoveFromAllFactions(this);
}

TP_THIS_FUNCTION(TInitiateMountPackage, bool, Actor, Actor* apMount);
static TInitiateMountPackage* RealInitiateMountPackage = nullptr;

bool Actor::InitiateMountPackage(Actor* apMount) noexcept
{
return ThisCall(RealInitiateMountPackage, this, apMount);
}

bool Actor::IsDead() noexcept
{
PAPYRUS_FUNCTION(bool, Actor, IsDead);
Expand Down Expand Up @@ -651,7 +660,7 @@ void TP_MAKE_THISCALL(HookUpdateDetectionState, ActorKnowledge, void* apState)

struct DialogueItem;

// This is an AIProcess function
// TODO: This is an AIProcess function
TP_THIS_FUNCTION(TProcessResponse, uint64_t, void, DialogueItem* apVoice, Actor* apTalkingActor, Actor* apTalkedToActor);
static TProcessResponse* RealProcessResponse = nullptr;

Expand All @@ -665,6 +674,17 @@ uint64_t TP_MAKE_THISCALL(HookProcessResponse, void, DialogueItem* apVoice, Acto
return ThisCall(RealProcessResponse, apThis, apVoice, apTalkingActor, apTalkedToActor);
}

bool TP_MAKE_THISCALL(HookInitiateMountPackage, Actor, Actor* apMount)
{
if (!apMount)
{
return ThisCall(RealInitiateMountPackage, apThis, apMount);
}

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

static TiltedPhoques::Initializer s_actorHooks([]()
{
POINTER_SKYRIMSE(TCharacterConstructor, s_characterCtor, 0x1406BA280 - 0x140000000);
Expand All @@ -680,6 +700,7 @@ static TiltedPhoques::Initializer s_actorHooks([]()
POINTER_SKYRIMSE(TPickUpItem, s_pickUpItem, 0x14060C280 - 0x140000000);
POINTER_SKYRIMSE(TUpdateDetectionState, s_updateDetectionState, 0x140742FE0 - 0x140000000);
POINTER_SKYRIMSE(TProcessResponse, s_processResponse, 0x14068BC50 - 0x140000000);
POINTER_SKYRIMSE(TInitiateMountPackage, s_initiateMountPackage, 0x14062CF40 - 0x140000000);

FUNC_GetActorLocation = s_GetActorLocation.Get();
RealCharacterConstructor = s_characterCtor.Get();
Expand All @@ -693,6 +714,7 @@ static TiltedPhoques::Initializer s_actorHooks([]()
RealPickUpItem = s_pickUpItem.Get();
RealUpdateDetectionState = s_updateDetectionState.Get();
RealProcessResponse = s_processResponse.Get();
RealInitiateMountPackage = s_initiateMountPackage.Get();

TP_HOOK(&RealCharacterConstructor, HookCharacterConstructor);
TP_HOOK(&RealCharacterConstructor2, HookCharacterConstructor2);
Expand All @@ -705,4 +727,5 @@ static TiltedPhoques::Initializer s_actorHooks([]()
TP_HOOK(&RealPickUpItem, HookPickUpItem);
TP_HOOK(&RealUpdateDetectionState, HookUpdateDetectionState);
TP_HOOK(&RealProcessResponse, HookProcessResponse);
TP_HOOK(&RealInitiateMountPackage, HookInitiateMountPackage);
});
1 change: 1 addition & 0 deletions Code/client/Games/Skyrim/Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ struct Actor : TESObjectREFR
void UnEquipAll() noexcept;
void RemoveFromAllFactions() noexcept;
void QueueUpdate() noexcept;
bool InitiateMountPackage(Actor* apMount) noexcept;

bool IsDead() noexcept;
void Kill() noexcept;
Expand Down
2 changes: 1 addition & 1 deletion Code/client/Games/Skyrim/BSAnimationGraphManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct BSAnimationGraphManager

uint32_t animationGraphIndex; // A8 - 5C

SortedMap<uint32_t, String> BSAnimationGraphManager::DumpAnimationVariables(bool aPrintVariables);
SortedMap<uint32_t, String> DumpAnimationVariables(bool aPrintVariables);
uint64_t GetDescriptorKey(int aForceIndex = -1);
uint32_t ReSendEvent(BSFixedString* apEventName);
};
Expand Down
2 changes: 1 addition & 1 deletion Code/client/Games/Skyrim/Effects/ActiveEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct ActiveEffect
// this ctor is used by seemingly all ActiveEffect child classes' Instantiate() methods
// can be used to find individual Instantiate() methods
// address: 0x140C4E350
ActiveEffect::ActiveEffect(Actor* apCaster, MagicItem* apSpell, EffectItem* apEffect);
ActiveEffect(Actor* apCaster, MagicItem* apSpell, EffectItem* apEffect);

virtual void sub_0();
virtual void sub_1();
Expand Down
4 changes: 2 additions & 2 deletions Code/client/Games/Skyrim/LoadingScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ TRequestLoadingText* RealRequestLoadingText;

void RequestLoadingText(ScaleFormContext* apContext)
{
static char* s_displayStr = "TESSST";
static const char* s_displayStr = "TESSST";

apContext->scaleformReturn->someBool50 = 0;
if(apContext->scaleformReturn->scaleformValue)
apContext->scaleformReturn->scaleformValue->data = s_displayStr;
apContext->scaleformReturn->scaleformValue->data = (char*)s_displayStr;

RealRequestLoadingText(apContext);
}
Expand Down
2 changes: 1 addition & 1 deletion Code/client/Games/Skyrim/Misc/BSScript.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct BSScript
void PrepareImplementation(IFunctionArguments::Statement* apStatement,
std::index_sequence<Is...>) noexcept
{
((apStatement->values[Is].Set(std::get<Is>(args))), ...);
((apStatement->vars[Is].Set(std::get<Is>(args))), ...);
}

Tuple args;
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;
};
125 changes: 125 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 @@ -1139,3 +1146,121 @@ void CharacterService::OnNotifyProjectileLaunch(const NotifyProjectileLaunch& ac
Projectile::Launch(&result, launchData);
}

void CharacterService::OnMountEvent(const MountEvent& acEvent) const noexcept
{
#if TP_SKYRIM64
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;

if (m_world.try_get<RemoteComponent>(cMountEntity))
{
const TESForm* pMountForm = TESForm::GetById(acEvent.MountID);
Actor* pMount = RTTI_CAST(pMountForm, TESForm, Actor);
pMount->GetExtension()->SetRemote(false);

m_world.emplace<LocalComponent>(cMountEntity, mountServerIdRes.value());
m_world.emplace<LocalAnimationComponent>(cMountEntity);
m_world.remove<RemoteComponent, InterpolationComponent, RemoteAnimationComponent,
FaceGenComponent, CacheComponent, WaitingFor3D>(cMountEntity);

RequestOwnershipClaim request;
request.ServerId = mountServerIdRes.value();

m_transport.Send(request);
}

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

m_transport.Send(request);
#endif
}

void CharacterService::OnNotifyMount(const NotifyMount& acMessage) const noexcept
{
#if TP_SKYRIM64
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);

Actor* pMount = nullptr;

auto formView = m_world.view<FormIdComponent>();
for (auto entity : formView)
{
std::optional<uint32_t> serverIdRes = utils::GetServerId(entity);
if (!serverIdRes.has_value())
continue;

uint32_t serverId = serverIdRes.value();

if (serverId == acMessage.MountId)
{
auto mountFormIdComponent = formView.get<FormIdComponent>(entity);

if (m_world.all_of<LocalComponent>(entity))
{
m_world.remove<LocalAnimationComponent, LocalComponent>(entity);
m_world.emplace_or_replace<RemoteComponent>(entity, acMessage.MountId, mountFormIdComponent.Id);
}

TESForm* pMountForm = TESForm::GetById(mountFormIdComponent.Id);
pMount = RTTI_CAST(pMountForm, TESForm, Actor);
pMount->GetExtension()->SetRemote(true);

InterpolationSystem::Setup(m_world, entity);
AnimationSystem::Setup(m_world, entity);

break;
}
}

pRider->InitiateMountPackage(pMount);
#endif
}

21 changes: 1 addition & 20 deletions Code/client/Services/Generic/TestService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,26 +181,7 @@ void TestService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
{
s_f8Pressed = true;


/*
auto* pActor = (Actor*)TESForm::GetById(0xFF000DA5);
pActor->SetWeaponDrawnEx(true);

//PlaceActorInWorld();

const auto pPlayerBaseForm = static_cast<TESNPC*>(PlayerCharacter::Get()->baseForm);

//const auto pNpc = TESNPC::Create(data, pPlayerBaseForm->GetChangeFlags());
auto pActor = Actor::Create(pPlayerBaseForm);
pActor->SaveInventory(0);

#if TP_SKYRIM64
auto& objManager = DefaultObjectManager::Get();
spdlog::info(objManager.isSomeActionReady);
#endif

TP_ASSERT(0, "{}", 5)
*/
PlaceActorInWorld();
}
}
else
Expand Down
3 changes: 2 additions & 1 deletion Code/encoding/Messages/ClientMessageFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <Messages/ProjectileLaunchRequest.h>
#include <Messages/ScriptAnimationRequest.h>
#include <Messages/DrawWeaponRequest.h>
#include <Messages/MountRequest.h>

using TiltedPhoques::UniquePtr;

Expand All @@ -56,7 +57,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;
}
Loading