Skip to content

Commit

Permalink
fix(papyrus-vm): fix CallParent opcode (#1924)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pospelove authored Apr 19, 2024
1 parent fa1957a commit fed1223
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 7 deletions.
4 changes: 3 additions & 1 deletion papyrus-vm/include/papyrus-vm/VirtualMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ class VirtualMachine

VarValue CallMethod(IGameObject* self, const char* methodName,
std::vector<VarValue>& arguments,
std::shared_ptr<StackIdHolder> stackIdHolder = nullptr);
std::shared_ptr<StackIdHolder> stackIdHolder = nullptr,
const std::vector<std::shared_ptr<ActivePexInstance>>*
activePexInstancesOverride = nullptr);

VarValue CallStatic(const std::string& className,
const std::string& functionName,
Expand Down
36 changes: 32 additions & 4 deletions papyrus-vm/src/papyrus-vm-lib/ActivePexInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,36 @@ void ActivePexInstance::ExecuteOpCode(ExecutionContext* ctx, uint8_t op,
parentInstance ? parentInstance->GetSourcePexName() : "";
try {
auto gameObject = static_cast<IGameObject*>(activeInstanceOwner);

std::vector<std::shared_ptr<ActivePexInstance>>
activePexInstancesForCallParent;
if (gameObject) {
activePexInstancesForCallParent =
gameObject->ListActivePexInstances();

std::string toFind = sourcePex.source;

for (auto& v : activePexInstancesForCallParent) {
if (!Utils::stricmp(v->GetSourcePexName().data(), toFind.data())) {
v = parentInstance;
spdlog::trace("CallParent: redirecting method call {} -> {}",
toFind, parentName);
}
}
}

if (spdlog::should_log(spdlog::level::trace)) {
std::vector<std::string> argsForCallStr;
for (auto v : argsForCall) {
argsForCallStr.push_back(v.ToString());
}
spdlog::trace("CallParent: calling with args {}",
fmt::join(argsForCallStr, ", "));
}

auto res = parentVM->CallMethod(gameObject, (const char*)(*args[0]),
argsForCall);
argsForCall, ctx->stackIdHolder,
&activePexInstancesForCallParent);
if (EnsureCallResultIsSynchronous(res, ctx))
*args[1] = res;
} catch (std::exception& e) {
Expand All @@ -390,7 +418,7 @@ void ActivePexInstance::ExecuteOpCode(ExecutionContext* ctx, uint8_t op,
// BYOHRelationshipAdoptionPetDoorTrigger
if (args[0]->GetType() != VarValue::kType_String &&
args[0]->GetType() != VarValue::kType_Identifier)
throw std::runtime_error("Anomally in CallMethod. String expected");
throw std::runtime_error("Anomaly in CallMethod. String expected");

std::string functionName = (const char*)(*args[0]);
static const std::string nameOnBeginState = "onBeginState";
Expand Down Expand Up @@ -736,8 +764,8 @@ ActivePexInstance::TransformInstructions(
dereferenceStart = 2;
break;
case OpcodesImplementation::Opcodes::op_CallParent:
// TODO?
dereferenceStart = 0;
// Do not dereference functionName
dereferenceStart = 1;
break;
case OpcodesImplementation::Opcodes::op_PropGet:
case OpcodesImplementation::Opcodes::op_PropSet:
Expand Down
12 changes: 10 additions & 2 deletions papyrus-vm/src/papyrus-vm-lib/VirtualMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ int32_t StackIdHolder::GetStackId() const
VarValue VirtualMachine::CallMethod(
IGameObject* selfObj, const char* methodName,
std::vector<VarValue>& arguments,
std::shared_ptr<StackIdHolder> stackIdHolder)
std::shared_ptr<StackIdHolder> stackIdHolder,
const std::vector<std::shared_ptr<ActivePexInstance>>*
activePexInstancesOverride)
{
if (!stackIdHolder) {
stackIdHolder.reset(new StackIdHolder(*this));
Expand All @@ -152,7 +154,13 @@ VarValue VirtualMachine::CallMethod(
return VarValue::None();
}

for (auto& activeScript : selfObj->ListActivePexInstances()) {
const auto& instances = activePexInstancesOverride
? *activePexInstancesOverride
: selfObj->ListActivePexInstances();

// TODO: in theory we shouldn't iterate over all scripts, but only use the
// current one
for (auto& activeScript : instances) {
FunctionInfo functionInfo;

if (!Utils::stricmp(methodName, "GotoState") ||
Expand Down

0 comments on commit fed1223

Please sign in to comment.