diff --git a/.travis.yml b/.travis.yml index 61a770769..50de0fd1c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,28 +2,31 @@ language: c++ dist: trusty sudo: required +branches: + except: + - /^appveyor.*$/ + +git: + depth: 3 + matrix: include: - - os: osx - osx_image: xcode8.2 - env: - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7" - - os: osx osx_image: xcode8.2 env: - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 -DFORCE_INTERNAL_ZLIB=YES -DFORCE_INTERNAL_JPEG=YES -DFORCE_INTERNAL_BZIP2=YES -DFORCE_INTERNAL_GME=YES" + - FMOD_LIBRARY=libfmodex.dylib - os: linux compiler: gcc env: - GCC_VERSION=5 - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release" + - FMOD_LIBRARY=libfmodex64.so addons: apt: sources: - ubuntu-toolchain-r-test - - kubuntu-backports packages: - g++-5 - libsdl2-dev @@ -34,17 +37,37 @@ matrix: - libfluidsynth-dev - libgtk-3-dev + - os: linux + compiler: gcc + env: + - GCC_VERSION=6 + - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDYN_FLUIDSYNTH=NO" + - FMOD_LIBRARY=libfmodex64.so + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + - libsdl2-dev + - libgme-dev + - libopenal-dev + - libmpg123-dev + - libsndfile-dev + - libfluidsynth-dev + - libgtk-3-dev + - os: linux compiler: clang env: - CLANG_VERSION=3.9 - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDYN_OPENAL=NO -DDYN_FLUIDSYNTH=NO" + - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DDYN_OPENAL=NO" + - FMOD_LIBRARY=libfmodex64.so addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-3.9 - - kubuntu-backports packages: - clang-3.9 - libstdc++-5-dev @@ -62,11 +85,15 @@ before_install: - if [ -n "$CLANG_VERSION" ]; then export CC="clang-${CLANG_VERSION}" CXX="clang++-${CLANG_VERSION}"; fi - $CC --version - $CXX --version + - export FMOD_FILENAME=fmod-4.44.64-${TRAVIS_OS_NAME}.tar.bz2 + - curl -LO "https://github.com/coelckers/gzdoom/releases/download/ci_deps/${FMOD_FILENAME}" + - tar -xf "${FMOD_FILENAME}" script: + - echo ${TRAVIS_BUILD_DIR} - mkdir build - cd build - - cmake ${CMAKE_OPTIONS} .. + - cmake ${CMAKE_OPTIONS} -DFMOD_INCLUDE_DIR="${TRAVIS_BUILD_DIR}/fmod/inc" -DFMOD_LIBRARY="${TRAVIS_BUILD_DIR}/fmod/lib/${FMOD_LIBRARY}" .. - make -j2 notifications: diff --git a/src/gl/scene/gl_sky.cpp b/src/gl/scene/gl_sky.cpp index 19d1c9127..7fe92b890 100644 --- a/src/gl/scene/gl_sky.cpp +++ b/src/gl/scene/gl_sky.cpp @@ -289,7 +289,7 @@ void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex if (frontreflect > 0) { float backreflect = bs->GetReflect(sector_t::ceiling); - if (backreflect > 0 && bs->ceilingplane.fD() == fs->ceilingplane.fD()) + if (backreflect > 0 && bs->ceilingplane.fD() == fs->ceilingplane.fD() && !bs->isClosed()) { // Don't add intra-portal line to the portal. return; @@ -368,7 +368,7 @@ void GLWall::SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,ver if (frontreflect > 0) { float backreflect = bs->GetReflect(sector_t::floor); - if (backreflect > 0 && bs->floorplane.fD() == fs->floorplane.fD()) + if (backreflect > 0 && bs->floorplane.fD() == fs->floorplane.fD() && !bs->isClosed()) { // Don't add intra-portal line to the portal. return; diff --git a/src/r_defs.h b/src/r_defs.h index 63c615500..ea0e11480 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -954,6 +954,11 @@ public: return LowestFloorAt(a->Pos(), resultsec); } + bool isClosed() const + { + return floorplane.Normal() == -ceilingplane.Normal() && floorplane.D == -ceilingplane.D; + } + double NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); double NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 12a0c44e0..c0a69eb6e 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5105,7 +5105,18 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build) ExpEmit from = val->Emit(build); from.Free(build); ExpEmit to(build, REGT_POINTER); - build->Emit(from.Konst ? OP_NEW_K : OP_NEW, to.RegNum, from.RegNum, build->GetConstantAddress(CallingFunction, ATAG_OBJECT)); + + if (!from.Konst) + { + int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags); + if (outerside == FScopeBarrier::Side_Virtual) + outerside = FScopeBarrier::SideFromObjectFlags(CallingFunction->OwningClass->ObjectFlags); + build->Emit(OP_NEW, to.RegNum, from.RegNum, outerside+1); // +1 to ensure it's not 0 + } + else + { + build->Emit(OP_NEW_K, to.RegNum, from.RegNum); + } return to; } @@ -8781,20 +8792,27 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit selfemit; if (Function->Variants[0].Flags & VARF_Method) { -#if 0 - // [ZZ] - if (Function->Variants[0].Implementation && Function->Variants[0].Implementation->BarrierSide == FScopeBarrier::Side_Virtual) - { - // pass this even before Self, because otherwise we can't silently advance the arguments. - // this is not even implicit arguments. - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(Function, ATAG_OBJECT)); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(CallingFunction, ATAG_OBJECT)); - count += 2; - } -#endif assert(Self != nullptr); selfemit = Self->Emit(build); assert((selfemit.RegType == REGT_POINTER) || (selfemit.Fixed && selfemit.Target)); + + int innerside = FScopeBarrier::SideFromFlags(Function->Variants[0].Flags); + + if (innerside == FScopeBarrier::Side_Virtual) + { + auto selfside = FScopeBarrier::SideFromObjectFlags(static_cast(Self->ValueType)->PointedType->ObjectFlags); + + int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags); + if (outerside == FScopeBarrier::Side_Virtual) + outerside = FScopeBarrier::SideFromObjectFlags(CallingFunction->OwningClass->ObjectFlags); + + if (selfside != outerside && (selfside == FScopeBarrier::Side_Play || selfside == FScopeBarrier::Side_UI)) // if the self pointer and the calling functions have the same scope the check here is not needed. + { + // Check the self object against the calling function's flags at run time + build->Emit(OP_SCOPE, selfemit.RegNum, outerside + 1, build->GetConstantAddress(vmfunc, ATAG_OBJECT)); + } + } + if (selfemit.Fixed && selfemit.Target) { // Address of a local variable. @@ -8859,6 +8877,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { selfemit.Free(build); ExpEmit funcreg(build, REGT_POINTER); + build->Emit(OP_VTBL, funcreg.RegNum, selfemit.RegNum, vmfunc->VirtualIndex); if (EmitTail) { // Tail call diff --git a/src/scripting/backend/scopebarrier.cpp b/src/scripting/backend/scopebarrier.cpp index ad104f317..29caa2457 100644 --- a/src/scripting/backend/scopebarrier.cpp +++ b/src/scripting/backend/scopebarrier.cpp @@ -173,25 +173,16 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name) } // these are for vmexec.h -void FScopeBarrier::ValidateNew(PClass* cls, PFunction* callingfunc) +void FScopeBarrier::ValidateNew(PClass* cls, int outerside) { - int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual; - if (outerside == FScopeBarrier::Side_Virtual) - outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags); int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); } -// this can be imported in vmexec.h -void FScopeBarrier::ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype) + +void FScopeBarrier::ValidateCall(PClass* selftype, VMFunction *calledfunc, int outerside) { - // [ZZ] anonymous blocks have 0 variants, so give them Side_Virtual. - int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual; - if (outerside == FScopeBarrier::Side_Virtual) - outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags); - int innerside = FScopeBarrier::SideFromFlags(calledfunc->Variants[0].Flags); - if (innerside == FScopeBarrier::Side_Virtual) - innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) - ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->SymbolName.GetChars(), FScopeBarrier::StringFromSide(outerside)); + ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->PrintableName.GetChars(), FScopeBarrier::StringFromSide(outerside)); } \ No newline at end of file diff --git a/src/scripting/backend/scopebarrier.h b/src/scripting/backend/scopebarrier.h index db8a5044a..da0bc6d1d 100644 --- a/src/scripting/backend/scopebarrier.h +++ b/src/scripting/backend/scopebarrier.h @@ -53,7 +53,8 @@ struct FScopeBarrier void AddFlags(int flags1, int flags2, const char* name); // this is called from vmexec.h - static void ValidateNew(PClass* cls, PFunction* callingfunc); - static void ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype); + static void ValidateNew(PClass* cls, int scope); + static void ValidateCall(PClass* selftype, VMFunction *calledfunc, int outerside); + }; diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 0281be3df..594942351 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -648,6 +648,13 @@ begin: reg.a[a] = p->Virtuals[C]; } NEXTOP; + OP(SCOPE) : + { + ASSERTA(a); ASSERTA(C); + FScopeBarrier::ValidateCall(((DObject*)a)->GetClass(), (VMFunction*)C, B - 1); + } + NEXTOP; + OP(CALL_K): ASSERTKA(a); assert(konstatag[a] == ATAG_OBJECT); @@ -665,19 +672,6 @@ begin: int numret; b = B; -#if 0 - // [ZZ] hax! - if (call->BarrierSide == 3) // :( - this is Side_Virtual. Side_Virtual should receive special arguments. - { - PFunction* calledfunc = (PFunction*)(reg.param + f->NumParam - b)[0].a; - PFunction* callingfunc = (PFunction*)(reg.param + f->NumParam - b)[1].a; - DObject* dobj = (DObject*)(reg.param + f->NumParam - b)[2].a; // this is the self pointer. it should be in, since Side_Virtual functions are always non-static methods. - PClass* selftype = dobj->GetClass(); - FScopeBarrier::ValidateCall(calledfunc, callingfunc, selftype); - b -= 2; - } -#endif - FillReturns(reg, f, returns, pc+1, C); if (call->VarFlags & VARF_Native) { @@ -817,11 +811,10 @@ begin: { b = B; PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[b] : konsta[b].v); - PFunction *callingfunc = (PFunction*)konsta[C].o; // [ZZ] due to how this is set, it's always const if (cls->ObjectFlags & OF_Abstract) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); // [ZZ] validate readonly and between scope construction - if (callingfunc) - FScopeBarrier::ValidateNew(cls, callingfunc); + c = C; + if (c) FScopeBarrier::ValidateNew(cls, c - 1); reg.a[a] = cls->CreateNew(); reg.atag[a] = ATAG_OBJECT; NEXTOP; diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 3d503932a..18a444677 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -106,12 +106,13 @@ xx(PARAMI, parami, I24, NOP, 0, 0), // push immediate, signed integer for func xx(CALL, call, RPI8I8, NOP, 0, 0), // Call function pkA with parameter count B and expected result count C xx(CALL_K, call, KPI8I8, CALL, 1, REGT_POINTER), xx(VTBL, vtbl, RPRPI8, NOP, 0, 0), // dereferences a virtual method table. +xx(SCOPE, scope, RPI8, NOP, 0, 0), // Scope check at runtime. xx(TAIL, tail, RPI8, NOP, 0, 0), // Call+Ret in a single instruction xx(TAIL_K, tail, KPI8, TAIL, 1, REGT_POINTER), xx(RESULT, result, __BCP, NOP, 0, 0), // Result should go in register encoded in BC (in caller, after CALL) xx(RET, ret, I8BCP, NOP, 0, 0), // Copy value from register encoded in BC to return value A, possibly returning xx(RETI, reti, I8I16, NOP, 0, 0), // Copy immediate from BC to return value A, possibly returning -xx(NEW, new, RPRP, NOP, 0, 0), +xx(NEW, new, RPRPI8, NOP, 0, 0), xx(NEW_K, new, RPKP, NOP, 0, 0), xx(TRY, try, I24, NOP, 0, 0), // When an exception is thrown, start searching for a handler at pc + ABC xx(UNTRY, untry, I8, NOP, 0, 0), // Pop A entries off the exception stack diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 4ab9e0162..029a38be4 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -450,13 +450,13 @@ class Actor : Thinker native native static int FindUniqueTid(int start = 0, int limit = 0); native void SetShade(color col); - native string GetTag(string defstr = "") const; + native clearscope string GetTag(string defstr = "") const; native void SetTag(string defstr = ""); native double GetBobOffset(double frac = 0); native void ClearCounters(); native bool GiveBody (int num, int max=0); native bool HitFloor(); - native bool isTeammate(Actor other) const; + native clearscope bool isTeammate(Actor other) const; native int PlayerNumber(); native void SetFriendPlayer(PlayerInfo player); native void SoundAlert(Actor target, bool splash = false, double maxdist = 0); @@ -468,15 +468,15 @@ class Actor : Thinker native native bool UpdateWaterLevel (bool splash = true); native bool IsZeroDamage(); native void ClearInterpolation(); - native Vector3 PosRelative(sector sec) const; + native clearscope Vector3 PosRelative(sector sec) const; native void HandleSpawnFlags(); native void ExplodeMissile(line lin = null, Actor target = null, bool onsky = false); native void RestoreDamage(); - native int SpawnHealth() const; + native clearscope int SpawnHealth() const; native void SetDamage(int dmg); - native double Distance2D(Actor other) const; - native double Distance3D(Actor other) const; + native clearscope double Distance2D(Actor other) const; + native clearscope double Distance3D(Actor other) const; native void SetOrigin(vector3 newpos, bool moving); native void SetXYZ(vector3 newpos); native Actor GetPointer(int aaptr); @@ -511,7 +511,7 @@ class Actor : Thinker native native void BloodSplatter (Vector3 pos, double hitangle, bool axe = false); native bool HitWater (sector sec, Vector3 pos, bool checkabove = false, bool alert = true, bool force = false); native void PlaySpawnSound(Actor missile); - native bool CountsAsKill() const; + native clearscope bool CountsAsKill() const; native bool Teleport(Vector3 pos, double angle, int flags); native void TraceBleed(int damage, Actor missile); @@ -559,21 +559,21 @@ class Actor : Thinker native native void LinkToWorld(LinkContext ctx = null); native void UnlinkFromWorld(out LinkContext ctx = null); native bool CanSeek(Actor target); - native double AngleTo(Actor target, bool absolute = false) const; + native clearscope double AngleTo(Actor target, bool absolute = false) const; native void AddZ(double zadd, bool moving = true); native void SetZ(double z); - native vector2 Vec2To(Actor other) const; - native vector3 Vec3To(Actor other) const; - native vector3 Vec3Offset(double x, double y, double z, bool absolute = false) const; - native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false) const; - native vector2 Vec2Angle(double length, double angle, bool absolute = false) const; - native vector2 Vec2Offset(double x, double y, bool absolute = false) const; - native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false) const; - native void VelFromAngle(double speed = 0, double angle = 0) const; - native void Vel3DFromAngle(double speed, double angle, double pitch) const; + native clearscope vector2 Vec2To(Actor other) const; + native clearscope vector3 Vec3To(Actor other) const; + native clearscope vector3 Vec3Offset(double x, double y, double z, bool absolute = false) const; + native clearscope vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false) const; + native clearscope vector2 Vec2Angle(double length, double angle, bool absolute = false) const; + native clearscope vector2 Vec2Offset(double x, double y, bool absolute = false) const; + native clearscope vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false) const; + native void VelFromAngle(double speed = 0, double angle = 0); + native void Vel3DFromAngle(double speed, double angle, double pitch); native void Thrust(double speed = 0, double angle = 0); - native bool isFriend(Actor other) const; - native bool isHostile(Actor other) const; + native clearscope bool isFriend(Actor other) const; + native clearscope bool isHostile(Actor other) const; native void AdjustFloorClip(); native DropItem GetDropItems(); native void CopyFriendliness (Actor other, bool changeTarget, bool resetHealth = true); @@ -588,8 +588,8 @@ class Actor : Thinker native native void Howl(); native void DrawSplash (int count, double angle, int kind); native void GiveSecret(bool printmsg = true, bool playsound = true); - native double GetCameraHeight() const; - native double GetGravity() const; + native clearscope double GetCameraHeight() const; + native clearscope double GetGravity() const; native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native void AddInventory(Inventory inv); @@ -597,7 +597,7 @@ class Actor : Thinker native native void ClearInventory(); native bool GiveInventory(class type, int amount, bool givecheat = false); native bool TakeInventory(class itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); - native Inventory FindInventory(class itemtype, bool subclass = false) const; + native clearscope Inventory FindInventory(class itemtype, bool subclass = false) const; native Inventory GiveInventoryType(class itemtype); native Inventory DropInventory (Inventory item, int amt = -1); native bool UseInventory(Inventory item); @@ -609,11 +609,11 @@ class Actor : Thinker native action native void SetCamera(Actor cam, bool revert = false); // DECORATE compatible functions - native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); - native double GetDistance(bool checkz, int ptr = AAPTR_TARGET); - native double GetAngle(int flags, int ptr = AAPTR_TARGET); + native clearscope int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT) const; + native double GetDistance(bool checkz, int ptr = AAPTR_TARGET) const; + native double GetAngle(int flags, int ptr = AAPTR_TARGET) const; native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT); - native int GetSpawnHealth() const; + native clearscope int GetSpawnHealth() const; native double GetCrouchFactor(int ptr = AAPTR_PLAYER1); native double GetCVar(string cvar); native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 3821ff002..d18b0bde4 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -150,7 +150,7 @@ class PlayerPawn : Actor native } // This is for SBARINFO. - int, int GetEffectTicsForItem(class item) const + clearscope int, int GetEffectTicsForItem(class item) const { let pg = (class)(item); if (pg != null) @@ -167,7 +167,7 @@ class PlayerPawn : Actor native return -1, -1; } - native int GetMaxHealth(bool withupgrades = false) const; + native clearscope int GetMaxHealth(bool withupgrades = false) const; native bool ResetAirSupply (bool playgasp = false); native void CheckWeaponSwitch(class item); native clearscope static String GetPrintableDisplayName(Class cls);