diff --git a/src/dobjtype.h b/src/dobjtype.h index d31dac3ce..952f4d627 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -708,11 +708,15 @@ protected: class PStruct : public PNamedType { DECLARE_CLASS(PStruct, PNamedType); + public: PStruct(FName name, PTypeBase *outer); TArray Fields; bool HasNativeFields; + // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use thes two functions for it. + VMFunction *mConstructor = nullptr; + VMFunction *mDestructor = nullptr; virtual PField *AddField(FName name, PType *type, DWORD flags=0); virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f1a0ae8bf..15bb8d0b4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4408,6 +4408,8 @@ enum EACSFunctions ACSF_DamageActor, // [arookas] ACSF_SetActorFlag, ACSF_SetTranslation, + ACSF_GetActorFloorTexture, + ACSF_GetActorFloorTerrain, // OpenGL stuff @@ -6100,6 +6102,35 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; } + case ACSF_GetActorFloorTexture: + { + auto a = SingleActorFromTID(args[0], activator); + if (a != nullptr) + { + return GlobalACSStrings.AddString(TexMan[a->floorpic]->Name); + } + else + { + return GlobalACSStrings.AddString(""); + } + break; + } + + case ACSF_GetActorFloorTerrain: + { + auto a = SingleActorFromTID(args[0], activator); + if (a != nullptr) + { + return GlobalACSStrings.AddString(Terrains[a->floorterrain].Name); + } + else + { + return GlobalACSStrings.AddString(""); + } + break; + } + + default: break; diff --git a/src/p_local.h b/src/p_local.h index 6bb65ad97..8ebdf9fae 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -261,7 +261,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo AActor *P_CheckOnmobj (AActor *thing); void P_FakeZMovement (AActor *mo); bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); -bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor = NULL); +bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor = NULL, bool missilecheck = false); bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags = 0); void P_ApplyTorque(AActor *mo); diff --git a/src/p_map.cpp b/src/p_map.cpp index d48fb4e5a..4e873c99a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -84,6 +84,49 @@ TArray spechit; TArray portalhit; +// FCheckPosition requires explicit contstruction and destruction when used in the VM +DEFINE_ACTION_FUNCTION(_FCheckPosition, _Constructor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + new(self) FCheckPosition; + return 0; +} + +DEFINE_ACTION_FUNCTION(_FCheckPosition, _Destructor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + self->~FCheckPosition(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_FCheckPosition, ClearLastRipped) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + self->LastRipped.Clear(); + return 0; +} + +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos); +DEFINE_FIELD_NAMED_X(FCheckPosition, FCheckPosition, sector, cursector); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorz); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingz); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, dropoffz); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorpic); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorterrain); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorsector); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingpic); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingsector); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, touchmidtex); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, abovemidtex); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floatok); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, FromPMove); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingline); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, stepthing); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, DoRipping); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, portalstep); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, PushTime); + //========================================================================== // // CanCollideWith @@ -1845,9 +1888,18 @@ DEFINE_ACTION_FUNCTION(AActor, CheckPosition) PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_BOOL_DEF(actorsonly); - ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly)); + PARAM_POINTER_DEF(tm, FCheckPosition); + if (tm) + { + ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), *tm, actorsonly)); + } + else + { + ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly)); + } } + //---------------------------------------------------------------------------- // // FUNC P_TestMobjLocation @@ -2637,10 +2689,10 @@ pushline: bool P_TryMove(AActor *thing, const DVector2 &pos, int dropoff, // killough 3/15/98: allow dropoff as option - const secplane_t *onfloor) // [RH] Let P_TryMove keep the thing on the floor + const secplane_t *onfloor, bool missilecheck) // [RH] Let P_TryMove keep the thing on the floor { FCheckPosition tm; - return P_TryMove(thing, pos, dropoff, onfloor, tm); + return P_TryMove(thing, pos, dropoff, onfloor, tm, missilecheck); } DEFINE_ACTION_FUNCTION(AActor, TryMove) @@ -2649,7 +2701,16 @@ DEFINE_ACTION_FUNCTION(AActor, TryMove) PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_INT(dropoff); - ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff)); + PARAM_BOOL_DEF(missilecheck); + PARAM_POINTER_DEF(tm, FCheckPosition); + if (tm == nullptr) + { + ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff, nullptr, missilecheck)); + } + else + { + ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff, nullptr, *tm, missilecheck)); + } } diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index d8c1aa3dd..b2f9d40eb 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5160,6 +5160,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -5410,6 +5411,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -5504,6 +5506,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -7801,6 +7804,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use if (EmitTail) { build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); @@ -8072,6 +8076,8 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); int count = 0; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use + if (count == 1) { ExpEmit reg; @@ -9508,6 +9514,19 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) { ExpEmit out(0, REGT_NIL); + // call the destructors for all structs requiring one. + // go in reverse order of construction + for (int i = build->ConstructedStructs.Size() - 1; i >= 0; i--) + { + auto pstr = static_cast(build->ConstructedStructs[i]->ValueType); + assert(pstr->mDestructor != nullptr); + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + // If we return nothing, use a regular RET opcode. // Otherwise just return the value we're given. if (Value == nullptr) @@ -10173,6 +10192,19 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) else { // Init arrays and structs. + if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + { + auto pstr = static_cast(ValueType); + if (pstr->mConstructor != nullptr) + { + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this); + } } return ExpEmit(); } @@ -10184,6 +10216,22 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) { build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); } + else + { + if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + { + auto pstr = static_cast(ValueType); + if (pstr->mDestructor != nullptr) + { + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this)); + } + } // Stack space will not be released because that would make controlled destruction impossible. // For that all local stack variables need to live for the entire execution of a function. } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 08afa6d93..a0a66a776 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -1993,6 +1993,7 @@ class FxLocalVariableDeclaration : public FxExpression public: int StackOffset = -1; int RegNum = -1; + bool constructed = false; FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p); ~FxLocalVariableDeclaration(); diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/codegeneration/dynarrays.cpp index 4489bbcb2..05e18a3ca 100644 --- a/src/scripting/codegeneration/dynarrays.cpp +++ b/src/scripting/codegeneration/dynarrays.cpp @@ -37,9 +37,7 @@ ** */ -#define private public // this file needs public access to TArray's private 'Count' field so just hack the visibility qualifiers here #include "tarray.h" -#undef private #include "dobject.h" #include "thingdef.h" // We need one specific type for each of the 7 integral VM types and instantiate the needed functions for each of them. @@ -775,10 +773,10 @@ DEFINE_ACTION_FUNCTION(FDynArray_String, Clear) return 0; } -DEFINE_FIELD_NAMED(FDynArray_I8, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_I16, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_I32, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_F32, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_F64, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_Ptr, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_String, Count, Size) // clashes with type 'Inventory'. +DEFINE_FIELD_NAMED_X(DynArray_I8, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_I16, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_I32, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_F32, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_F64, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_Ptr, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_String, FArray, Count, Size) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f57509d81..407fd6307 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -50,6 +50,8 @@ #include "zstring.h" #include "d_event.h" #include "g_levellocals.h" +#include "vm.h" +#include "p_checkposition.h" static TArray properties; static TArray AFTable; @@ -856,6 +858,14 @@ void InitThingdef() qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } + // Add the constructor and destructor to FCheckPosition. + auto fcp = NewStruct("FCheckPosition", nullptr); + fcp->mConstructor = *FindFunction(fcp, "_Constructor")->VMPointer; + fcp->mDestructor = *FindFunction(fcp, "_Destructor")->VMPointer; + fcp->Size = sizeof(FCheckPosition); + fcp->Align = alignof(FCheckPosition); + + FieldTable.Clear(); if (FieldTable.Size() == 0) { diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 2e98e865e..1035c2f8e 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1116,9 +1116,9 @@ struct AFuncDesc MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##icls##_##name; #define DEFINE_FIELD_NAMED_X(cls, icls, name, scriptname) \ - static const FieldDesc VMField_##icls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ - extern FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr; \ - MSVC_FSEG FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##icls##_##scriptname; + static const FieldDesc VMField_##cls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; #define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \ diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index da099256e..b7746f1ce 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -5,6 +5,7 @@ class VMFunctionBuilder; class FxExpression; +class FxLocalVariableDeclaration; struct ExpEmit { @@ -92,6 +93,7 @@ public: // keep the frame pointer, if needed, in a register because the LFP opcode is hideously inefficient, requiring more than 20 instructions on x64. ExpEmit FramePointer; + TArray ConstructedStructs; private: struct AddrKonst diff --git a/src/tarray.h b/src/tarray.h index fc9a62587..fe0d8c1e2 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -71,8 +71,8 @@ protected: struct FArray { void *Array; - unsigned int Most; unsigned int Count; + unsigned int Most; }; // T is the type stored in the array. diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 906bf9539..14c4791c6 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1337,7 +1337,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - _crtBreakAlloc = 124459; + //_crtBreakAlloc = 53039; #endif DoMain (hInstance); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9744f3766..6a5be172e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1,3 +1,34 @@ +struct FCheckPosition +{ + // in + native Actor thing; + native Vector3 pos; + + // out + native Sector cursector; + native double floorz; + native double ceilingz; + native double dropoffz; + native TextureID floorpic; + native int floorterrain; + native Sector floorsector; + native TextureID ceilingpic; + native Sector ceilingsector; + native bool touchmidtex; + native bool abovemidtex; + native bool floatok; + native bool FromPMove; + native line ceilingline; + native Actor stepthing; + native bool DoRipping; + native bool portalstep; + + native int PushTime; + + native void ClearLastRipped(); +} + + class Actor : Thinker native { const DEFAULT_HEALTH = 1000; @@ -327,7 +358,7 @@ class Actor : Thinker native native double BulletSlope(out FTranslatedLineTarget pLineTarget = null, int aimflags = 0); native Actor AimTarget(); native bool CheckMissileSpawn(double maxdist); - native bool CheckPosition(Vector2 pos, bool actorsonly = false); + native bool CheckPosition(Vector2 pos, bool actorsonly = false, FCheckPosition tm = null); native bool TestMobjLocation(); native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native Actor SpawnMissile(Actor dest, class type, Actor owner = null); @@ -388,7 +419,7 @@ class Actor : Thinker native return true; } - native bool TryMove(vector2 newpos, int dropoff); + native bool TryMove(vector2 newpos, int dropoff, bool missilecheck = false, FCheckPosition tm = null); native void NewChaseDir(); native void RandomChaseDir(); native bool CheckMissileRange();