Skip to content

Commit

Permalink
Merge pull request #683 from tiltedphoques/feat/vampireLordRevamped
Browse files Browse the repository at this point in the history
Beast form sync (Vampire Lord, werewolf)
  • Loading branch information
RobbeBryssinck authored May 26, 2024
2 parents 61af7d1 + 04f7e03 commit 9b620f1
Show file tree
Hide file tree
Showing 18 changed files with 170 additions and 33 deletions.
8 changes: 8 additions & 0 deletions Code/client/Events/BeastFormChangeEvent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

/**
* @brief Dispatched when the local player enters or leaves beast form (vampire lord, werewolf).
*/
struct BeastFormChangeEvent
{
};
8 changes: 0 additions & 8 deletions Code/client/Events/LeaveBeastFormEvent.h

This file was deleted.

1 change: 1 addition & 0 deletions Code/client/Games/Animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
TP_THIS_FUNCTION(TPerformAction, uint8_t, ActorMediator, TESActionData* apAction);
static TPerformAction* RealPerformAction;

// TODO: make scoped override
thread_local bool g_forceAnimation = false;

uint8_t TP_MAKE_THISCALL(HookPerformAction, ActorMediator, TESActionData* apAction)
Expand Down
47 changes: 47 additions & 0 deletions Code/client/Games/Skyrim/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <Services/PapyrusService.h>

#include <Forms/ActorValueInfo.h>
#include <Forms/TESRace.h>

#include <Effects/ValueModifierEffect.h>

Expand Down Expand Up @@ -579,12 +580,58 @@ void Actor::Reset() noexcept
s_pReset(this, 0, nullptr);
}

bool Actor::PlayIdle(TESIdleForm* apIdle) noexcept
{
PAPYRUS_FUNCTION(bool, Actor, PlayIdle, TESIdleForm*);
return s_pPlayIdle(this, apIdle);
}

void Actor::Respawn() noexcept
{
Resurrect(false);
Reset();
}

bool Actor::IsVampireLord() const noexcept
{
return race && race->formID == 0x200283A;
}

extern thread_local bool g_forceAnimation;

void Actor::FixVampireLordModel() noexcept
{
TESBoundObject* pObject = Cast<TESBoundObject>(TESForm::GetById(0x2011a84));
if (!pObject)
return;

{
ScopedInventoryOverride _;
AddObjectToContainer(pObject, nullptr, 1, nullptr);
}

EquipManager::Get()->Equip(this, pObject, nullptr, 1, nullptr, false, true, false, false);

g_forceAnimation = true;

BSFixedString str("isLevitating");
uint32_t isLevitating = GetAnimationVariableInt(&str);
spdlog::critical("isLevitating {}", isLevitating);

// By default, a loaded vampire lord is not levitating.
if (isLevitating)
{
BSFixedString levitation("LevitationToggle");
SendAnimationEvent(&levitation);
}

// TODO: weapon draw code does not seem to take care of this
//BSFixedString weapEquip("WeapEquip");
//SendAnimationEvent(&weapEquip);

g_forceAnimation = false;
}

TP_THIS_FUNCTION(TForceState, void, Actor, const NiPoint3&, float, float, TESObjectCELL*, TESWorldSpace*, bool);
static TForceState* RealForceState = nullptr;

Expand Down
4 changes: 4 additions & 0 deletions Code/client/Games/Skyrim/Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct ExPlayerCharacter;
struct ActorExtension;
struct AIProcess;
struct CombatController;
struct TESIdleForm;

