bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret) { if (ActionFunc != nullptr) { ActionCycles.Clock(); VMValue params[3] = { self, stateowner, VMValue(info) }; // If the function returns a state, store it at *stateret. // If it doesn't return a state but stateret is non-nullptr, we need // to set *stateret to nullptr. if (stateret != nullptr) { *stateret = nullptr; if (ActionFunc->Proto == nullptr || ActionFunc->Proto->ReturnTypes.Size() == 0 || ActionFunc->Proto->ReturnTypes[0] != TypeState) { stateret = nullptr; } } try { if (stateret == nullptr) { VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0); } else { VMReturn ret; ret.PointerAt((void **)stateret); VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1); } } catch (CVMAbortException &err) { err.MaybePrintMessage(); const char *callinfo = ""; if (info != nullptr && info->mStateType == STATE_Psprite) { if (stateowner->IsKindOf(NAME_Weapon) && stateowner != self) callinfo = "weapon "; else callinfo = "overlay "; } err.stacktrace.AppendFormat("Called from %sstate %s in %s\n", callinfo, FState::StaticGetStateName(this).GetChars(), stateowner->GetClass()->TypeName.GetChars()); throw; throw; } ActionCycles.Unclock(); return true; } else { return false; } }
DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr) { auto c = PClass::FindClass(gameinfo.MessageBoxClass); if (!c->IsDescendantOf(NAME_MessageBoxMenu)) c = PClass::FindClass(NAME_MessageBoxMenu); auto p = c->CreateNew(); FString namestr = message; IFVIRTUALPTRNAME(p, NAME_MessageBoxMenu, Init) { VMValue params[] = { p, parent, &namestr, messagemode, playsound, action.GetIndex(), reinterpret_cast<void*>(handler) }; VMCall(func, params, countof(params), nullptr, 0); return (DMenu*)p; }
double AInventory::GetSpeedFactor() { double factor = 1.; auto self = this; while (self != nullptr) { IFVIRTUALPTR(self, AInventory, GetSpeedFactor) { VMValue params[1] = { (DObject*)self }; double retval; VMReturn ret(&retval); VMCall(func, params, 1, &ret, 1); factor *= retval; } self = self->Inventory; }
void ezExpressionVM::Execute(const ezExpressionByteCode& byteCode, ezArrayPtr<const ezExpression::Stream> inputs, ezArrayPtr<ezExpression::Stream> outputs, ezUInt32 uiNumInstances) { // Input mapping { auto inputNames = byteCode.GetInputs(); m_InputMapping.Clear(); m_InputMapping.Reserve(inputNames.GetCount()); for (auto& inputName : inputNames) { bool bInputFound = false; for (ezUInt32 i = 0; i < inputs.GetCount(); ++i) { if (inputs[i].m_sName == inputName) { inputs[i].ValidateDataSize(uiNumInstances, "Input"); m_InputMapping.PushBack(i); bInputFound = true; break; } } EZ_ASSERT_DEV(bInputFound, "Bytecode expects an input '{0}'", inputName); } } // Output mapping { auto outputNames = byteCode.GetOutputs(); m_OutputMapping.Clear(); m_OutputMapping.Reserve(outputNames.GetCount()); for (auto& outputName : outputNames) { bool bOutputFound = false; for (ezUInt32 i = 0; i < outputs.GetCount(); ++i) { if (outputs[i].m_sName == outputName) { outputs[i].ValidateDataSize(uiNumInstances, "Output"); m_OutputMapping.PushBack(i); bOutputFound = true; break; } } EZ_ASSERT_DEV(bOutputFound, "Bytecode expects an output '{0}'", outputName); } } ezSimdVec4f* pRegisters = m_Registers.GetData(); const ezUInt32 uiNumRegisters = (uiNumInstances + 3) / 4; const ezUInt32 uiLastInstanceIndex = uiNumInstances - 1; const ezUInt32 uiTotalNumRegisters = byteCode.GetNumTempRegisters() * uiNumRegisters; if (uiTotalNumRegisters > m_Registers.GetCount()) { EZ_REPORT_FAILURE("Not enough registers to execute bytecode. Needs {0} but only has {1}.", uiTotalNumRegisters, m_Registers.GetCount()); return; } // Execute bytecode const ezExpressionByteCode::StorageType* pByteCode = byteCode.GetByteCode(); const ezExpressionByteCode::StorageType* pByteCodeEnd = byteCode.GetByteCodeEnd(); while (pByteCode < pByteCodeEnd) { ezExpressionByteCode::OpCode::Enum opCode = ezExpressionByteCode::GetOpCode(pByteCode); switch (opCode) { // unary case ezExpressionByteCode::OpCode::Abs_R: VMOperation1(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& x) { return x.Abs(); }); break; case ezExpressionByteCode::OpCode::Sqrt_R: VMOperation1(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& x) { return x.GetSqrt(); }); break; case ezExpressionByteCode::OpCode::Mov_R: VMOperation1(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& x) { return x; }); break; case ezExpressionByteCode::OpCode::Mov_C: VMOperation1_C(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& x) { return x; }); break; case ezExpressionByteCode::OpCode::Mov_I: VMLoadInput(pByteCode, pRegisters, uiNumRegisters, inputs, m_InputMapping); break; case ezExpressionByteCode::OpCode::Mov_O: VMStoreOutput(pByteCode, pRegisters, uiNumRegisters, outputs, m_OutputMapping); break; // binary case ezExpressionByteCode::OpCode::Add_RR: VMOperation2(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a + b; }); break; case ezExpressionByteCode::OpCode::Add_CR: VMOperation2_C(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a + b; }); break; case ezExpressionByteCode::OpCode::Sub_RR: VMOperation2(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a - b; }); break; case ezExpressionByteCode::OpCode::Sub_CR: VMOperation2_C(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a - b; }); break; case ezExpressionByteCode::OpCode::Mul_RR: VMOperation2(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompMul(b); }); break; case ezExpressionByteCode::OpCode::Mul_CR: VMOperation2_C(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompMul(b); }); break; case ezExpressionByteCode::OpCode::Div_RR: VMOperation2(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompDiv(b); }); break; case ezExpressionByteCode::OpCode::Div_CR: VMOperation2_C(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompDiv(b); }); break; case ezExpressionByteCode::OpCode::Min_RR: VMOperation2(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompMin(b); }); break; case ezExpressionByteCode::OpCode::Min_CR: VMOperation2_C(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompMin(b); }); break; case ezExpressionByteCode::OpCode::Max_RR: VMOperation2(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompMax(b); }); break; case ezExpressionByteCode::OpCode::Max_CR: VMOperation2_C(pByteCode, pRegisters, uiNumRegisters, [](const ezSimdVec4f& a, const ezSimdVec4f& b) { return a.CompMax(b); }); break; // call case ezExpressionByteCode::OpCode::Call: VMCall(pByteCode, pRegisters, uiNumRegisters); break; default: EZ_ASSERT_NOT_IMPLEMENTED; return; } } }
IFVM(PlayerPawn, BringUpWeapon) { VMValue param = player->mo; VMCall(func, ¶m, 1, nullptr, 0); }