Skip to content

Commit

Permalink
refact(skymp5-server): eliminate duplicated code and remove macro def…
Browse files Browse the repository at this point in the history
…initions for Papyrus Classes (#2324)
  • Loading branch information
Wedmer authored Feb 16, 2025
1 parent 097f3fa commit 7f36752
Show file tree
Hide file tree
Showing 48 changed files with 389 additions and 326 deletions.
30 changes: 0 additions & 30 deletions skymp5-server/cpp/server_guest_lib/SpSnippetFunctionGen.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include "MpActor.h"
#include "SpSnippet.h"
#include "SpSnippetFunctionGen.h"
#include "papyrus-vm/VirtualMachine.h"
#include <cstdio>

Expand All @@ -13,32 +12,3 @@ class SpSnippetFunctionGen

static uint32_t GetFormId(VarValue varValue);
};

// TODO: unhardcode mode
#define DEFINE_STATIC_SPSNIPPET(name) \
VarValue name(VarValue self, const std::vector<VarValue>& arguments) \
{ \
if (auto actor = compatibilityPolicy->GetDefaultActor( \
GetName(), #name, self.GetMetaStackId())) { \
auto s = SpSnippetFunctionGen::SerializeArguments(arguments, actor); \
SpSnippet(GetName(), (#name), s.data()) \
.Execute(actor, SpSnippetMode::kNoReturnResult); \
} \
return VarValue::None(); \
}

// TODO: unhardcode mode
#define DEFINE_METHOD_SPSNIPPET(name) \
VarValue name(VarValue self, const std::vector<VarValue>& arguments) \
{ \
if (auto actor = compatibilityPolicy->GetDefaultActor( \
GetName(), #name, self.GetMetaStackId())) { \
auto s = SpSnippetFunctionGen::SerializeArguments(arguments, actor); \
auto promise = SpSnippet(GetName(), (#name), s.data(), \
SpSnippetFunctionGen::GetFormId(self)) \
.Execute(actor, SpSnippetMode::kReturnResult); \
return VarValue(promise); \
} \
\
return VarValue::None(); \
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "IPapyrusClass.h"
#include "SpSnippetFunctionGen.h"

VarValue IPapyrusClassBase::MakeSPSnippetPromise(
const char* script, const char* name,
std::shared_ptr<IPapyrusCompatibilityPolicy> policy, VarValue self,
const std::vector<VarValue>& arguments, bool method, bool returns,
VarValue defaultResult)
{
if (auto actor =
policy->GetDefaultActor(script, name, self.GetMetaStackId())) {
auto s = SpSnippetFunctionGen::SerializeArguments(arguments, actor);
auto promise =
SpSnippet(script, name, s.data(),
method ? SpSnippetFunctionGen::GetFormId(self) : 0)
.Execute(actor,
(returns ? SpSnippetMode::kReturnResult
: SpSnippetMode::kNoReturnResult));
if (returns)
return VarValue(promise);
}
return defaultResult;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "SpSnippetFunctionGen.h"
#include "papyrus-vm/VirtualMachine.h"
#include "script_compatibility_policies/IPapyrusCompatibilityPolicy.h"

Expand All @@ -9,9 +10,17 @@ class IPapyrusClassBase

virtual void Register(
VirtualMachine& vm,
std::shared_ptr<IPapyrusCompatibilityPolicy> compatibilityPolicy) = 0;
std::shared_ptr<IPapyrusCompatibilityPolicy> policy) = 0;

virtual ~IPapyrusClassBase() = default;
static VarValue MakeSPSnippetPromise(
const char* script, const char* name,
std::shared_ptr<IPapyrusCompatibilityPolicy> policy, VarValue self,
const std::vector<VarValue>& arguments, bool method = false,
bool returns = false, VarValue defaultResult = VarValue::None());

public:
std::shared_ptr<IPapyrusCompatibilityPolicy> compatibilityPolicy;
};

template <class T>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "PapyrusActor.h"

#include "MpActor.h"
#include "SpSnippetFunctionGen.h"
#include "script_objects/EspmGameObject.h"
#include "script_objects/MpFormGameObject.h"

#include "EvaluateTemplate.h"
#include "SpSnippetFunctionGen.h"
#include "papyrus-vm/CIString.h"
#include <algorithm>

Expand All @@ -25,6 +25,34 @@ espm::ActorValue ConvertToAV(CIString actorValueName)
}
}

VarValue PapyrusActor::DrawWeapon(VarValue self,
const std::vector<VarValue>& arguments)
{
return MakeSPSnippetPromise(GetName(), "DrawWeapon", compatibilityPolicy,
self, arguments, true, true);
}

VarValue PapyrusActor::UnequipAll(VarValue self,
const std::vector<VarValue>& arguments)
{
return MakeSPSnippetPromise(GetName(), "UnequipAll", compatibilityPolicy,
self, arguments, true, true);
}

VarValue PapyrusActor::PlayIdle(VarValue self,
const std::vector<VarValue>& arguments)
{
return MakeSPSnippetPromise(GetName(), "PlayIdle", compatibilityPolicy, self,
arguments, true, true);
}

VarValue PapyrusActor::GetSitState(VarValue self,
const std::vector<VarValue>& arguments)
{
return MakeSPSnippetPromise(GetName(), "GetSitState", compatibilityPolicy,
self, arguments, true, true);
}

VarValue PapyrusActor::IsWeaponDrawn(VarValue self,
const std::vector<VarValue>& arguments)
{
Expand Down
12 changes: 4 additions & 8 deletions skymp5-server/cpp/server_guest_lib/script_classes/PapyrusActor.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
#pragma once
#include "IPapyrusClass.h"
#include "SpSnippetFunctionGen.h"
#include "script_objects/EspmGameObject.h"

class PapyrusActor final : public IPapyrusClass<PapyrusActor>
{
public:
const char* GetName() override { return "Actor"; }

DEFINE_METHOD_SPSNIPPET(DrawWeapon);
DEFINE_METHOD_SPSNIPPET(UnequipAll);
DEFINE_METHOD_SPSNIPPET(PlayIdle);
DEFINE_METHOD_SPSNIPPET(GetSitState);
VarValue DrawWeapon(VarValue self, const std ::vector<VarValue>& arguments);
VarValue UnequipAll(VarValue self, const std ::vector<VarValue>& arguments);
VarValue PlayIdle(VarValue self, const std ::vector<VarValue>& arguments);
VarValue GetSitState(VarValue self, const std ::vector<VarValue>& arguments);

VarValue IsWeaponDrawn(VarValue self,
const std::vector<VarValue>& arguments);
Expand Down Expand Up @@ -68,6 +66,4 @@ class PapyrusActor final : public IPapyrusClass<PapyrusActor>

void Register(VirtualMachine& vm,
std::shared_ptr<IPapyrusCompatibilityPolicy> policy) override;

std::shared_ptr<IPapyrusCompatibilityPolicy> compatibilityPolicy;
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "PapyrusCell.h"
#include "script_objects/EspmGameObject.h"
#include "spdlog/spdlog.h"

VarValue PapyrusCell::IsAttached(VarValue self,
const std::vector<VarValue>& arguments)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#pragma once
#include "IPapyrusClass.h"
#include "SpSnippetFunctionGen.h"
#include "script_objects/EspmGameObject.h"

class PapyrusCell final : public IPapyrusClass<PapyrusCell>
{
Expand All @@ -14,6 +12,4 @@ class PapyrusCell final : public IPapyrusClass<PapyrusCell>

void Register(VirtualMachine& vm,
std::shared_ptr<IPapyrusCompatibilityPolicy> policy) override;

std::shared_ptr<IPapyrusCompatibilityPolicy> compatibilityPolicy;
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
#include "PapyrusFormList.h"
#include "PapyrusGame.h"
#include "PapyrusKeyword.h"
#include "PapyrusLeveledActor.h"
#include "PapyrusLeveledItem.h"
#include "PapyrusLeveledSpell.h"
#include "PapyrusMessage.h"
#include "PapyrusNetImmerse.h"
#include "PapyrusObjectReference.h"
Expand Down Expand Up @@ -45,7 +47,9 @@ PapyrusClassesFactory::CreateAndRegister(
result.emplace_back(std::make_unique<PapyrusPotion>());
result.emplace_back(std::make_unique<PapyrusVisualEffect>());
result.emplace_back(std::make_unique<PapyrusQuest>());
result.emplace_back(std::make_unique<PapyrusLeveledActor>());
result.emplace_back(std::make_unique<PapyrusLeveledItem>());
result.emplace_back(std::make_unique<PapyrusLeveledSpell>());

for (auto& papyrusClass : result) {
papyrusClass->Register(vm, compatibilityPolicy);
Expand Down
15 changes: 15 additions & 0 deletions skymp5-server/cpp/server_guest_lib/script_classes/PapyrusDebug.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
#include "PapyrusDebug.h"

#include "MpActor.h"
#include "SpSnippetFunctionGen.h"
#include "script_objects/MpFormGameObject.h"

VarValue PapyrusDebug::Notification(VarValue self,
const std::vector<VarValue>& arguments)
{
return MakeSPSnippetPromise(GetName(), "Notification", compatibilityPolicy,
self, arguments);
}

VarValue PapyrusDebug::MessageBox(VarValue self,
const std::vector<VarValue>& arguments)
{
return MakeSPSnippetPromise(GetName(), "MessageBox", compatibilityPolicy,
self, arguments);
}

VarValue PapyrusDebug::SendAnimationEvent(
VarValue, const std::vector<VarValue>& arguments)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#pragma once
#include "IPapyrusClass.h"
#include "SpSnippetFunctionGen.h"

class PapyrusDebug final : public IPapyrusClass<PapyrusDebug>
{
public:
const char* GetName() override { return "Debug"; }

DEFINE_STATIC_SPSNIPPET(Notification);
DEFINE_STATIC_SPSNIPPET(MessageBox);
VarValue Notification(VarValue self,
const std ::vector<VarValue>& arguments);
VarValue MessageBox(VarValue self, const std ::vector<VarValue>& arguments);

VarValue SendAnimationEvent(VarValue self,
const std::vector<VarValue>& arguments);
Expand All @@ -17,6 +17,4 @@ class PapyrusDebug final : public IPapyrusClass<PapyrusDebug>

void Register(VirtualMachine& vm,
std::shared_ptr<IPapyrusCompatibilityPolicy> policy) override;

std::shared_ptr<IPapyrusCompatibilityPolicy> compatibilityPolicy;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "PapyrusEffectBase.h"

#include "SpSnippetFunctionGen.h"
#include "WorldState.h"
#include "script_objects/EspmGameObject.h"
#include "script_objects/MpFormGameObject.h"

PapyrusEffectBase::PapyrusEffectBase(const std::string& name)
: strName(name)
{
}

VarValue PapyrusEffectBase::Play(VarValue self,
const std::vector<VarValue>& arguments)
{
Helper(self, "Play", arguments);
return VarValue::None();
}

VarValue PapyrusEffectBase::Stop(VarValue self,
const std::vector<VarValue>& arguments)
{
Helper(self, "Stop", arguments);
return VarValue::None();
}

void PapyrusEffectBase::Register(
VirtualMachine& vm, std::shared_ptr<IPapyrusCompatibilityPolicy> policy)
{
AddMethod(vm, "Play", &PapyrusEffectBase::Play);
AddMethod(vm, "Stop", &PapyrusEffectBase::Stop);
}

void PapyrusEffectBase::Helper(VarValue& self, const char* funcName,
const std::vector<VarValue>& arguments)
{
const auto& selfRec = GetRecordPtr(self);
if (selfRec.rec) {
if (arguments.size() < 1) {
throw std::runtime_error(std::string(funcName) +
" requires at least one argument");
}
if (auto actorForm = GetFormPtr<MpObjectReference>(arguments[0])) {
for (auto listener : actorForm->GetActorListeners()) {
SpSnippet(
GetName(), funcName,
SpSnippetFunctionGen::SerializeArguments(arguments, listener).data(),
selfRec.ToGlobalId(selfRec.rec->GetId()))
.Execute(listener, SpSnippetMode::kNoReturnResult);
// Workaround to use this function on player clone
if (actorForm->GetFormId() == listener->GetFormId()) {
SpSnippet(GetName(), funcName,
SpSnippetFunctionGen::SerializeArguments(arguments).data(),
selfRec.ToGlobalId(selfRec.rec->GetId()))
.Execute(listener, SpSnippetMode::kNoReturnResult);
}
}
}
} else {
throw std::runtime_error(std::string(funcName) + ": can't get object!");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once
#include "IPapyrusClass.h"

class PapyrusEffectBase : public IPapyrusClass<PapyrusEffectBase>
{
public:
PapyrusEffectBase(const std::string& name);
const char* GetName() override { return strName.c_str(); }
VarValue Play(VarValue self, const std::vector<VarValue>& arguments);
VarValue Stop(VarValue self, const std::vector<VarValue>& arguments);

void Register(VirtualMachine& vm,
std::shared_ptr<IPapyrusCompatibilityPolicy> policy) override;

private:
void Helper(VarValue& self, const char* funcName,
const std::vector<VarValue>& arguments);

private:
std::string strName;
};
Original file line number Diff line number Diff line change
@@ -1,50 +1,6 @@
#include "PapyrusEffectShader.h"

#include "WorldState.h"
#include "script_objects/EspmGameObject.h"
#include "script_objects/MpFormGameObject.h"

VarValue PapyrusEffectShader::Play(VarValue self,
const std::vector<VarValue>& arguments)
{
Helper(self, "Play", arguments);
return VarValue::None();
}

VarValue PapyrusEffectShader::Stop(VarValue self,
const std::vector<VarValue>& arguments)
{
Helper(self, "Stop", arguments);
return VarValue::None();
}

// This is exact copy of PapyrusVisualEffect::Helper
void PapyrusEffectShader::Helper(VarValue& self, const char* funcName,
const std::vector<VarValue>& arguments)
PapyrusEffectShader::PapyrusEffectShader()
: PapyrusEffectBase("EffectShader")
{
const auto& selfRec = GetRecordPtr(self);
if (selfRec.rec) {
if (arguments.size() < 1) {
throw std::runtime_error(std::string(funcName) +
" requires at least one argument");
}
if (auto actorForm = GetFormPtr<MpObjectReference>(arguments[0])) {
for (auto listener : actorForm->GetActorListeners()) {
SpSnippet(
GetName(), funcName,
SpSnippetFunctionGen::SerializeArguments(arguments, listener).data(),
selfRec.ToGlobalId(selfRec.rec->GetId()))
.Execute(listener, SpSnippetMode::kNoReturnResult);
// Workaround to use this function on player clone
if (actorForm->GetFormId() == listener->GetFormId()) {
SpSnippet(GetName(), funcName,
SpSnippetFunctionGen::SerializeArguments(arguments).data(),
selfRec.ToGlobalId(selfRec.rec->GetId()))
.Execute(listener, SpSnippetMode::kNoReturnResult);
}
}
}
} else {
throw std::runtime_error(std::string(funcName) + ": can't get object!");
}
}
Loading

0 comments on commit 7f36752

Please sign in to comment.