struct Actor : TESObjectREFR
{
Expand Down Expand Up @@ -208,6 +209,7 @@ struct Actor : TESObjectREFR
[[nodiscard]] uint8_t GetPerkRank(uint32_t aPerkFormId) const noexcept;
[[nodiscard]] bool IsWearingBodyPiece() const noexcept;
[[nodiscard]] bool ShouldWearBodyPiece() const noexcept;
[[nodiscard]] bool IsVampireLord() const noexcept;

// Setters
void SetSpeed(float aSpeed) noexcept;
Expand Down Expand Up @@ -246,6 +248,8 @@ struct Actor : TESObjectREFR
void SetCombatTargetEx(Actor* apTarget) noexcept;
void StartCombat(Actor* apTarget) noexcept;
void StopCombat() noexcept;
bool PlayIdle(TESIdleForm* apIdle) noexcept;
void FixVampireLordModel() noexcept;

enum ActorFlags
{
Expand Down
5 changes: 3 additions & 2 deletions Code/client/Games/Skyrim/PlayerCharacter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
#include <Games/ActorExtension.h>

#include <Structs/Skyrim/AnimationGraphDescriptor_Master_Behavior.h>
#include <Structs/Skyrim/AnimationGraphDescriptor_VampireLordBehavior.h>

#include <Games/Overrides.h>

#include <Events/InventoryChangeEvent.h>
#include <Events/LeaveBeastFormEvent.h>
#include <Events/BeastFormChangeEvent.h>
#include <Events/AddExperienceEvent.h>
#include <Events/SetWaypointEvent.h>
#include <Events/RemoveWaypointEvent.h>
Expand Down Expand Up @@ -162,7 +163,7 @@ void TP_MAKE_THISCALL(HookSetBeastForm, void, void* apUnk1, void* apUnk2, bool a
if (!aEntering)
{
PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = AnimationGraphDescriptor_Master_Behavior::m_key;
World::Get().GetRunner().Trigger(LeaveBeastFormEvent());
World::Get().GetRunner().Trigger(BeastFormChangeEvent());
}

TiltedPhoques::ThisCall(RealSetBeastForm, apThis, apUnk1, apUnk2, aEntering);
Expand Down
14 changes: 14 additions & 0 deletions Code/client/Games/Skyrim/TESObjectREFR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,15 @@ void TESObjectREFR::EnableImpl() noexcept
TiltedPhoques::ThisCall(s_enable, this, false);
}

uint32_t TESObjectREFR::GetAnimationVariableInt(BSFixedString* apVariableName) noexcept
{
using ObjectReference = TESObjectREFR;

PAPYRUS_FUNCTION(uint32_t, ObjectReference, GetAnimationVariableInt, BSFixedString*);

return s_pGetAnimationVariableInt(this, apVariableName);
}

static thread_local bool s_cancelAnimationWaitEvent = false;

bool TESObjectREFR::PlayAnimationAndWait(BSFixedString* apAnimation, BSFixedString* apEventName) noexcept
Expand Down Expand Up @@ -578,6 +587,11 @@ bool TESObjectREFR::PlayAnimation(BSFixedString* apEventName) noexcept
return result;
}

bool TESObjectREFR::SendAnimationEvent(BSFixedString* apEventName) noexcept
{
return animationGraphHolder.SendAnimationEvent(apEventName);
}

bool TP_MAKE_THISCALL(HookPlayAnimation, void, uint32_t auiStackID, TESObjectREFR* apSelf, BSFixedString* apEventName)
{
spdlog::debug("EventName: {}", apEventName->AsAscii());
Expand Down
2 changes: 2 additions & 0 deletions Code/client/Games/Skyrim/TESObjectREFR.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ struct TESObjectREFR : TESForm

void SaveAnimationVariables(AnimationVariables& aWriter) const noexcept;
void LoadAnimationVariables(const AnimationVariables& aReader) const noexcept;
uint32_t GetAnimationVariableInt(BSFixedString* apVariableName) noexcept;

void RemoveAllItems() noexcept;
void Delete() const noexcept;
Expand All @@ -175,6 +176,7 @@ struct TESObjectREFR : TESForm
void MoveTo(TESObjectCELL* apCell, const NiPoint3& acPosition) const noexcept;
void PayGold(int32_t aAmount) noexcept;
void PayGoldToContainer(TESObjectREFR* pContainer, int32_t aAmount) noexcept;
bool SendAnimationEvent(BSFixedString* apEventName) noexcept;

bool Activate(TESObjectREFR* apActivator, uint8_t aUnk1, TESBoundObject* apObjectToGet, int32_t aCount, char aDefaultProcessing) noexcept;

Expand Down
7 changes: 4 additions & 3 deletions Code/client/Services/CharacterService.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct NotifyMount;
struct InitPackageEvent;
struct NotifyNewPackage;
struct NotifyRespawn;
struct LeaveBeastFormEvent;
struct BeastFormChangeEvent;
struct AddExperienceEvent;
struct NotifySyncExperience;
struct DialogueEvent;
Expand Down Expand Up @@ -78,7 +78,7 @@ struct CharacterService
void OnInitPackageEvent(const InitPackageEvent& acEvent) const noexcept;
void OnNotifyNewPackage(const NotifyNewPackage& acMessage) const noexcept;
void OnNotifyRespawn(const NotifyRespawn& acMessage) const noexcept;
void OnLeaveBeastForm(const LeaveBeastFormEvent& acEvent) const noexcept;
void OnBeastFormChange(const BeastFormChangeEvent& acEvent) const noexcept;
void OnAddExperienceEvent(const AddExperienceEvent& acEvent) noexcept;
void OnNotifySyncExperience(const NotifySyncExperience& acMessage) noexcept;
void OnDialogueEvent(const DialogueEvent& acEvent) noexcept;
Expand Down Expand Up @@ -114,6 +114,7 @@ struct CharacterService

float m_cachedExperience = 0.f;

// TODO: revamp this, read the local anim var like vampire lord?
struct WeaponDrawData
{
WeaponDrawData() = default;
Expand Down Expand Up @@ -147,7 +148,7 @@ struct CharacterService
entt::scoped_connection m_initPackageConnection;
entt::scoped_connection m_newPackageConnection;
entt::scoped_connection m_notifyRespawnConnection;
entt::scoped_connection m_leaveBeastFormConnection;
entt::scoped_connection m_beastFormChangeConnection;
entt::scoped_connection m_addExperienceEventConnection;
entt::scoped_connection m_syncExperienceConnection;
entt::scoped_connection m_dialogueEventConnection;
Expand Down
10 changes: 4 additions & 6 deletions Code/client/Services/Debug/DebugService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ void DebugService::OnMoveActor(const MoveActorEvent& acEvent) noexcept
moveData.position = acEvent.Position;
}

extern thread_local bool g_forceAnimation;

void DebugService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
{
if (!BSGraphics::GetMainWindow()->IsForeground())
Expand Down Expand Up @@ -197,11 +199,7 @@ void DebugService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
{
s_f7Pressed = true;

static char s_address[256] = "de.playtogether.gg:10100";
if (!m_transport.IsOnline())
m_transport.Connect(s_address);
else
m_transport.Close();
//
}
}
else
Expand All @@ -213,7 +211,7 @@ void DebugService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
{
s_f8Pressed = true;

PlaceActorInWorld();
//PlaceActorInWorld();
}
}
else
Expand Down
44 changes: 33 additions & 11 deletions Code/client/Services/Generic/CharacterService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include <Events/DisconnectedEvent.h>
#include <Events/MountEvent.h>
#include <Events/InitPackageEvent.h>
#include <Events/LeaveBeastFormEvent.h>
#include <Events/BeastFormChangeEvent.h>
#include <Events/AddExperienceEvent.h>
#include <Events/DialogueEvent.h>
#include <Events/SubtitleEvent.h>
Expand Down Expand Up @@ -95,7 +95,7 @@ CharacterService::CharacterService(World& aWorld, entt::dispatcher& aDispatcher,
m_newPackageConnection = m_dispatcher.sink<NotifyNewPackage>().connect<&CharacterService::OnNotifyNewPackage>(this);

m_notifyRespawnConnection = m_dispatcher.sink<NotifyRespawn>().connect<&CharacterService::OnNotifyRespawn>(this);
m_leaveBeastFormConnection = m_dispatcher.sink<LeaveBeastFormEvent>().connect<&CharacterService::OnLeaveBeastForm>(this);
m_beastFormChangeConnection = m_dispatcher.sink<BeastFormChangeEvent>().connect<&CharacterService::OnBeastFormChange>(this);

m_addExperienceEventConnection = m_dispatcher.sink<AddExperienceEvent>().connect<&CharacterService::OnAddExperienceEvent>(this);
m_syncExperienceConnection = m_dispatcher.sink<NotifySyncExperience>().connect<&CharacterService::OnNotifySyncExperience>(this);
Expand Down Expand Up @@ -404,7 +404,7 @@ void CharacterService::OnCharacterSpawn(const CharacterSpawnRequest& acMessage)

if (waitingItor != std::end(waitingView))
{
spdlog::info("Character with form id {:X} already has a spawn request in progress.", acMessage.FormId);
spdlog::info("Character with form id {:X} already has a spawn request in progress.", cActorId);
return;
}

Expand Down Expand Up @@ -634,23 +634,33 @@ void CharacterService::OnRemoveCharacter(const NotifyRemoveCharacter& acMessage)

void CharacterService::OnNotifyRespawn(const NotifyRespawn& acMessage) const noexcept
{
Actor* pActor = Utils::GetByServerId<Actor>(acMessage.ActorId);
if (!pActor)
auto view = m_world.view<FormIdComponent, RemoteComponent>();
const auto entityIt = std::find_if(view.begin(), view.end(), [view, id = acMessage.ActorId](auto aEntity) { return view.get<RemoteComponent>(aEntity).Id == id; });

if (entityIt == view.end())
{
spdlog::error("{}: could not find actor server id {:X}", __FUNCTION__, acMessage.ActorId);
spdlog::error("Actor to respawn not found in: {:X}", acMessage.ActorId);
return;
}

pActor->Delete();
const auto cId = *entityIt;

auto& formIdComponent = view.get<FormIdComponent>(cId);
CancelServerAssignment(*entityIt, formIdComponent.Id);

if (m_world.all_of<FormIdComponent>(cId))
m_world.remove<FormIdComponent>(cId);

// TODO: delete components?
if (m_world.orphan(cId))
m_world.destroy(cId);

RequestRespawn request;
request.ActorId = acMessage.ActorId;

m_transport.Send(request);
}

void CharacterService::OnLeaveBeastForm(const LeaveBeastFormEvent& acEvent) const noexcept
void CharacterService::OnBeastFormChange(const BeastFormChangeEvent& acEvent) const noexcept
{
auto view = m_world.view<FormIdComponent>();

Expand All @@ -669,8 +679,15 @@ void CharacterService::OnLeaveBeastForm(const LeaveBeastFormEvent& acEvent) cons
request.ActorId = serverId;

Actor* pActor = Utils::GetByServerId<Actor>(serverId);
if (pActor)
pActor->Delete();
if (!pActor)
return;

TESNPC* pNpc = Cast<TESNPC>(pActor->baseForm);
if (!pNpc)
return;

pNpc->Serialize(&request.AppearanceBuffer);
request.ChangeFlags = pNpc->GetChangeFlags();

m_transport.Send(request);
}
Expand Down Expand Up @@ -1512,6 +1529,11 @@ void CharacterService::RunRemoteUpdates() noexcept
if (pActor->IsDead() != waitingFor3D.SpawnRequest.IsDead)
waitingFor3D.SpawnRequest.IsDead ? pActor->Kill() : pActor->Respawn();

#if TP_SKYRIM64
if (pActor->IsVampireLord())
pActor->FixVampireLordModel();
#endif

toRemove.push_back(entity);

spdlog::info("Applied 3D for actor, form id: {:X}", pActor->formID);
Expand Down
2 changes: 2 additions & 0 deletions Code/client/Services/Generic/InventoryService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ void InventoryService::OnEquipmentChangeEvent(const EquipmentChangeEvent& acEven
request.CurrentInventory = pActor->GetEquipment();

m_transport.Send(request);

spdlog::info("Sending equipment request, item: {:X}, count: {}, target object: {:X}", acEvent.ItemId, acEvent.Count, acEvent.ActorId);
}

void InventoryService::OnNotifyInventoryChanges(const NotifyInventoryChanges& acMessage) noexcept
Expand Down
1 change: 1 addition & 0 deletions Code/client/Services/Generic/MagicService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <Actor.h>
#include <Magic/ActorMagicCaster.h>
#include <Games/ActorExtension.h>
#include <EquipManager.h>

#include <Structs/Skyrim/AnimationGraphDescriptor_VampireLordBehavior.h>
#include <Structs/Skyrim/AnimationGraphDescriptor_WerewolfBehavior.h>
Expand Down
Loading

0 comments on commit 9b620f1

Please sign in to comment.