void Interpreter::doSuperSend(long bytecodeIndex) { VMSymbol* signature = static_cast<VMSymbol*>(method->GetConstant(bytecodeIndex)); VMFrame* ctxt = GetFrame()->GetOuterContext(); VMMethod* realMethod = ctxt->GetMethod(); VMClass* holder = realMethod->GetHolder(); VMClass* super = holder->GetSuperClass(); VMInvokable* invokable = static_cast<VMInvokable*>(super->LookupInvokable(signature)); if (invokable != nullptr) (*invokable)(GetFrame()); else { long numOfArgs = Signature::GetNumberOfArguments(signature); vm_oop_t receiver = GetFrame()->GetStackElement(numOfArgs - 1); VMArray* argumentsArray = GetUniverse()->NewArray(numOfArgs); for (long i = numOfArgs - 1; i >= 0; --i) { vm_oop_t o = GetFrame()->Pop(); argumentsArray->SetIndexableField(i, o); } vm_oop_t arguments[] = {signature, argumentsArray}; AS_OBJ(receiver)->Send(doesNotUnderstand, arguments, 2); } }
bool SetNodeLocalRotationEuler(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeName, VMArray<float> inArray, bool firstPerson) { NiAVObject * object = ResolveNode(obj, nodeName, firstPerson); if(object && inArray.Length() == 3) { float heading, attitude, bank; inArray.Get(&heading, 0); inArray.Get(&attitude, 1); inArray.Get(&bank, 2); // Degrees to radians heading *= MATH_PI / 180; attitude *= MATH_PI / 180; bank *= MATH_PI / 180; object->m_localTransform.rot.SetEulerAngles(heading, attitude, bank); BSTaskPool * taskPool = BSTaskPool::GetSingleton(); if(taskPool) taskPool->UpdateWorldData(object); return true; } return false; }
// 配列の要素の順番を反転させる。引数の配列自体を変更する。 static void ReverseArray(VMArray<SInt32> arr) { std::size_t size = arr.GetSize(); std::size_t n = size / 2; for (int i = 0; i < n; i++) { arr.Swap(i, size-i-1); } }
bool GetNodeLocalPosition(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeName, VMArray<float> inArray, bool firstPerson) { NiAVObject * object = ResolveNode(obj, nodeName, firstPerson); if(object && inArray.Length() == 3) { inArray.Set(&object->m_localTransform.pos.x, 0); inArray.Set(&object->m_localTransform.pos.y, 1); inArray.Set(&object->m_localTransform.pos.z, 2); return true; } return false; }
void ApplyMultByIndex(VMArray<float> &multsToModify, UInt32 index, float iniVal, float max) { //Enforce limits if (iniVal < 0.0) iniVal = 0.0; else if (iniVal > max) iniVal = max; float data; multsToModify.Get(&data, index); data *= iniVal; multsToModify.Set(&data, index); }
void CreateEnchantment(TESForm* baseForm, BaseExtraList * extraData, float maxCharge, VMArray<EffectSetting*> effects, VMArray<float> magnitudes, VMArray<UInt32> areas, VMArray<UInt32> durations) { if(baseForm && (baseForm->formType == TESObjectWEAP::kTypeID || baseForm->formType == TESObjectARMO::kTypeID)) { EnchantmentItem * enchantment = NULL; if(effects.Length() > 0 && magnitudes.Length() == effects.Length() && areas.Length() == effects.Length() && durations.Length() == effects.Length()) { tArray<MagicItem::EffectItem> effectItems; effectItems.Allocate(effects.Length()); UInt32 j = 0; for(UInt32 i = 0; i < effects.Length(); i++) { EffectSetting * magicEffect = NULL; effects.Get(&magicEffect, i); if(magicEffect) { // Only add effects that actually exist magnitudes.Get(&effectItems[j].magnitude, i); areas.Get(&effectItems[j].area, i); durations.Get(&effectItems[j].duration, i); effectItems[j].mgef = magicEffect; j++; } } effectItems.count = j; // Set count to existing count if(baseForm->formType == TESObjectWEAP::kTypeID) enchantment = CALL_MEMBER_FN(PersistentFormManager::GetSingleton(), CreateOffensiveEnchantment)(&effectItems); else enchantment = CALL_MEMBER_FN(PersistentFormManager::GetSingleton(), CreateDefensiveEnchantment)(&effectItems); FormHeap_Free(effectItems.arr.entries); } if(enchantment) { if(maxCharge > 0xFFFF) // Charge exceeds uint16 clip it maxCharge = 0xFFFF; ExtraEnchantment* extraEnchant = static_cast<ExtraEnchantment*>(extraData->GetByType(kExtraData_Enchantment)); if(extraEnchant) { PersistentFormManager::GetSingleton()->DecRefEnchantment(extraEnchant->enchant); extraEnchant->enchant = enchantment; PersistentFormManager::GetSingleton()->IncRefEnchantment(extraEnchant->enchant); extraEnchant->maxCharge = (UInt16)maxCharge; } else { ExtraEnchantment* extraEnchant = ExtraEnchantment::Create(); extraEnchant->enchant = enchantment; extraEnchant->maxCharge = (UInt16)maxCharge; extraData->Add(kExtraData_Enchantment, extraEnchant); } } } }
void Interpreter::send(VMSymbol* signature, VMClass* receiverClass) { VMInvokable* invokable = receiverClass->LookupInvokable(signature); if (invokable != nullptr) { #ifdef LOG_RECEIVER_TYPES StdString name = receiverClass->GetName()->GetStdString(); if (GetUniverse()->callStats.find(name) == GetUniverse()->callStats.end()) GetUniverse()->callStats[name] = {0,0}; GetUniverse()->callStats[name].noCalls++; if (invokable->IsPrimitive()) GetUniverse()->callStats[name].noPrimitiveCalls++; #endif // since an invokable is able to change/use the frame, we have to write // cached values before, and read cached values after calling GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal); (*invokable)(GetFrame()); bytecodeIndexGlobal = GetFrame()->GetBytecodeIndex(); } else { GetFrame()->PrintStackTrace(); //doesNotUnderstand long numberOfArgs = Signature::GetNumberOfArguments(signature); vm_oop_t receiver = GetFrame()->GetStackElement(numberOfArgs-1); VMArray* argumentsArray = GetUniverse()->NewArray(numberOfArgs - 1); // without receiver // the receiver should not go into the argumentsArray // so, numberOfArgs - 2 for (long i = numberOfArgs - 2; i >= 0; --i) { vm_oop_t o = GetFrame()->Pop(); argumentsArray->SetIndexableField(i, o); } vm_oop_t arguments[] = {signature, argumentsArray}; GetFrame()->Pop(); // pop the receiver //check if current frame is big enough for this unplanned Send //doesNotUnderstand: needs 3 slots, one for this, one for method name, one for args long additionalStackSlots = 3 - GetFrame()->RemainingStackSize(); if (additionalStackSlots > 0) { GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal); //copy current frame into a bigger one and replace the current frame SetFrame(VMFrame::EmergencyFrameFrom(GetFrame(), additionalStackSlots)); } AS_OBJ(receiver)->Send(doesNotUnderstand, arguments, 2); } }
void _Method::InvokeOn_With_(Interpreter* interp, VMFrame* frame) { // REM: this is a clone with _Primitive::InvokeOn_With_ VMArray* args = static_cast<VMArray*>(frame->Pop()); vm_oop_t rcvr = static_cast<vm_oop_t>(frame->Pop()); VMMethod* mthd = static_cast<VMMethod*>(frame->Pop()); frame->Push(rcvr); size_t num_args = args->GetNumberOfIndexableFields(); for (size_t i = 0; i < num_args; i++) { vm_oop_t arg = args->GetIndexableField(i); frame->Push(arg); } mthd->Invoke(interp, frame); }
bool GetRelativeNodePosition(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeNameA, BSFixedString nodeNameB, VMArray<float> inArray, bool firstPerson) { NiAVObject * objectA = ResolveNode(obj, nodeNameA, firstPerson); NiAVObject * objectB = ResolveNode(obj, nodeNameB, firstPerson); if(objectA && objectB && inArray.Length() == 3) { float x = objectB->m_worldTransform.pos.x - objectA->m_worldTransform.pos.x; float y = objectB->m_worldTransform.pos.y - objectA->m_worldTransform.pos.y; float z = objectB->m_worldTransform.pos.z - objectA->m_worldTransform.pos.z; inArray.Set(&x, 0); inArray.Set(&y, 1); inArray.Set(&z, 2); return true; } return false; }
bool SetNodeLocalPosition(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeName, VMArray<float> inArray, bool firstPerson) { NiAVObject * object = ResolveNode(obj, nodeName, firstPerson); if(object && inArray.Length() == 3) { inArray.Get(&object->m_localTransform.pos.x, 0); inArray.Get(&object->m_localTransform.pos.y, 1); inArray.Get(&object->m_localTransform.pos.z, 2); BSTaskPool * taskPool = BSTaskPool::GetSingleton(); if(taskPool) taskPool->UpdateWorldData(object); return true; } return false; }
bool SetNodeLocalRotationMatrix(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeName, VMArray<float> inArray, bool firstPerson) { NiAVObject * object = ResolveNode(obj, nodeName, firstPerson); if(object && inArray.Length() == 9) { inArray.Get(&object->m_localTransform.rot.data[0][0], 0); inArray.Get(&object->m_localTransform.rot.data[0][1], 1); inArray.Get(&object->m_localTransform.rot.data[0][2], 2); inArray.Get(&object->m_localTransform.rot.data[1][0], 3); inArray.Get(&object->m_localTransform.rot.data[1][1], 4); inArray.Get(&object->m_localTransform.rot.data[1][2], 5); inArray.Get(&object->m_localTransform.rot.data[2][0], 6); inArray.Get(&object->m_localTransform.rot.data[2][1], 7); inArray.Get(&object->m_localTransform.rot.data[2][2], 8); BSTaskPool * taskPool = BSTaskPool::GetSingleton(); if(taskPool) taskPool->UpdateWorldData(object); return true; } return false; }
void SetFloatByIndex(VMArray<float> &dest, UInt32 index, float iniVal, float min, float max) { //Enforce limits if (iniVal < min) iniVal = min; else if (iniVal > max) iniVal = max; dest.Set(&iniVal, index); }
bool GetNodeWorldRotationEuler(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeName, VMArray<float> inArray, bool firstPerson) { NiAVObject * object = ResolveNode(obj, nodeName, firstPerson); if(object && inArray.Length() == 3) { float heading, attitude, bank; object->m_localTransform.rot.GetEulerAngles(&heading, &attitude, &bank); // Radians to degrees heading *= 180 / MATH_PI; attitude *= 180 / MATH_PI; bank *= 180 / MATH_PI; inArray.Set(&heading, 0); inArray.Set(&attitude, 1); inArray.Set(&bank, 2); return true; } return false; }
ExceptionCode inb(VMValue &result, const VMArray &args) { if(args.length() != 1) return ExceptionCode::InvalidArgument; if(args[0].type() != VMType::UInt16) return ExceptionCode::InvalidArgument; result = VMValue::UInt8( ::inb(args[0].value<VMUInt16>())); return ExceptionCode::None; }
ExceptionCode outb(VMValue &, const VMArray &args) { if(args.length() != 2) return ExceptionCode::InvalidArgument; if(args[0].type() != VMType::UInt16) return ExceptionCode::InvalidArgument; if(args[1].type() != VMType::UInt8) return ExceptionCode::InvalidArgument; ::outb(args[0].value<VMUInt16>(), args[1].value<VMUInt8>()); return ExceptionCode::None; }
void PushArgs(VMArray<T> args) { using namespace papyrusUI; UInt32 argCount = args.Length(); UInt32 offset = invokeDelegate_->argCount; UInt32 newArgCount = offset + argCount; if (newArgCount > 128) { _WARNING("Tried to push more than 128 arguments into PapyrusUICallback."); return; } invokeDelegate_->argCount = newArgCount; for (UInt32 i=0; i<argCount; i++, offset++) { T arg; args.Get(&arg, i); SetGFxValue<T>(&invokeDelegate_->args[offset], arg); } }
bool GetNodeWorldRotationMatrix(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeName, VMArray<float> inArray, bool firstPerson) { NiAVObject * object = ResolveNode(obj, nodeName, firstPerson); if(object && inArray.Length() == 9) { inArray.Set(&object->m_worldTransform.rot.data[0][0], 0); inArray.Set(&object->m_worldTransform.rot.data[0][1], 1); inArray.Set(&object->m_worldTransform.rot.data[0][2], 2); inArray.Set(&object->m_worldTransform.rot.data[1][0], 3); inArray.Set(&object->m_worldTransform.rot.data[1][1], 4); inArray.Set(&object->m_worldTransform.rot.data[1][2], 5); inArray.Set(&object->m_worldTransform.rot.data[2][0], 6); inArray.Set(&object->m_worldTransform.rot.data[2][1], 7); inArray.Set(&object->m_worldTransform.rot.data[2][2], 8); return true; } return false; }
bool EAr_MGEFInfoLib::SetMainArrays( VMArray<TESEffectShader*> eShaders, VMArray<BGSArtObject*> eArt, VMArray<TESEffectShader*> hShaders, VMArray<BGSArtObject*> hArt, VMArray<BGSProjectile*> projectiles, VMArray<BGSImpactDataSet*> impactData, VMArray<UInt32> persistFlags, VMArray<float> tWeights, VMArray<float> tCurves, VMArray<float> tDurations) { if ((eShaders.Length() < 126) || (eArt.Length() < 126) || (hShaders.Length() < 126) || (hArt.Length() < 126) || (projectiles.Length() < 126) || (impactData.Length() < 126) || (persistFlags.Length() < 126) || (tWeights.Length() < 126) || (tCurves.Length() < 126) || (tDurations.Length() < 126)) return false; for (UInt32 i = 0; i < 126; i++) { TESEffectShader* pESh = NULL; BGSArtObject* pEAr = NULL; TESEffectShader* pHSh = NULL; BGSArtObject* pHAr = NULL; BGSProjectile* pPro = NULL; BGSImpactDataSet* pIDS = NULL; UInt32 flag; float tWei; float tCur; float tDur; eShaders.Get (&pESh, i); eArt.Get (&pEAr, i); hShaders.Get (&pHSh, i); hArt.Get (&pHAr, i); projectiles.Get (&pPro, i); impactData.Get (&pIDS, i); persistFlags.Get (&flag, i); tWeights.Get (&tWei, i); tCurves.Get (&tCur, i); tDurations.Get (&tDur, i); _eShaders.push_back (pESh); _eArt.push_back (pEAr); _hShaders.push_back (pHSh); _hArt.push_back (pHAr); _projectiles.push_back (pPro); _impactData.push_back (pIDS); _persistFlags.push_back (flag); _tWeights.push_back (tWei); _tCurves.push_back (tCur); _tDurations.push_back (tDur); } battleaxeKeyword = papyrusKeyword::GetKeyword(NULL, "WeapTypeBattleaxe"); READY = true; _MESSAGE("Internal effect library loaded successfully."); return true; }
// 一定距離内に居るアクターをすべて返す VMArray<Actor*> FindCloseActor(float distance, UInt32 sortOrder) { enum Order { kSortOrder_distance = 0, // 距離が近い順 kSortOrder_crosshair = 1, // クロスヘアに近い順 kSortOrder_zaxis_clock = 2, // Z軸時計回り kSortOrder_zaxis_rclock = 3, // Z軸逆時計回り kSortOrder_invalid = 4 }; double fovThreshold = (double)PlayerCamera::GetSingleton()->worldFOV / 180.0 * M_PI /2; VMArray<Actor*> result; result.arr = NULL; tArray<UInt32>* actorHandles = &(*s_cellInfo)->actorHandles; if (actorHandles->count == 0) return result; std::vector<std::pair<double, Actor*>> vec; vec.reserve(actorHandles->count); PlayerCharacter* player = *g_thePlayer; NiPoint3 camPos; GetCameraPos(&camPos); UInt32 handle; size_t i = 0; while (actorHandles->GetNthItem(i++, handle)) { TESObjectREFR* ref = NULL; if (handle != *g_invalidRefHandle) LookupREFRByHandle(&handle, &ref); if (ref && ref->formType == kFormType_Character) { Actor* actor = (Actor*)ref; NiPoint3 pos; GetTargetPos(actor, &pos); double dx = pos.x - camPos.x; double dy = pos.y - camPos.y; double dz = pos.z - camPos.z; double dd = sqrt(dx*dx + dy*dy + dz*dz); if (distance <= 0 || dd <= distance) { double point; NiPoint3 cameraAngle; GetCameraAngle(&cameraAngle); double angleZ = NormalRelativeAngle(atan2(dx, dy) - cameraAngle.z); double angleX = NormalRelativeAngle(atan2(-dz, sqrt(dx*dx + dy*dy)) - cameraAngle.x); if (abs(angleZ) < fovThreshold) { switch (sortOrder) { case kSortOrder_distance: point = dd; break; case kSortOrder_crosshair: point = sqrt(angleZ*angleZ + angleX*angleX); break; case kSortOrder_zaxis_clock: point = NormalAbsoluteAngle(atan2(dx, dy) - cameraAngle.z); break; case kSortOrder_zaxis_rclock: point = 2*M_PI - NormalAbsoluteAngle(atan2(dx, dy) - cameraAngle.z); break; default: point = 0; break; } if (point >= 0) { vec.push_back(std::make_pair(point, actor)); } } } } } if (vec.size() == 0) return result; if (sortOrder < kSortOrder_invalid) std::sort(vec.begin(), vec.end()); // Papyrusに返す配列を確保 if (result.Allocate(vec.size())) { for (i = 0; i < vec.size(); i++) { result.Set(&vec[i].second, i); } } return result; }
void CloneObjectsTest::testCloneArray() { VMArray* orig = GetUniverse()->NewArray(3); orig->SetIndexableField(0, GetUniverse()->NewString("foobar42")); orig->SetIndexableField(1, GetUniverse()->NewString("foobar43")); orig->SetIndexableField(2, GetUniverse()->NewString("foobar44")); VMArray* clone = orig->Clone(); CPPUNIT_ASSERT((intptr_t)orig != (intptr_t)clone); CPPUNIT_ASSERT_EQUAL_MESSAGE("class differs!!", orig->clazz, clone->clazz); CPPUNIT_ASSERT_EQUAL_MESSAGE("objectSize differs!!", orig->objectSize, clone->objectSize); CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfFields differs!!", orig->numberOfFields, clone->numberOfFields); CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfFields differs!!", orig->GetNumberOfIndexableFields(), clone->GetNumberOfIndexableFields()); CPPUNIT_ASSERT_EQUAL_MESSAGE("field 0 differs", orig->GetIndexableField(0), clone->GetIndexableField(0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("field 1 differs", orig->GetIndexableField(1), clone->GetIndexableField(1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("field 2 differs", orig->GetIndexableField(2), clone->GetIndexableField(2)); }