diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f68b2d809..18133f05e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -793,7 +793,7 @@ file( GLOB HEADER_FILES sound/*.h textures/*.h scripting/*.h - scripting/codegeneration/*.h + scripting/backend/*.h scripting/decorate/*.h scripting/zscript/*.h scripting/vm/*.h @@ -1271,17 +1271,18 @@ set (PCH_SOURCES r_data/voxels.cpp r_data/renderstyle.cpp r_data/r_interpolate.cpp + scripting/symbols.cpp scripting/thingdef.cpp scripting/thingdef_data.cpp scripting/thingdef_properties.cpp - scripting/codegeneration/codegen.cpp - scripting/codegeneration/dynarrays.cpp + scripting/backend/codegen.cpp + scripting/backend/dynarrays.cpp + scripting/backend/vmbuilder.cpp + scripting/backend/vmdisasm.cpp scripting/decorate/olddecorations.cpp scripting/decorate/thingdef_exp.cpp scripting/decorate/thingdef_parse.cpp scripting/decorate/thingdef_states.cpp - scripting/vm/vmbuilder.cpp - scripting/vm/vmdisasm.cpp scripting/vm/vmexec.cpp scripting/vm/vmframe.cpp scripting/zscript/ast.cpp @@ -1526,9 +1527,9 @@ source_group("Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE source_group("Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+") source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+") source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+") -source_group("Scripting\\Decorate" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+") -source_group("Scripting\\ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) -source_group("Scripting\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/codegeneration/.+") +source_group("Scripting\\Decorate frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+") +source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) +source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+") source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+") source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+") source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+") diff --git a/src/actor.h b/src/actor.h index 4016d447b..13511b617 100644 --- a/src/actor.h +++ b/src/actor.h @@ -572,12 +572,9 @@ struct FLinkContext msecnode_t *render_list = nullptr; }; -class DDropItem : public DObject +struct FDropItem { - DECLARE_CLASS(DDropItem, DObject) - HAS_OBJECT_POINTERS -public: - DDropItem *Next; + FDropItem *Next; FName Name; int Probability; int Amount; @@ -610,7 +607,7 @@ public: return (AActor *)(this->GetClass()->Defaults); } - DDropItem *GetDropItems() const; + FDropItem *GetDropItems() const; // Return true if the monster should use a missile attack, false for melee bool SuggestMissileAttack (double dist); @@ -699,7 +696,7 @@ public: // Give an item to the actor and pick it up. // Returns true if the item pickup succeeded. - bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false); + bool GiveInventory (PClassActor *type, int amount, bool givecheat = false); // Removes the item from the inventory list. virtual void RemoveInventory (AInventory *item); @@ -736,7 +733,7 @@ public: AInventory *FirstInv (); // Tries to give the actor some ammo. - bool GiveAmmo (PClassInventory *type, int amount); + bool GiveAmmo (PClassActor *type, int amount); // Destroys all the inventory the actor is holding. void DestroyAllInventory (); diff --git a/src/am_map.cpp b/src/am_map.cpp index a69ab098c..1bd1aacd5 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2857,7 +2857,7 @@ void AM_drawThings () // Find the key's own color. // Only works correctly if single-key locks have lower numbers than any-key locks. // That is the case for all default keys, however. - if (t->IsKindOf(PClass::FindActor(NAME_Key))) + if (t->IsKindOf(NAME_Key)) { if (G_SkillProperty(SKILLP_EasyKey)) { diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 54d154a3e..637494333 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -263,7 +263,7 @@ void InitBotStuff() for(unsigned i=0;iIsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls != NULL && cls->IsDescendantOf(NAME_Weapon)) { AWeapon *w = (AWeapon*)GetDefaultByType(cls); if (w != NULL) diff --git a/src/b_think.cpp b/src/b_think.cpp index 7ce276aa0..da3fb6124 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -328,7 +328,7 @@ void DBot::WhatToGet (AActor *item) //if(pos && !bglobal.thingvis[pos->id][item->id]) continue; // if (item->IsKindOf (RUNTIME_CLASS(AArtifact))) // return; // don't know how to use artifacts - if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { // FIXME AWeapon *heldWeapon; diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 7428fceea..e8f9509e5 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -1210,7 +1210,7 @@ static void PrintSecretString(const char *string, bool thislevel) { while ((actor = it.Next())) { - if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue; + if (!actor->IsKindOf("SecretTrigger")) continue; foundone = true; break; } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 7fecec550..36c32bf5b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -73,7 +73,7 @@ #include "thingdef.h" #include "info.h" #include "v_text.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO @@ -1658,7 +1658,7 @@ static int PatchWeapon (int weapNum) { val = 5; } - info->AmmoType1 = (PClassInventory*)AmmoNames[val]; + info->AmmoType1 = AmmoNames[val]; if (info->AmmoType1 != NULL) { info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2; @@ -1983,7 +1983,7 @@ static int PatchMisc (int dummy) player->health = deh.StartHealth; // Hm... I'm not sure that this is the right way to change this info... - DDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; + FDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; while (di != NULL) { if (di->Name == NAME_Clip) @@ -2916,7 +2916,7 @@ static bool LoadDehSupp () else { auto cls = PClass::FindActor(sc.String); - if (cls == NULL || !cls->IsDescendantOf(PClass::FindActor(NAME_Ammo))) + if (cls == NULL || !cls->IsDescendantOf(NAME_Ammo)) { sc.ScriptError("Unknown ammo type '%s'", sc.String); } @@ -2934,7 +2934,7 @@ static bool LoadDehSupp () { sc.MustGetString(); PClass *cls = PClass::FindClass(sc.String); - if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls == NULL || !cls->IsDescendantOf(NAME_Weapon)) { sc.ScriptError("Unknown weapon type '%s'", sc.String); } diff --git a/src/d_main.cpp b/src/d_main.cpp index 3a497fcde..6c0a4c027 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2704,6 +2704,8 @@ void D_DoomMain (void) // delete all data that cannot be left until reinitialization V_ClearFonts(); // must clear global font pointers + ColorSets.Clear(); + PainFlashes.Clear(); R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. gameinfo.~gameinfo_t(); new (&gameinfo) gameinfo_t; // Reset gameinfo @@ -2714,7 +2716,7 @@ void D_DoomMain (void) GC::FullGC(); // clean up before taking down the object list. - // Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions. + // Delete the reference to the VM functions here which were deleted and will be recreated after the restart. FAutoSegIterator probe(ARegHead, ARegTail); while (*++probe != NULL) { diff --git a/src/d_net.cpp b/src/d_net.cpp index c38a7cefe..97f6be9bb 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2539,7 +2539,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_MORPHEX: { s = ReadString (stream); - const char *msg = cht_Morph (players + player, dyn_cast(PClass::FindClass (s)), false); + const char *msg = cht_Morph (players + player, PClass::FindActor (s), false); if (player == consoleplayer) { Printf ("%s\n", *msg != '\0' ? msg : "Morph failed."); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index d3ce8c943..62beb5460 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -156,7 +156,7 @@ int D_PlayerClassToInt (const char *classname) { for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) { - PClassPlayerPawn *type = PlayerClasses[i].Type; + auto type = PlayerClasses[i].Type; if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0) { @@ -180,7 +180,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet if (players[player].mo != NULL) { - colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet()); + colorset = GetColorSet(players[player].mo->GetClass(), info->GetColorSet()); } if (colorset != NULL) { diff --git a/src/d_player.h b/src/d_player.h index e09db38a3..65f401f2d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -66,39 +66,17 @@ struct FPlayerColorSet ExtraRange Extra[6]; }; -typedef TMap FPlayerColorSetMap; -typedef TMap PainFlashList; +typedef TArray> PainFlashList; +typedef TArray> ColorSetList; -class PClassPlayerPawn : public PClassActor -{ - DECLARE_CLASS(PClassPlayerPawn, PClassActor); -protected: -public: - PClassPlayerPawn(); - virtual void DeriveData(PClass *newclass); - void EnumColorSets(TArray *out); - FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } - void SetPainFlash(FName type, PalEntry color); - bool GetPainFlash(FName type, PalEntry *color) const; +extern PainFlashList PainFlashes; +extern ColorSetList ColorSets; - FString DisplayName; // Display name (used in menus, etc.) - FString SoundClass; // Sound class - FString Face; // Doom status bar face (when used) - FString Portrait; - FString Slot[10]; - FName InvulMode; - FName HealingRadiusType; - double HexenArmor[5]; - BYTE ColorRangeStart; // Skin color range - BYTE ColorRangeEnd; - FPlayerColorSetMap ColorSets; - PainFlashList PainFlashes; -}; -FString GetPrintableDisplayName(PClassPlayerPawn *cls); +FString GetPrintableDisplayName(PClassActor *cls); class APlayerPawn : public AActor { - DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) + DECLARE_CLASS(APlayerPawn, AActor) HAS_OBJECT_POINTERS public: @@ -119,9 +97,9 @@ public: void TweakSpeeds (double &forwardmove, double &sidemove); void MorphPlayerThink (); void ActivateMorphWeapon (); - AWeapon *PickNewWeapon (PClassInventory *ammotype); - AWeapon *BestWeapon (PClassInventory *ammotype); - void CheckWeaponSwitch(PClassInventory *ammotype); + AWeapon *PickNewWeapon (PClassActor *ammotype); + AWeapon *BestWeapon (PClassActor *ammotype); + void CheckWeaponSwitch(PClassActor *ammotype); void GiveDeathmatchInventory (); void FilterCoopRespawnInventory (APlayerPawn *oldplayer); @@ -176,6 +154,17 @@ public: // [SP] ViewBob Multiplier double ViewBob; + // Former class properties that were moved into the object to get rid of the meta class. + FName SoundClass; // Sound class + FName Face; // Doom status bar face (when used) + FName Portrait; + FName Slot[10]; + FName InvulMode; + FName HealingRadiusType; + double HexenArmor[5]; + BYTE ColorRangeStart; // Skin color range + BYTE ColorRangeEnd; + }; // @@ -272,7 +261,7 @@ public: bool CheckSkin (int skin); - PClassPlayerPawn *Type; + PClassActor *Type; DWORD Flags; TArray Skins; }; @@ -344,7 +333,7 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_PlayerClass)); } - PClassPlayerPawn *GetPlayerClassType() const + PClassActor *GetPlayerClassType() const { return PlayerClasses[GetPlayerClassNum()].Type; } @@ -402,7 +391,7 @@ public: userinfo_t userinfo; // [RH] who is this? - PClassPlayerPawn *cls; // class of associated PlayerPawn + PClassActor *cls; // class of associated PlayerPawn float DesiredFOV; // desired field of vision float FOV; // current field of vision @@ -460,7 +449,7 @@ public: short fixedcolormap; // can be set to REDCOLORMAP, etc. short fixedlightlevel; int morphTics; // player is a chicken/pig if > 0 - PClassPlayerPawn *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed + PClassActor *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) TObjPtr PremorphWeapon; // ready weapon before morphing @@ -539,12 +528,16 @@ public: // Make sure that a state is properly set after calling this unless // you are 100% sure the context already implies the layer exists. DPSprite *GetPSprite(PSPLayers layer); + + bool GetPainFlash(FName type, PalEntry *color) const; }; // Bookkeeping on players - state. extern player_t players[MAXPLAYERS]; void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale); +void EnumColorSets(PClassActor *pc, TArray *out); +FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum); inline void AActor::SetFriendPlayer(player_t *player) { diff --git a/src/dobject.cpp b/src/dobject.cpp index 63c7bb688..68f3aab8e 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -301,42 +301,17 @@ DObject::~DObject () PClass *type = GetClass(); if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) { - DObject **probe; - - if (!(ObjectFlags & OF_YesReallyDelete)) + if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released))) { Printf("Warning: '%s' is freed outside the GC process.\n", type != NULL ? type->TypeName.GetChars() : "==some object=="); } - // Find all pointers that reference this object and NULL them. - StaticPointerSubstitution(this, NULL); - - // Now unlink this object from the GC list. - for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) + if (!(ObjectFlags & OF_Released)) { - if (*probe == this) - { - *probe = ObjNext; - if (&ObjNext == GC::SweepPos) - { - GC::SweepPos = probe; - } - break; - } - } - - // If it's gray, also unlink it from the gray list. - if (this->IsGray()) - { - for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) - { - if (*probe == this) - { - *probe = GCNext; - break; - } - } + // Find all pointers that reference this object and NULL them. + StaticPointerSubstitution(this, NULL); + Release(); } } @@ -347,6 +322,41 @@ DObject::~DObject () } } +void DObject::Release() +{ + DObject **probe; + + // Unlink this object from the GC list. + for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) + { + if (*probe == this) + { + *probe = ObjNext; + if (&ObjNext == GC::SweepPos) + { + GC::SweepPos = probe; + } + break; + } + } + + // If it's gray, also unlink it from the gray list. + if (this->IsGray()) + { + for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) + { + if (*probe == this) + { + *probe = GCNext; + break; + } + } + } + ObjNext = nullptr; + GCNext = nullptr; + ObjectFlags |= OF_Released; +} + //========================================================================== // // diff --git a/src/dobject.h b/src/dobject.h index ef7560909..6797d2436 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -93,8 +93,6 @@ enum { CLASSREG_PClass, CLASSREG_PClassActor, - CLASSREG_PClassInventory, - CLASSREG_PClassPlayerPawn, }; struct ClassReg @@ -205,6 +203,7 @@ enum EObjectFlags OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) + OF_Released = 1 << 12, // Object was released from the GC system and should not be processed by GC function }; template class TObjPtr; @@ -457,6 +456,7 @@ public: virtual ~DObject (); inline bool IsKindOf (const PClass *base) const; + inline bool IsKindOf(FName base) const; inline bool IsA (const PClass *type) const; void SerializeUserVars(FSerializer &arc); @@ -467,6 +467,9 @@ public: Class = NULL; } + // Releases the object from the GC, letting the caller care of any maintenance. + void Release(); + // For catching Serialize functions in derived classes // that don't call their base class. void CheckIfSerialized () const; @@ -603,6 +606,7 @@ static inline void GC::WriteBarrier(DObject *pointed) } } +#include "symbols.h" #include "dobjtype.h" inline bool DObject::IsKindOf (const PClass *base) const @@ -610,6 +614,11 @@ inline bool DObject::IsKindOf (const PClass *base) const return base->IsAncestorOf (GetClass ()); } +inline bool DObject::IsKindOf(FName base) const +{ + return GetClass()->IsDescendantOf(base); +} + inline bool DObject::IsA (const PClass *type) const { return (type == GetClass()); diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index df1760dd7..8e9333934 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -254,6 +254,14 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) curr->Destroy(); } + /* + if (curr->IsKindOf(RUNTIME_CLASS(PSymbol))) + Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast(curr)->SymbolName.GetChars()); + else if (curr->IsKindOf(RUNTIME_CLASS(PType))) + Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast(curr)->DescriptiveName()); + else + Printf("Collecting %s\n", curr->GetClass()->TypeName.GetChars()); + */ curr->ObjectFlags |= OF_Cleanup; delete curr; finalized++; @@ -277,7 +285,9 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) void Mark(DObject **obj) { DObject *lobj = *obj; - if (lobj != NULL) + + assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released)); + if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released)) { if (lobj->ObjectFlags & OF_EuthanizeMe) { @@ -361,23 +371,6 @@ static void MarkRoot() } Mark(SectorMarker); Mark(interpolator.Head); - // Mark action functions - if (!FinalGC) - { - FAutoSegIterator probe(ARegHead, ARegTail); - - while (*++probe != NULL) - { - AFuncDesc *afunc = (AFuncDesc *)*probe; - Mark(*(afunc->VMPointer)); - } - } - // Mark types - TypeTable.Mark(); - for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) - { - Mark(PClass::AllClasses[i]); - } // Mark global symbols Namespaces.MarkSymbols(); // Mark bot stuff. @@ -458,8 +451,8 @@ static size_t SingleStep() { // Nothing more to sweep? State = GCS_Finalize; } - assert(old >= AllocBytes); - Estimate -= old - AllocBytes; + //assert(old >= AllocBytes); + Estimate -= MAX(0, old - AllocBytes); return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST; } @@ -559,9 +552,12 @@ void FullGC() void Barrier(DObject *pointing, DObject *pointed) { + assert(pointed->GetClass() < (void*)0x1000000000000000); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointed->IsWhite() && !pointed->IsDead()); assert(State != GCS_Finalize && State != GCS_Pause); + assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong. + if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects. // The invariant only needs to be maintained in the propagate state. if (State == GCS_Propagate) { @@ -776,7 +772,7 @@ CCMD(gc) { if (argv.argc() == 1) { - Printf ("Usage: gc stop|now|full|pause [size]|stepmul [size]\n"); + Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n"); return; } if (stricmp(argv[1], "stop") == 0) @@ -791,6 +787,12 @@ CCMD(gc) { GC::FullGC(); } + else if (stricmp(argv[1], "count") == 0) + { + int cnt = 0; + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++); + Printf("%d active objects counted\n", cnt); + } else if (stricmp(argv[1], "pause") == 0) { if (argv.argc() == 2) @@ -814,3 +816,4 @@ CCMD(gc) } } } + diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 54cc64675..34709cddc 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -64,9 +64,7 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. -FNamespaceManager Namespaces; +FMemArena ClassDataAllocator(32768); // use this for all static class data that can be released in bulk when the type system is shut down. FTypeTable TypeTable; TArray PClass::AllClasses; @@ -153,11 +151,7 @@ void DumpTypeTable() /* PType ******************************************************************/ -IMPLEMENT_CLASS(PType, true, true) - -IMPLEMENT_POINTERS_START(PType) - IMPLEMENT_POINTER(HashNext) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PType, true, false) //========================================================================== // @@ -186,18 +180,6 @@ PType::~PType() { } -//========================================================================== -// -// PType :: PropagateMark -// -//========================================================================== - -size_t PType::PropagateMark() -{ - size_t marked = Symbols.MarkSymbols(); - return marked + Super::PropagateMark(); -} - //========================================================================== // // PType :: WriteValue @@ -458,11 +440,7 @@ IMPLEMENT_CLASS(PCompoundType, true, false) /* PNamedType *************************************************************/ -IMPLEMENT_CLASS(PNamedType, true, true) - -IMPLEMENT_POINTERS_START(PNamedType) - IMPLEMENT_POINTER(Outer) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PNamedType, true, false) //========================================================================== // @@ -490,20 +468,6 @@ void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = TypeName; } -//========================================================================== -// -// PNamedType :: QualifiedName -// -//========================================================================== - -FString PNamedType::QualifiedName() const -{ - FString out; - if (Outer != nullptr) out = Outer->QualifiedName(); - out << "::" << TypeName; - return out; -} - /* PInt *******************************************************************/ IMPLEMENT_CLASS(PInt, false, false) @@ -1331,11 +1295,7 @@ PStateLabel::PStateLabel() /* PPointer ***************************************************************/ -IMPLEMENT_CLASS(PPointer, false, true) - -IMPLEMENT_POINTERS_START(PPointer) - IMPLEMENT_POINTER(PointedType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PPointer, false, false) //========================================================================== // @@ -1538,11 +1498,7 @@ bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) cons /* PClassPointer **********************************************************/ -IMPLEMENT_CLASS(PClassPointer,false, true) - -IMPLEMENT_POINTERS_START(PClassPointer) - IMPLEMENT_POINTER(ClassRestriction) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClassPointer,false, false) //========================================================================== // @@ -1623,11 +1579,7 @@ PClassPointer *NewClassPointer(PClass *restrict) /* PEnum ******************************************************************/ -IMPLEMENT_CLASS(PEnum, false, true) - -IMPLEMENT_POINTERS_START(PEnum) - IMPLEMENT_POINTER(Outer) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PEnum, false, false) //========================================================================== // @@ -1679,11 +1631,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) /* PArray *****************************************************************/ -IMPLEMENT_CLASS(PArray, false, true) - -IMPLEMENT_POINTERS_START(PArray) - IMPLEMENT_POINTER(ElementType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PArray, false, false) //========================================================================== // @@ -1916,11 +1864,7 @@ PResizableArray *NewResizableArray(PType *type) /* PDynArray **************************************************************/ -IMPLEMENT_CLASS(PDynArray, false, true) - -IMPLEMENT_POINTERS_START(PDynArray) - IMPLEMENT_POINTER(ElementType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PDynArray, false, false) //========================================================================== // @@ -2056,7 +2000,7 @@ void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const { - if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ElementType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { // Add to the list of pointer arrays for this class. special->Push(offset); @@ -2171,12 +2115,7 @@ PDynArray *NewDynArray(PType *type) /* PMap *******************************************************************/ -IMPLEMENT_CLASS(PMap, false, true) - -IMPLEMENT_POINTERS_START(PMap) - IMPLEMENT_POINTER(KeyType) - IMPLEMENT_POINTER(ValueType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PMap, false, false) //========================================================================== // @@ -2428,7 +2367,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) if (Symbols.AddSymbol(field) == nullptr) { // name is already in use - delete field; + field->Destroy(); return nullptr; } Fields.Push(field); @@ -2459,18 +2398,6 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD f return field; } -//========================================================================== -// -// PStruct :: PropagateMark -// -//========================================================================== - -size_t PStruct::PropagateMark() -{ - GC::MarkArray(Fields); - return Fields.Size() * sizeof(void*) + Super::PropagateMark(); -} - //========================================================================== // // NewStruct @@ -2683,76 +2610,9 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray return static_cast(proto); } -/* PFunction **************************************************************/ - -IMPLEMENT_CLASS(PFunction, false, false) - -//========================================================================== -// -// PFunction :: PropagataMark -// -//========================================================================== - -size_t PFunction::PropagateMark() -{ - for (unsigned i = 0; i < Variants.Size(); ++i) - { - GC::Mark(Variants[i].Proto); - GC::Mark(Variants[i].Implementation); - } - return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); -} - -//========================================================================== -// -// PFunction :: AddVariant -// -// Adds a new variant for this function. Does not check if a matching -// variant already exists. -// -//========================================================================== - -unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) -{ - Variant variant; - - // I do not think we really want to deal with overloading here... - assert(Variants.Size() == 0); - - variant.Flags = flags; - variant.UseFlags = useflags; - variant.Proto = proto; - variant.ArgFlags = std::move(argflags); - variant.ArgNames = std::move(argnames); - variant.Implementation = impl; - if (impl != nullptr) impl->Proto = proto; - - // SelfClass can differ from OwningClass, but this is variant-dependent. - // Unlike the owner there can be cases where different variants can have different SelfClasses. - // (Of course only if this ever gets enabled...) - if (flags & VARF_Method) - { - assert(proto->ArgumentTypes.Size() > 0); - auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); - assert(selftypeptr != nullptr); - variant.SelfClass = dyn_cast(selftypeptr->PointedType); - assert(variant.SelfClass != nullptr); - } - else - { - variant.SelfClass = nullptr; - } - - return Variants.Push(variant); -} - /* PClass *****************************************************************/ -IMPLEMENT_CLASS(PClass, false, true) - -IMPLEMENT_POINTERS_START(PClass) - IMPLEMENT_POINTER(ParentClass) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClass, false, false) //========================================================================== // @@ -2947,6 +2807,7 @@ void PClass::StaticShutdown () *p = nullptr; } FunctionPtrList.Clear(); + VMFunction::DeleteAll(); // Make a full garbage collection here so that all destroyed but uncollected higher level objects // that still exist are properly taken down before the low level data is deleted. @@ -2957,18 +2818,10 @@ void PClass::StaticShutdown () bVMOperational = false; // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. + bShutdown = true; TypeTable.Clear(); Namespaces.ReleaseSymbols(); - FlatpointerArena.FreeAllBlocks(); - bShutdown = true; - - for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i) - { - PClass *type = PClass::AllClasses[i]; - PClass::AllClasses[i] = NULL; - type->Destroy(); - } - + ClassDataAllocator.FreeAllBlocks(); AllClasses.Clear(); PClassActor::AllActorClasses.Clear(); @@ -3056,8 +2909,6 @@ PClass *ClassReg::RegisterClass() { &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, - &PClassInventory::RegistrationInfo, - &PClassPlayerPawn::RegistrationInfo, }; // Skip classes that have already been registered @@ -3341,48 +3192,31 @@ void PClass::DeriveData(PClass *newclass) PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { - assert (size >= Size); + assert(size >= Size); PClass *type; bool notnew; - size_t bucket; - PClass *existclass = static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket)); + const PClass *existclass = FindClass(name); // This is a placeholder so fill it in - if (existclass != nullptr) + if (existclass != NULL && existclass->Size == (unsigned)-1) { - if (existclass->Size == TentativeClass) + type = const_cast(existclass); + if (!IsDescendantOf(type->ParentClass)) { - if (!IsDescendantOf(existclass->ParentClass)) - { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), existclass->ParentClass->TypeName.GetChars()); - } - - if (size == TentativeClass) - { - // see if we can reuse the existing class. This is only possible if the inheritance is identical. Otherwise it needs to be replaced. - if (this == existclass->ParentClass) - { - existclass->ObjectFlags &= OF_Transient; - return existclass; - } - } - notnew = true; - } - else - { - // a different class with the same name already exists. Let the calling code deal with this. - return nullptr; + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } + DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); + notnew = true; } else { + type = static_cast(GetClass()->CreateNew()); notnew = false; } - // Create a new type object of the same type as us. (We may be a derived class of PClass.) - type = static_cast(GetClass()->CreateNew()); - + type->TypeName = name; + type->bRuntimeClass = true; Derive(type, name); type->Size = size; if (size != TentativeClass) @@ -3391,22 +3225,13 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->Virtuals = Virtuals; DeriveData(type); } + else + type->ObjectFlags &= OF_Transient; + if (!notnew) { type->InsertIntoHash(); } - else - { - TypeTable.ReplaceType(type, existclass, bucket); - StaticPointerSubstitution(existclass, type, true); // replace the old one, also in the actor defaults. - // Delete the old class from the class lists, both the full one and the actor list. - auto index = PClassActor::AllActorClasses.Find(static_cast(existclass)); - if (index < PClassActor::AllActorClasses.Size()) PClassActor::AllActorClasses.Delete(index); - index = PClass::AllClasses.Find(existclass); - if (index < PClass::AllClasses.Size()) PClass::AllClasses.Delete(index); - // Now we can destroy the old class as nothing should reference it anymore - existclass->Destroy(); - } return type; } @@ -3577,7 +3402,7 @@ void PClass::BuildFlatPointers () { } // Concatenate them into a new array - size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); + size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); @@ -3643,7 +3468,7 @@ void PClass::BuildArrayPointers() } // Concatenate them into a new array - size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); + size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); @@ -3721,31 +3546,6 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si return nullptr; } -//========================================================================== -// -// FTypeTable :: ReplaceType -// -// Replaces an existing type in the table with a new version of the same -// type. For use when redefining actors in DECORATE. Does nothing if the -// old version is not in the table. -// -//========================================================================== - -void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) -{ - for (PType **type_p = &TypeHash[bucket]; *type_p != nullptr; type_p = &(*type_p)->HashNext) - { - PType *type = *type_p; - if (type == oldtype) - { - newtype->HashNext = type->HashNext; - type->HashNext = nullptr; - *type_p = newtype; - break; - } - } -} - //========================================================================== // // FTypeTable :: AddType - Fully Parameterized Version @@ -3762,7 +3562,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t type->TypeTableType = metatype; type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; - GC::WriteBarrier(type); + type->Release(); } //========================================================================== @@ -3785,7 +3585,7 @@ void FTypeTable::AddType(PType *type) type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; - GC::WriteBarrier(type); + type->Release(); } //========================================================================== @@ -3824,36 +3624,23 @@ size_t FTypeTable::Hash(const PClass *p1, intptr_t p2, intptr_t p3) } } -//========================================================================== -// -// FTypeTable :: Mark -// -// Mark all types in this table for the garbage collector. -// -//========================================================================== - -void FTypeTable::Mark() -{ - for (int i = HASH_SIZE - 1; i >= 0; --i) - { - if (TypeHash[i] != nullptr) - { - GC::Mark(TypeHash[i]); - } - } -} - //========================================================================== // // FTypeTable :: Clear // -// Removes everything from the table. We let the garbage collector worry -// about deleting them. -// //========================================================================== void FTypeTable::Clear() { + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr;) + { + auto next = ty->HashNext; + delete ty; + ty = next; + } + } memset(TypeHash, 0, sizeof(TypeHash)); } @@ -3863,232 +3650,3 @@ CCMD(typetable) DumpTypeTable(); } -// Symbol tables ------------------------------------------------------------ - -IMPLEMENT_CLASS(PTypeBase, true, false); -IMPLEMENT_CLASS(PSymbol, true, false); -IMPLEMENT_CLASS(PSymbolConst, false, false); -IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); -IMPLEMENT_CLASS(PSymbolConstString, false, false); -IMPLEMENT_CLASS(PSymbolTreeNode, false, false) -IMPLEMENT_CLASS(PSymbolType, false, true) - -IMPLEMENT_POINTERS_START(PSymbolType) - IMPLEMENT_POINTER(Type) -IMPLEMENT_POINTERS_END - -IMPLEMENT_CLASS(PSymbolVMFunction, false, true) - -IMPLEMENT_POINTERS_START(PSymbolVMFunction) - IMPLEMENT_POINTER(Function) -IMPLEMENT_POINTERS_END - -//========================================================================== -// -// -// -//========================================================================== - -PSymbol::~PSymbol() -{ -} - -PSymbolTable::PSymbolTable() -: ParentSymbolTable(nullptr) -{ -} - -PSymbolTable::PSymbolTable(PSymbolTable *parent) -: ParentSymbolTable(parent) -{ -} - -PSymbolTable::~PSymbolTable () -{ - ReleaseSymbols(); -} - -size_t PSymbolTable::MarkSymbols() -{ - size_t count = 0; - MapType::Iterator it(Symbols); - MapType::Pair *pair; - - while (it.NextPair(pair)) - { - GC::Mark(pair->Value); - count++; - } - return count * sizeof(*pair); -} - -void PSymbolTable::ReleaseSymbols() -{ - // The GC will take care of deleting the symbols. We just need to - // clear our references to them. - Symbols.Clear(); -} - -void PSymbolTable::SetParentTable (PSymbolTable *parent) -{ - ParentSymbolTable = parent; -} - -PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const -{ - PSymbol * const *value = Symbols.CheckKey(symname); - if (value == nullptr && searchparents && ParentSymbolTable != nullptr) - { - return ParentSymbolTable->FindSymbol(symname, searchparents); - } - return value != nullptr ? *value : nullptr; -} - -PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) -{ - PSymbol * const *value = Symbols.CheckKey(symname); - if (value == nullptr) - { - if (ParentSymbolTable != nullptr) - { - return ParentSymbolTable->FindSymbolInTable(symname, symtable); - } - symtable = nullptr; - return nullptr; - } - symtable = this; - return *value; -} - -PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) -{ - // Symbols that already exist are not inserted. - if (Symbols.CheckKey(sym->SymbolName) != nullptr) - { - return nullptr; - } - Symbols.Insert(sym->SymbolName, sym); - return sym; -} - -void PSymbolTable::RemoveSymbol(PSymbol *sym) -{ - auto mysym = Symbols.CheckKey(sym->SymbolName); - if (mysym == nullptr || *mysym != sym) return; - Symbols.Remove(sym->SymbolName); -} - -PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) -{ - // If a symbol with a matching name exists, take its place and return it. - PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); - if (symslot != nullptr) - { - PSymbol *oldsym = *symslot; - *symslot = newsym; - return oldsym; - } - // Else, just insert normally and return nullptr since there was no - // symbol to replace. - Symbols.Insert(newsym->SymbolName, newsym); - return nullptr; -} - -IMPLEMENT_CLASS(PNamespace, false, true) - -IMPLEMENT_POINTERS_START(PNamespace) -IMPLEMENT_POINTER(Parent) -IMPLEMENT_POINTERS_END - -PNamespace::PNamespace(int filenum, PNamespace *parent) -{ - Parent = parent; - if (parent) Symbols.SetParentTable(&parent->Symbols); - FileNum = filenum; -} - -size_t PNamespace::PropagateMark() -{ - GC::Mark(Parent); - return Symbols.MarkSymbols() + 1; -} - -FNamespaceManager::FNamespaceManager() -{ - GlobalNamespace = nullptr; -} - -PNamespace *FNamespaceManager::NewNamespace(int filenum) -{ - PNamespace *parent = nullptr; - // The parent will be the last namespace with this or a lower filenum. - // This ensures that DECORATE won't see the symbols of later files. - for (int i = AllNamespaces.Size() - 1; i >= 0; i--) - { - if (AllNamespaces[i]->FileNum <= filenum) - { - parent = AllNamespaces[i]; - break; - } - } - auto newns = new PNamespace(filenum, parent); - AllNamespaces.Push(newns); - return newns; -} - -size_t FNamespaceManager::MarkSymbols() -{ - for (auto ns : AllNamespaces) - { - GC::Mark(ns); - } - return AllNamespaces.Size(); -} - -void FNamespaceManager::ReleaseSymbols() -{ - GlobalNamespace = nullptr; - AllNamespaces.Clear(); -} - -// removes all symbols from the symbol tables. -// After running the compiler these are not needed anymore. -// Only the namespaces themselves are kept because the type table references them. -int FNamespaceManager::RemoveSymbols() -{ - int count = 0; - for (auto ns : AllNamespaces) - { - count += ns->Symbols.Symbols.CountUsed(); - ns->Symbols.ReleaseSymbols(); - } - return count; -} - -void RemoveUnusedSymbols() -{ - // Global symbols are not needed anymore after running the compiler. - int count = Namespaces.RemoveSymbols(); - - // We do not need any non-field and non-function symbols in structs and classes anymore. - for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) - { - for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) - { - if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) - { - auto it = ty->Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction))) - { - ty->Symbols.RemoveSymbol(pair->Value); - count++; - } - } - } - } - } - DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count); -} diff --git a/src/dobjtype.h b/src/dobjtype.h index 3858585e9..cc0a17da8 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -39,36 +39,6 @@ enum VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature }; -// Symbol information ------------------------------------------------------- - -class PTypeBase : public DObject -{ - DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) - -public: - virtual FString QualifiedName() const - { - return ""; - } -}; - -class PSymbol : public PTypeBase -{ - DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase); -public: - virtual ~PSymbol(); - - virtual FString QualifiedName() const - { - return SymbolName.GetChars(); - } - - FName SymbolName; - -protected: - PSymbol(FName name) { SymbolName = name; } -}; - // An action function ------------------------------------------------------- struct FState; @@ -79,101 +49,6 @@ struct VMReturn; class VMFunction; struct FNamespaceManager; -// A VM function ------------------------------------------------------------ - -class PSymbolVMFunction : public PSymbol -{ - DECLARE_CLASS(PSymbolVMFunction, PSymbol); - HAS_OBJECT_POINTERS; -public: - VMFunction *Function; - - PSymbolVMFunction(FName name) : PSymbol(name) {} - PSymbolVMFunction() : PSymbol(NAME_None) {} -}; - -// A symbol for a type ------------------------------------------------------ - -class PSymbolType : public PSymbol -{ - DECLARE_CLASS(PSymbolType, PSymbol); - HAS_OBJECT_POINTERS; -public: - class PType *Type; - - PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} - PSymbolType() : PSymbol(NAME_None) {} -}; - -// A symbol table ----------------------------------------------------------- - -struct PSymbolTable -{ - PSymbolTable(); - PSymbolTable(PSymbolTable *parent); - ~PSymbolTable(); - - size_t MarkSymbols(); - - // Sets the table to use for searches if this one doesn't contain the - // requested symbol. - void SetParentTable (PSymbolTable *parent); - PSymbolTable *GetParentTable() const - { - return ParentSymbolTable; - } - - // Finds a symbol in the table, optionally searching parent tables - // as well. - PSymbol *FindSymbol (FName symname, bool searchparents) const; - - // Like FindSymbol with searchparents set true, but also returns the - // specific symbol table the symbol was found in. - PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); - - - // Places the symbol in the table and returns a pointer to it or NULL if - // a symbol with the same name is already in the table. This symbol is - // not copied and will be freed when the symbol table is destroyed. - PSymbol *AddSymbol (PSymbol *sym); - - // Similar to AddSymbol but always succeeds. Returns the symbol that used - // to be in the table with this name, if any. - PSymbol *ReplaceSymbol(PSymbol *sym); - - void RemoveSymbol(PSymbol *sym); - - // Frees all symbols from this table. - void ReleaseSymbols(); - - typedef TMap MapType; - - MapType::Iterator GetIterator() - { - return MapType::Iterator(Symbols); - } - -private: - - PSymbolTable *ParentSymbolTable; - MapType Symbols; - - friend class DObject; - friend struct FNamespaceManager; -}; - -// A symbol for a compiler tree node ---------------------------------------- - -class PSymbolTreeNode : public PSymbol -{ - DECLARE_CLASS(PSymbolTreeNode, PSymbol); -public: - struct ZCC_TreeNode *Node; - - PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {} - PSymbolTreeNode() : PSymbol(NAME_None) {} -}; - // Basic information shared by all types ------------------------------------ // Only one copy of a type is ever instantiated at one time. @@ -202,7 +77,6 @@ struct ZCC_ExprConstant; class PType : public PTypeBase { DECLARE_ABSTRACT_CLASS(PType, PTypeBase) - HAS_OBJECT_POINTERS; protected: public: @@ -296,8 +170,6 @@ public: const char *DescriptiveName() const; - size_t PropagateMark(); - static void StaticInit(); }; @@ -335,7 +207,6 @@ class PCompoundType : public PType class PNamedType : public PCompoundType { DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); - HAS_OBJECT_POINTERS; public: PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name @@ -349,7 +220,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - virtual FString QualifiedName() const; }; // Basic types -------------------------------------------------------------- @@ -492,7 +362,6 @@ public: class PPointer : public PBasicType { DECLARE_CLASS(PPointer, PBasicType); - HAS_OBJECT_POINTERS; public: PPointer(); PPointer(PType *pointsat, bool isconst = false); @@ -525,7 +394,6 @@ public: class PClassPointer : public PPointer { DECLARE_CLASS(PClassPointer, PPointer); - HAS_OBJECT_POINTERS; public: PClassPointer(class PClass *restrict = nullptr); @@ -537,58 +405,11 @@ public: virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; }; -// Struct/class fields ------------------------------------------------------ - -// A PField describes a symbol that takes up physical space in the struct. -class PField : public PSymbol -{ - DECLARE_CLASS(PField, PSymbol); - HAS_OBJECT_POINTERS -public: - PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0); - - size_t Offset; - PType *Type; - DWORD Flags; - int BitValue; -protected: - PField(); -}; - -// Struct/class fields ------------------------------------------------------ - -// A PField describes a symbol that takes up physical space in the struct. -class PProperty : public PSymbol -{ - DECLARE_CLASS(PProperty, PSymbol); -public: - PProperty(FName name, TArray &variables); - - TArray Variables; - -protected: - PProperty(); -}; - -class PPropFlag : public PSymbol -{ - DECLARE_CLASS(PPropFlag, PSymbol); -public: - PPropFlag(FName name, PField *offset, int bitval); - - PField *Offset; - int bitval; - -protected: - PPropFlag(); -}; - // Compound types ----------------------------------------------------------- class PEnum : public PInt { DECLARE_CLASS(PEnum, PInt); - HAS_OBJECT_POINTERS; public: PEnum(FName name, PTypeBase *outer); @@ -601,7 +422,6 @@ protected: class PArray : public PCompoundType { DECLARE_CLASS(PArray, PCompoundType); - HAS_OBJECT_POINTERS; public: PArray(PType *etype, unsigned int ecount); @@ -625,7 +445,6 @@ protected: class PResizableArray : public PArray { DECLARE_CLASS(PResizableArray, PArray); - HAS_OBJECT_POINTERS; public: PResizableArray(PType *etype); @@ -639,7 +458,6 @@ protected: class PDynArray : public PCompoundType { DECLARE_CLASS(PDynArray, PCompoundType); - HAS_OBJECT_POINTERS; public: PDynArray(PType *etype, PStruct *backing); @@ -663,7 +481,6 @@ protected: class PMap : public PCompoundType { DECLARE_CLASS(PMap, PCompoundType); - HAS_OBJECT_POINTERS; public: PMap(PType *keytype, PType *valtype); @@ -692,8 +509,6 @@ public: 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); - size_t PropagateMark(); - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; @@ -730,36 +545,6 @@ protected: PPrototype(); }; -// TBD: Should we really support overloading? -class PFunction : public PSymbol -{ - DECLARE_CLASS(PFunction, PSymbol); -public: - struct Variant - { - PPrototype *Proto; - VMFunction *Implementation; - TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes - TArray ArgNames; // we need the names to access them later when the function gets compiled. - uint32_t Flags; - int UseFlags; - PStruct *SelfClass; - }; - TArray Variants; - PStruct *OwningClass = nullptr; - - unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); - int GetImplicitArgs() - { - if (Variants[0].Flags & VARF_Action) return 3; - else if (Variants[0].Flags & VARF_Method) return 1; - return 0; - } - - size_t PropagateMark(); - - PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} -}; // Meta-info for every class derived from DObject --------------------------- @@ -771,7 +556,6 @@ enum class PClass : public PNativeStruct { DECLARE_CLASS(PClass, PNativeStruct); - HAS_OBJECT_POINTERS; protected: // We unravel _WITH_META here just as we did for PType. TArray SpecialInits; @@ -828,11 +612,24 @@ public: } return false; } + inline bool IsDescendantOf(const PClass *ti) const { return ti->IsAncestorOf(this); } + inline bool IsDescendantOf(FName ti) const + { + auto me = this; + while (me) + { + if (me->TypeName == ti) + return true; + me = me->ParentClass; + } + return false; + } + // Find a type, given its name. const PClass *FindParentClass(FName name) const; PClass *FindParentClass(FName name) { return const_cast(const_cast(this)->FindParentClass(name)); } @@ -865,10 +662,8 @@ struct FTypeTable PType *TypeHash[HASH_SIZE]; PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); - void ReplaceType(PType *newtype, PType *oldtype, size_t bucket); void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket); void AddType(PType *type); - void Mark(); void Clear(); static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); @@ -915,82 +710,6 @@ extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; extern PPointer *TypeVoidPtr; -// A constant value --------------------------------------------------------- - -class PSymbolConst : public PSymbol -{ - DECLARE_CLASS(PSymbolConst, PSymbol); -public: - PType *ValueType; - - PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} - PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} -}; - -// A constant numeric value ------------------------------------------------- - -class PSymbolConstNumeric : public PSymbolConst -{ - DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); -public: - union - { - int Value; - double Float; - void *Pad; - }; - - PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} - PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} - PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} - PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} - PSymbolConstNumeric() {} -}; - -// A constant string value -------------------------------------------------- - -class PSymbolConstString : public PSymbolConst -{ - DECLARE_CLASS(PSymbolConstString, PSymbolConst); -public: - FString Str; - - PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {} - PSymbolConstString() {} -}; - -// Namespaces -------------------------------------------------- - -class PNamespace : public PTypeBase -{ - DECLARE_CLASS(PNamespace, PTypeBase) - HAS_OBJECT_POINTERS; - -public: - PSymbolTable Symbols; - PNamespace *Parent; - int FileNum; // This is for blocking DECORATE access to later files. - - PNamespace() {} - PNamespace(int filenum, PNamespace *parent); - size_t PropagateMark(); -}; - -struct FNamespaceManager -{ - PNamespace *GlobalNamespace; - TArray AllNamespaces; - - FNamespaceManager(); - PNamespace *NewNamespace(int filenum); - size_t MarkSymbols(); - void ReleaseSymbols(); - int RemoveSymbols(); -}; - -extern FNamespaceManager Namespaces; - - // Enumerations for serializing types in an archive ------------------------- inline bool &DObject::BoolVar(FName field) diff --git a/src/doomtype.h b/src/doomtype.h index 248aee33b..c88ec842d 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -41,6 +41,8 @@ #endif #include +#include +#include #include "tarray.h" #include "name.h" #include "zstring.h" @@ -155,12 +157,9 @@ struct PalEntry #endif }; -class PClassInventory; - class FTextureID { friend class FTextureManager; - friend FTextureID GetHUDIcon(PClassInventory *cls); friend void R_InitSpriteDefs(); public: diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 0ee391e21..68d940704 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -340,7 +340,7 @@ inline int T_FindFirstSectorFromTag(int tagnum) // Doom index is only supported for the 4 original ammo types // //========================================================================== -static PClassInventory * T_GetAmmo(const svalue_t &t) +static PClassActor * T_GetAmmo(const svalue_t &t) { const char * p; @@ -361,8 +361,8 @@ static PClassInventory * T_GetAmmo(const svalue_t &t) } p=DefAmmo[ammonum]; } - PClassInventory * am=dyn_cast(PClass::FindActor(p)); - if (am == NULL) + auto am = PClass::FindActor(p); + if (am == NULL || !am->IsKindOf(PClass::FindClass(NAME_Ammo))) { script_error("unknown ammo type : %s", p); return NULL; @@ -2434,8 +2434,8 @@ static void FS_GiveInventory (AActor *actor, const char * type, int amount) { type = "BasicArmorPickup"; } - PClassInventory * info = dyn_cast(PClass::FindActor (type)); - if (info == NULL) + auto info = PClass::FindActor (type); + if (info == NULL || !info->IsKindOf(RUNTIME_CLASS(AInventory))) { Printf ("Unknown inventory item: %s\n", type); return; @@ -2564,7 +2564,7 @@ void FParser::SF_PlayerKeys(void) void FParser::SF_PlayerAmmo(void) { int playernum, amount; - PClassInventory * ammotype; + PClassActor * ammotype; if (CheckArgs(2)) { @@ -2600,7 +2600,7 @@ void FParser::SF_PlayerAmmo(void) void FParser::SF_MaxPlayerAmmo() { int playernum, amount; - PClassInventory * ammotype; + PClassActor * ammotype; if (CheckArgs(2)) { @@ -2629,7 +2629,7 @@ void FParser::SF_MaxPlayerAmmo() for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory) { - if (item->IsKindOf(PClass::FindClass(NAME_BackpackItem))) + if (item->IsKindOf(NAME_BackpackItem)) { if (t_argc>=4) amount = intvalue(t_argv[3]); else amount*=2; @@ -2676,7 +2676,7 @@ void FParser::SF_PlayerWeapon() return; } auto ti = PClass::FindActor(WeaponNames[weaponnum]); - if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!ti || !ti->IsDescendantOf(NAME_Weapon)) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2712,7 +2712,7 @@ void FParser::SF_PlayerWeapon() { if (!wp) { - AWeapon * pw=players[playernum].PendingWeapon; + auto pw=players[playernum].PendingWeapon; players[playernum].mo->GiveInventoryType(ti); players[playernum].PendingWeapon=pw; } @@ -2757,7 +2757,7 @@ void FParser::SF_PlayerSelectedWeapon() return; } auto ti = PClass::FindActor(WeaponNames[weaponnum]); - if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!ti || !ti->IsDescendantOf(NAME_Weapon)) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2862,7 +2862,7 @@ void FParser::SF_SetWeapon() { AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1]))); - if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item == NULL || !item->IsKindOf(NAME_Weapon)) { } else if (players[playernum].ReadyWeapon == item) @@ -2874,7 +2874,7 @@ void FParser::SF_SetWeapon() } else { - AWeapon *weap = static_cast (item); + auto weap = static_cast (item); if (weap->CheckAmmo (AWeapon::EitherFire, false)) { diff --git a/src/g_game.cpp b/src/g_game.cpp index e5c327472..9417f40b9 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1361,7 +1361,7 @@ void G_PlayerReborn (int player) BYTE currclass; userinfo_t userinfo; // [RH] Save userinfo APlayerPawn *actor; - PClassPlayerPawn *cls; + PClassActor *cls; FString log; DBot *Bot; //Added by MC: diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index 0ad6b72f1..75d98c2c7 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -187,7 +187,7 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc) keygroup->anykeylist.Push (k); //... but only keys get key numbers! - if (mi->IsDescendantOf(PClass::FindActor(NAME_Key))) + if (mi->IsDescendantOf(NAME_Key)) { if (!ignorekey && GetDefaultByType(mi)->special1 == 0) diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 66f51e92e..53e7d84ed 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -25,54 +25,6 @@ EXTERN_CVAR(Bool, sv_unlimited_pickup) -IMPLEMENT_CLASS(PClassInventory, false, false) - -PClassInventory::PClassInventory() -{ - GiveQuest = 0; - AltHUDIcon.SetNull(); -} - -void PClassInventory::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory))); - Super::DeriveData(newclass); - PClassInventory *newc = static_cast(newclass); - - newc->PickupMsg = PickupMsg; - newc->GiveQuest = GiveQuest; - newc->AltHUDIcon = AltHUDIcon; - newc->ForbiddenToPlayerClass = ForbiddenToPlayerClass; - newc->RestrictedToPlayerClass = RestrictedToPlayerClass; -} - -size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass) -{ - size_t changed = Super::PointerSubstitution(oldclass, newclass); - AInventory *def = (AInventory*)Defaults; - if (def != NULL) - { - if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); - for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) - { - if (ForbiddenToPlayerClass[i] == oldclass) - { - ForbiddenToPlayerClass[i] = static_cast(newclass); - changed++; - } - } - for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) - { - if (RestrictedToPlayerClass[i] == oldclass) - { - RestrictedToPlayerClass[i] = static_cast(newclass); - changed++; - } - } - } - return changed; -} - void AInventory::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); @@ -98,8 +50,8 @@ DEFINE_FIELD(AInventory, DropTime) DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) -DEFINE_FIELD(PClassInventory, PickupMsg) -DEFINE_FIELD(PClassInventory, GiveQuest) +DEFINE_FIELD(AInventory, GiveQuest) +DEFINE_FIELD(PClassActor, PickupMsg) //=========================================================================== // @@ -163,7 +115,8 @@ void AInventory::Serialize(FSerializer &arc) ("icon", Icon, def->Icon) ("pickupsound", PickupSound, def->PickupSound) ("spawnpointclass", SpawnPointClass, def->SpawnPointClass) - ("droptime", DropTime, def->DropTime); + ("droptime", DropTime, def->DropTime) + ("givequest", GiveQuest, def->GiveQuest); } //=========================================================================== @@ -548,7 +501,7 @@ DEFINE_ACTION_FUNCTION(AInventory, CanPickup) if (!toucher) ACTION_RETURN_BOOL(false); - PClassInventory *ai = self->GetClass(); + auto ai = self->GetClass(); // Is the item restricted to certain player classes? if (ai->RestrictedToPlayerClass.Size() != 0) { diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index be6280c0a..817fcf176 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -9,7 +9,6 @@ class player_t; class FConfigFile; -class PClassPlayerPawn; struct visstyle_t; /************************************************************************/ @@ -50,25 +49,9 @@ enum }; -class PClassInventory : public PClassActor -{ - DECLARE_CLASS(PClassInventory, PClassActor) -public: - PClassInventory(); - virtual void DeriveData(PClass *newclass); - virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass); - void Finalize(FStateDefinitions &statedef); - - FString PickupMsg; - int GiveQuest; // Optionally give one of the quest items. - FTextureID AltHUDIcon; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; -}; - class AInventory : public AActor { - DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) + DECLARE_CLASS(AInventory, AActor) HAS_OBJECT_POINTERS public: @@ -104,6 +87,8 @@ public: FTextureID Icon; // Icon to show on status bar or HUD int DropTime; // Countdown after dropping PClassActor *SpawnPointClass; // For respawning like Heretic's mace + int GiveQuest; // Optionally give one of the quest items. + FTextureID AltHUDIcon; DWORD ItemFlags; PClassActor *PickupFlash; // actor to spawn as pickup flash diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index a916531be..af180a4ea 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -64,9 +64,6 @@ IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(Ammo1) IMPLEMENT_POINTER(Ammo2) IMPLEMENT_POINTER(SisterWeapon) - IMPLEMENT_POINTER(AmmoType1) - IMPLEMENT_POINTER(AmmoType2) - IMPLEMENT_POINTER(SisterWeaponType) IMPLEMENT_POINTERS_END DEFINE_FIELD(AWeapon, WeaponFlags) @@ -528,7 +525,7 @@ bool FWeaponSlot::AddWeapon(PClassActor *type) return false; } - if (!type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!type->IsDescendantOf(NAME_Weapon)) { Printf("Can't add non-weapon %s to weapon slots\n", type->TypeName.GetChars()); return false; @@ -635,7 +632,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[j].Type)); - if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(NAME_Weapon)) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -650,7 +647,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[i].Type)); - if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(NAME_Weapon)) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -982,7 +979,7 @@ void FWeaponSlots::AddExtraWeapons() { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!cls->IsDescendantOf(NAME_Weapon)) { continue; } @@ -1058,7 +1055,7 @@ void FWeaponSlots::SetFromGameInfo() // //=========================================================================== -void FWeaponSlots::StandardSetup(PClassPlayerPawn *type) +void FWeaponSlots::StandardSetup(PClassActor *type) { SetFromPlayer(type); AddExtraWeapons(); @@ -1151,14 +1148,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) // //=========================================================================== -void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type) +void FWeaponSlots::SetFromPlayer(PClassActor *type) { Clear(); + auto Slot = ((APlayerPawn*)GetDefaultByType(type))->Slot; for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) { - if (!type->Slot[i].IsEmpty()) + if (Slot[i] != NAME_None) { - Slots[i].AddWeaponList(type->Slot[i], false); + Slots[i].AddWeaponList(Slot[i], false); } } } @@ -1342,7 +1340,7 @@ CCMD (weaponsection) //=========================================================================== void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) { - if (type != nullptr && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (type != nullptr && type->IsDescendantOf(NAME_Weapon)) { switch (AddDefaultWeapon(slot, type)) { @@ -1441,7 +1439,7 @@ void P_SetupWeapons_ntohton() { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls->IsDescendantOf(NAME_Weapon)) { Weapons_ntoh.Push(static_cast(cls)); } diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 50862bc47..606c96e98 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -65,8 +65,8 @@ struct FWeaponSlots ESlotDef AddDefaultWeapon (int slot, PClassActor *type); void AddExtraWeapons(); void SetFromGameInfo(); - void SetFromPlayer(PClassPlayerPawn *type); - void StandardSetup(PClassPlayerPawn *type); + void SetFromPlayer(PClassActor *type); + void StandardSetup(PClassActor *type); void LocalSetup(PClassActor *type); void SendDifferences(int playernum, const FWeaponSlots &other); int RestoreSlots (FConfigFile *config, const char *section); @@ -92,7 +92,7 @@ class AWeapon : public AStateProvider HAS_OBJECT_POINTERS public: DWORD WeaponFlags; - PClassInventory *AmmoType1, *AmmoType2; // Types of ammo used by this weapon + PClassActor *AmmoType1, *AmmoType2; // Types of ammo used by this weapon int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon int AmmoUse1, AmmoUse2; // How much ammo to use with each shot diff --git a/src/g_pch.h b/src/g_pch.h index 2c3676f5a..e5653796b 100644 --- a/src/g_pch.h +++ b/src/g_pch.h @@ -20,3 +20,4 @@ #include #include #include +#include diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index aed8457f8..2d1a95cdd 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -42,7 +42,7 @@ void A_Unblock(AActor *self, bool drop) // If the actor has attached metadata for items to drop, drop those. if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] { - DDropItem *di = self->GetDropItems(); + auto di = self->GetDropItems(); if (di != NULL) { diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 0c95c77b8..359e8a174 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -33,7 +33,7 @@ void InitAllPowerupEffects(AInventory *item); // //--------------------------------------------------------------------------- -bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) +bool P_MorphPlayer (player_t *activator, player_t *p, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) { AInventory *item; APlayerPawn *morphed; @@ -290,8 +290,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // and for the original DOOM status bar. if (player == &players[consoleplayer]) { - FString face = pmo->GetClass()->Face; - if (face.IsNotEmpty() && strcmp(face, "None") != 0) + FName face = pmo->Face; + if (face != NAME_None) { // Assume root-level base skin to begin with size_t skinindex = 0; @@ -337,7 +337,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, if (correctweapon) { // Better "lose morphed weapon" semantics PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); - if (morphweapon != nullptr && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (morphweapon != nullptr && morphweapon->IsDescendantOf(NAME_Weapon)) { AWeapon *OriginalMorphWeapon = static_cast(mo->FindInventory (morphweapon)); if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon)) @@ -367,7 +367,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, if (hxarmor != nullptr) { double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr); - Slots[4] = mo->GetClass()->HexenArmor[0]; + Slots[4] = mo->HexenArmor[0]; } return true; } diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index e770e418e..1c0047c69 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -35,7 +35,7 @@ class AActor; class player_t; class AMorphedMonster; -bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0, +bool P_MorphPlayer (player_t *activator, player_t *player, PClassActor *morphclass, int duration = 0, int style = 0, PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL); bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false); bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0, diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 4ab0c8133..d39c16d88 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -122,16 +122,6 @@ static int statspace; DVector2 AM_GetPosition(); int active_con_scaletext(); -FTextureID GetHUDIcon(PClassInventory *cls) -{ - return cls->AltHUDIcon; -} - -void SetHUDIcon(PClassInventory *cls, FTextureID tex) -{ - cls->AltHUDIcon = tex; -} - //--------------------------------------------------------------------------- // // Draws an image into a box with its bottom center at the bottom @@ -437,7 +427,7 @@ static void SetKeyTypes() static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv) { FTextureID icon = FNullTextureID(); - FTextureID AltIcon = GetHUDIcon(inv->GetClass()); + FTextureID AltIcon = inv->AltHUDIcon; if (!AltIcon.Exists()) return; @@ -516,27 +506,27 @@ static int DrawKeys(player_t * CPlayer, int x, int y) // Drawing Ammo // //--------------------------------------------------------------------------- -static TArray orderedammos; +static TArray orderedammos; static void AddAmmoToList(AWeapon * weapdef) { - for(int i=0; i<2;i++) + for (int i = 0; i < 2; i++) { - PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; + auto ti = i == 0 ? weapdef->AmmoType1 : weapdef->AmmoType2; if (ti) { - auto ammodef=(AInventory*)GetDefaultByType(ti); + auto ammodef = (AInventory*)GetDefaultByType(ti); if (ammodef && !(ammodef->ItemFlags&IF_INVBAR)) { unsigned int j; - for(j=0;jmo->Inventory;inv;inv=inv->Inventory) { - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (inv->IsKindOf(NAME_Weapon)) { AddAmmoToList((AWeapon*)inv); } @@ -646,11 +636,11 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) for(i=orderedammos.Size()-1;i>=0;i--) { - PClassInventory * type = orderedammos[i]; + auto type = orderedammos[i]; auto ammoitem = CPlayer->mo->FindInventory(type); auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]); - FTextureID AltIcon = GetHUDIcon(type); + FTextureID AltIcon = inv->AltHUDIcon; FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon; if (!icon.isValid()) continue; @@ -682,7 +672,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) //--------------------------------------------------------------------------- FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL) // This function is also used by SBARINFO { - FTextureID picnum, AltIcon = GetHUDIcon(item->GetClass()); + FTextureID picnum, AltIcon = item->AltHUDIcon; FState * state=NULL, *ReadyState; picnum.SetNull(); @@ -713,7 +703,7 @@ FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL } } // no spawn state - now try the ready state if it's weapon - else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) + else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(NAME_Weapon) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) { state = ReadyState; } @@ -767,7 +757,7 @@ static void DrawWeapons(player_t *CPlayer, int x, int y) // First draw all weapons in the inventory that are not assigned to a weapon slot for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory) { - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) && + if (inv->IsKindOf(NAME_Weapon) && !CPlayer->weapons.LocateWeapon(static_cast(inv)->GetClass(), NULL, NULL)) { DrawOneWeapon(CPlayer, x, y, static_cast(inv)); @@ -816,7 +806,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y) { if (rover->Amount>0) { - FTextureID AltIcon = GetHUDIcon(rover->GetClass()); + FTextureID AltIcon = rover->AltHUDIcon; if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) ) { @@ -1285,7 +1275,7 @@ void HUD_InitHud() } else tex.SetInvalid(); - if (ti) SetHUDIcon(static_cast(ti), tex); + if (ti) ((AInventory*)GetDefaultByType(ti))->AltHUDIcon = tex; } } } diff --git a/src/g_statusbar/sbar_mugshot.cpp b/src/g_statusbar/sbar_mugshot.cpp index d88ad40f2..d24298b94 100644 --- a/src/g_statusbar/sbar_mugshot.cpp +++ b/src/g_statusbar/sbar_mugshot.cpp @@ -489,7 +489,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu if (CurrentState != NULL) { int skin = player->userinfo.GetSkin(); - const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? player->MorphedPlayerClass->Face.GetChars() : skins[skin].face); + const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? ((APlayerPawn*)GetDefaultByType(player->MorphedPlayerClass))->Face.GetChars() : skins[skin].face); return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index c3950571f..6e6b55bec 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -148,7 +148,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { type = INVENTORYICON; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -418,7 +418,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->IsDescendantOf(PClass::FindActor(NAME_Key))) + if (cls->IsDescendantOf(NAME_Key)) { auto key = GetDefaultByType(cls); if (key->special1 == keynum) @@ -471,7 +471,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage { inventoryItem[0] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -498,7 +498,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage sc.MustGetToken(TK_Identifier); inventoryItem[1] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -556,7 +556,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) { - if(item->IsKindOf(PClass::FindActor(NAME_Key))) + if(item->IsKindOf(NAME_Key)) { int keynum = item->special1; if(keynum) @@ -1078,7 +1078,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if(inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); inventoryItem = PClass::FindActor(NAME_Ammo); @@ -1094,7 +1094,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); inventoryItem = PClass::FindActor(NAME_Ammo); @@ -1160,7 +1160,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(inventoryItem)) + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_PowerupGiver)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); inventoryItem = PClass::FindActor(NAME_PowerupGiver); @@ -1203,7 +1203,7 @@ class CommandDrawNumber : public CommandDrawString if(value == INVENTORY) { inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Inventory)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); inventoryItem = RUNTIME_CLASS(AInventory); @@ -1476,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString num = 0; for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) { - if(item->IsKindOf(PClass::FindActor(NAME_Key))) + if(item->IsKindOf(NAME_Key)) num++; } break; @@ -2431,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand int rowWidth = 0; for(unsigned int i = 0;i < number+keyOffset;i++) { - while(!item->Icon.isValid() || !item->IsKindOf(PClass::FindActor(NAME_Key))) + while(!item->Icon.isValid() || !item->IsKindOf(NAME_Key)) { item = item->Inventory; if(item == NULL) @@ -2632,7 +2632,7 @@ class CommandDrawBar : public SBarInfoCommand sc.MustGetToken(TK_Identifier); type = AMMO; data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo + if (data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); data.inventoryItem = PClass::FindActor(NAME_Ammo); @@ -2660,7 +2660,7 @@ class CommandDrawBar : public SBarInfoCommand if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(data.inventoryItem)) + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_PowerupGiver)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); data.inventoryItem = PClass::FindActor(NAME_PowerupGiver); @@ -2672,7 +2672,7 @@ class CommandDrawBar : public SBarInfoCommand { type = INVENTORY; data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); data.inventoryItem = RUNTIME_CLASS(AInventory); @@ -2894,7 +2894,7 @@ class CommandDrawBar : public SBarInfoCommand if(sc.CheckToken(TK_Identifier) || (extendedSyntax && sc.CheckToken(TK_StringConst))) //comparing reference { data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) //must be a kind of inventory + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory)) //must be a kind of inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); data.inventoryItem = RUNTIME_CLASS(AInventory); @@ -2977,7 +2977,7 @@ class CommandIsSelected : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { weapon[i] = PClass::FindClass(sc.String); - if(weapon[i] == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon[i])) + if(weapon[i] == NULL || !weapon[i]->IsDescendantOf(NAME_Weapon)) { sc.ScriptMessage("'%s' is not a type of weapon.", sc.String); weapon[i] = RUNTIME_CLASS(AWeapon); @@ -3130,7 +3130,7 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl if(!sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); weapon = PClass::FindClass(sc.String); - if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon + if (weapon == NULL || !weapon->IsDescendantOf(NAME_Weapon)) //must be a weapon { sc.ScriptMessage("%s is not a kind of weapon.", sc.String); weapon = RUNTIME_CLASS(AWeapon); @@ -3317,7 +3317,7 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { ammo[i] = PClass::FindClass(sc.String); - if(ammo[i] == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(ammo[i])) //must be a kind of ammo + if(ammo[i] == NULL || !ammo[i]->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); ammo[i] = PClass::FindActor(NAME_Ammo); @@ -3400,7 +3400,7 @@ class CommandInInventory : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { item[i] = PClass::FindActor(sc.String); - if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i])) + if (item[i] == NULL || !item[i]->IsDescendantOf(NAME_Inventory)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); item[i] = RUNTIME_CLASS(AInventory); diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index 7a548eaa2..5ce79fd09 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -77,7 +77,7 @@ void gl_ParseVavoomSkybox(); inline PClassActor * GetRealType(PClassActor * ti) { PClassActor *rep = ti->GetReplacement(false); - if (rep != ti && rep != NULL && rep->IsDescendantOf(PClass::FindActor(NAME_DehackedPickup))) + if (rep != ti && rep != NULL && rep->IsDescendantOf(NAME_DehackedPickup)) { return rep; } diff --git a/src/info.cpp b/src/info.cpp index c86486b5e..58c7241ad 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -110,7 +110,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, const char *callinfo = ""; if (info != nullptr && info->mStateType == STATE_Psprite) { - if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon "; + if (stateowner->IsKindOf(NAME_Weapon) && stateowner != self) callinfo = "weapon "; else callinfo = "overlay "; } err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars()); @@ -176,11 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex) ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); } -IMPLEMENT_CLASS(PClassActor, false, true) - -IMPLEMENT_POINTERS_START(PClassActor) - IMPLEMENT_POINTER(DropItems) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClassActor, false, false) //========================================================================== // @@ -349,32 +345,12 @@ void PClassActor::DeriveData(PClass *newclass) *newa->PainChances = *PainChances; } -} + // Inventory stuff + newa->PickupMsg = PickupMsg; + newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; + newa->RestrictedToPlayerClass = RestrictedToPlayerClass; -//========================================================================== -// -// PClassActor :: PropagateMark -// -//========================================================================== - -size_t PClassActor::PropagateMark() -{ - // Mark state functions - for (int i = 0; i < NumOwnedStates; ++i) - { - if (OwnedStates[i].ActionFunc != NULL) - { - GC::Mark(OwnedStates[i].ActionFunc); - } - } - // Mark damage function - if (Defaults != NULL) - { - GC::Mark(((AActor *)Defaults)->DamageFunc); - } - -// marked += ActorInfo->NumOwnedStates * sizeof(FState); - return Super::PropagateMark(); + newa->DisplayName = DisplayName; } //========================================================================== @@ -414,10 +390,9 @@ bool PClassActor::SetReplacement(FName replaceName) // //========================================================================== -void PClassActor::SetDropItems(DDropItem *drops) +void PClassActor::SetDropItems(FDropItem *drops) { DropItems = drops; - GC::WriteBarrier(this, DropItems); } @@ -659,10 +634,33 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (VisibleToPlayerClass[i] == oldclass) { - VisibleToPlayerClass[i] = static_cast(newclass); + VisibleToPlayerClass[i] = static_cast(newclass); changed++; } } + + for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) + { + if (ForbiddenToPlayerClass[i] == oldclass) + { + ForbiddenToPlayerClass[i] = static_cast(newclass); + changed++; + } + } + for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) + { + if (RestrictedToPlayerClass[i] == oldclass) + { + RestrictedToPlayerClass[i] = static_cast(newclass); + changed++; + } + } + AInventory *def = dyn_cast((AActor*)Defaults); + if (def != NULL) + { + if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); + } + return changed; } diff --git a/src/info.h b/src/info.h index 3a20994f5..05785f90b 100644 --- a/src/info.h +++ b/src/info.h @@ -234,13 +234,11 @@ private: static DamageTypeDefinition *Get(FName type); }; -class DDropItem; -class PClassPlayerPawn; +struct FDropItem; class PClassActor : public PClass { DECLARE_CLASS(PClassActor, PClass); - HAS_OBJECT_POINTERS; protected: public: static void StaticInit (); @@ -256,9 +254,8 @@ public: void RegisterIDs(); void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); - size_t PropagateMark(); bool SetReplacement(FName replaceName); - void SetDropItems(DDropItem *drops); + void SetDropItems(FDropItem *drops); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); @@ -288,7 +285,7 @@ public: DmgFactors *DamageFactors; PainChanceList *PainChances; - TArray VisibleToPlayerClass; + TArray VisibleToPlayerClass; FString Obituary; // Player was killed by this actor FString HitObituary; // Player was killed by this actor in melee @@ -305,7 +302,7 @@ public: FName BloodType2; // Bloopsplatter replacement type FName BloodType3; // AxeBlood replacement type - DDropItem *DropItems; + FDropItem *DropItems; FString SourceLumpName; FIntCVar *distancecheck; @@ -318,6 +315,14 @@ public: FName MissileName; double MissileHeight; + // These are only valid for inventory items. + FString PickupMsg; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; + + // This is from PClassPlayerPawn + FString DisplayName; + // For those times when being able to scan every kind of actor is convenient static TArray AllActorClasses; }; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 23c2f1ded..15dd90a07 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -170,7 +170,7 @@ void cht_DoCheat (player_t *player, int cheat) break; case CHT_MORPH: - msg = cht_Morph (player, static_cast(PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer)), true); + msg = cht_Morph (player, PClass::FindActor (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer), true); break; case CHT_NOTARGET: @@ -317,7 +317,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_RESSURECT: if (player->playerstate != PST_LIVE && player->mo != nullptr) { - if (player->mo->IsKindOf(PClass::FindActor("PlayerChunk"))) + if (player->mo->IsKindOf("PlayerChunk")) { Printf("Unable to resurrect. Player is no longer connected to its body.\n"); } @@ -421,7 +421,7 @@ void cht_DoCheat (player_t *player, int cheat) { lastinvp = invp; invp = &(*invp)->Inventory; - if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { AWeapon *weap = static_cast (item); if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) || @@ -548,13 +548,13 @@ void cht_DoCheat (player_t *player, int cheat) Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg); } -const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo) +const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo) { if (player->mo == NULL) { return ""; } - PClassPlayerPawn *oldclass = player->mo->GetClass(); + auto oldclass = player->mo->GetClass(); // Set the standard morph style for the current game int style = MORPH_UNDOBYTOMEOFPOWER; diff --git a/src/m_cheat.h b/src/m_cheat.h index 11f89c4d7..baab5a451 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -29,12 +29,12 @@ // [RH] Functions that actually perform the cheating class player_t; -class PClassPlayerPawn; +class PClassActor; void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); void cht_Suicide (player_t *player); -const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo); +const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo); #endif diff --git a/src/memarena.cpp b/src/memarena.cpp index 8ea8b5806..af9f91547 100644 --- a/src/memarena.cpp +++ b/src/memarena.cpp @@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks() FreeBlockChain(FreeBlocks); } +//========================================================================== +// +// FMemArena :: DumpInfo +// +// Prints some info about this arena +// +//========================================================================== + +void FMemArena::DumpInfo() +{ + size_t allocated = 0; + size_t used = 0; + for (auto block = TopBlock; block != NULL; block = block->NextBlock) + { + allocated += BlockSize; + used += BlockSize - ((char*)block->Limit - (char*)block->Avail); + } + Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used); +} + //========================================================================== // // FMemArena :: FreeBlockChain diff --git a/src/memarena.h b/src/memarena.h index 3601469bf..14b735eda 100644 --- a/src/memarena.h +++ b/src/memarena.h @@ -46,6 +46,7 @@ public: void *Alloc(size_t size); void FreeAll(); void FreeAllBlocks(); + void DumpInfo(); protected: struct Block; diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index dd4d156d6..0e9f0eb6d 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -430,7 +430,7 @@ void DListMenuItemPlayerDisplay::UpdateTranslation() if (mPlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, mPlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(mPlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -552,11 +552,11 @@ void DListMenuItemPlayerDisplay::Drawer(bool selected) return; } - FString portrait = mPlayerClass->Type->Portrait; + FName portrait = ((APlayerPawn*)GetDefaultByType(mPlayerClass->Type))->Portrait; - if (portrait.IsNotEmpty() && !mNoportrait) + if (portrait != NAME_None && !mNoportrait) { - FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch); + FTextureID texid = TexMan.CheckForTexture(portrait.GetChars(), FTexture::TEX_MiscPatch); if (texid.isValid()) { FTexture *tex = TexMan(texid); diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 7116608b3..add8e5680 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -680,7 +680,7 @@ void DPlayerMenu::UpdateTranslation() if (PlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, PlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(PlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -749,11 +749,11 @@ void DPlayerMenu::UpdateColorsets() if (li != NULL) { int sel = 0; - PlayerClass->Type->EnumColorSets(&PlayerColorSets); + EnumColorSets(PlayerClass->Type, &PlayerColorSets); li->SetString(0, "Custom"); for(unsigned i=0;iType->GetColorSet(PlayerColorSets[i]); + FPlayerColorSet *colorset = GetColorSet(PlayerClass->Type, PlayerColorSets[i]); li->SetString(i+1, colorset->Name); } int mycolorset = players[consoleplayer].userinfo.GetColorSet(); @@ -899,7 +899,7 @@ void DPlayerMenu::ClassChanged (DMenuItemBase *li) players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1); PickPlayerClass(); - cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->DisplayName.GetChars()); + cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(PlayerClass->Type).GetChars()); UpdateSkins(); UpdateColorsets(); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bddcd7f95..197a0616d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1193,12 +1193,12 @@ static void GiveInventory (AActor *activator, const char *type, int amount) for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i]) - players[i].mo->GiveInventory(static_cast(info), amount); + players[i].mo->GiveInventory(info, amount); } } else { - activator->GiveInventory(static_cast(info), amount); + activator->GiveInventory(info, amount); } } @@ -5716,7 +5716,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) if (argCount >= 2) { PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1])); - if (powerupclass == NULL || !powerupclass->IsDescendantOf(PClass::FindActor(NAME_Powerup))) + if (powerupclass == NULL || !powerupclass->IsDescendantOf(NAME_Powerup)) { Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1])); return 0; @@ -9042,7 +9042,7 @@ scriptwait: AInventory *item = activator->FindInventory (dyn_cast( PClass::FindClass (FBehavior::StaticLookupString (STACK(1))))); - if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item == NULL || !item->IsKindOf(NAME_Weapon)) { STACK(1) = 0; } @@ -9110,7 +9110,7 @@ scriptwait: } else { - if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine"))) + if (activator != nullptr && activator->IsKindOf("ScriptedMarine")) { SetMarineSprite(activator, type); } @@ -9491,7 +9491,7 @@ scriptwait: { int tag = STACK(7); FName playerclass_name = FBehavior::StaticLookupString(STACK(6)); - PClassPlayerPawn *playerclass = dyn_cast(PClass::FindClass (playerclass_name)); + auto playerclass = PClass::FindActor (playerclass_name); FName monsterclass_name = FBehavior::StaticLookupString(STACK(5)); PClassActor *monsterclass = PClass::FindActor(monsterclass_name); int duration = STACK(4); diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index c732ea18c..518d2fb63 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -2387,7 +2387,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) { return false; } - if (item->IsKindOf(PClass::FindActor(NAME_Health))) + if (item->IsKindOf(NAME_Health)) { item->Amount *= amount; } @@ -3123,7 +3123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon) AWeapon *weaponitem = static_cast(self->FindInventory(cls)); - if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weaponitem != NULL && weaponitem->IsKindOf(NAME_Weapon)) { if (self->player->ReadyWeapon != weaponitem) { @@ -5668,7 +5668,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight. AInventory *gift = static_cast(Spawn(item)); - if (gift->IsKindOf(PClass::FindActor(NAME_Health))) + if (gift->IsKindOf(NAME_Health)) { gift->Amount *= amount; } @@ -6923,18 +6923,18 @@ DEFINE_ACTION_FUNCTION(AActor, SetCamera) if (self->player == nullptr || self->player->mo != self) return 0; - if (camera == nullptr) + if (cam == nullptr) { - camera = self; + cam = self; revert = false; } AActor *oldcamera = self->player->camera; - self->player->camera = camera; + self->player->camera = cam; if (revert) self->player->cheats |= CF_REVERTPLEASE; - if (oldcamera != camera) + if (oldcamera != cam) { - R_ClearPastViewer(camera); + R_ClearPastViewer(cam); } return 0; } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index a77a7358d..54be79e3c 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -369,7 +369,9 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { - node->ItemCheck[j].Item = dyn_cast(GetStrifeType(speech.ItemCheck[j])); + auto inv = GetStrifeType(speech.ItemCheck[j]); + if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr; + node->ItemCheck[j].Item = inv; node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = speech.Link; @@ -513,7 +515,9 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->ItemCheck.Resize(3); for (k = 0; k < 3; ++k) { - reply->ItemCheck[k].Item = dyn_cast(GetStrifeType(rsp->Item[k])); + auto inv = GetStrifeType(rsp->Item[k]); + if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr; + reply->ItemCheck[k].Item = inv; reply->ItemCheck[k].Amount = rsp->Count[k]; } reply->ItemCheckRequire.Clear(); @@ -1331,7 +1335,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply { if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory))) { - if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (reply->GiveType->IsDescendantOf(NAME_Weapon)) { if (player->mo->FindInventory(reply->GiveType) != NULL) { @@ -1357,7 +1361,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } } - if (reply->GiveType->IsDescendantOf(PClass::FindActor("SlideshowStarter"))) + if (reply->GiveType->IsDescendantOf("SlideshowStarter")) gameaction = ga_slideshow; } else diff --git a/src/p_conversation.h b/src/p_conversation.h index bd674aa10..8771d95ae 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -12,7 +12,7 @@ struct FBrokenLines; struct FStrifeDialogueItemCheck { - PClassInventory *Item; + PClassActor *Item; int Amount; }; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index bd5a9cb17..2fb040a93 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3226,7 +3226,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) if (dropamount > 0) { - if (flagmask != 0 && inv->IsKindOf(PClass::FindActor(NAME_Ammo))) + if (flagmask != 0 && inv->IsKindOf(NAME_Ammo)) { inv->Amount = int(dropamount * dropammofactor); inv->ItemFlags |= IF_IGNORESKILL; @@ -3252,7 +3252,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) inv->FloatVar("AmmoFactor") = dropammofactor; inv->ItemFlags |= flagmask; } - else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon))) + else if (inv->IsKindOf(NAME_Weapon)) { // The same goes for ammo from a weapon. static_cast(inv)->AmmoGive1 = int(static_cast(inv)->AmmoGive1 * dropammofactor); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 758b4ac18..2650224be 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -767,10 +767,12 @@ DEFINE_ACTION_FUNCTION(AActor, AddInventory) // //============================================================================ -bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) +bool AActor::GiveInventory(PClassActor *type, int amount, bool givecheat) { bool result = true; + if (type != nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false; + AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL; bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true; @@ -903,7 +905,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate // and infinite ammo is on if (notakeinfinite && ((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && - item->IsKindOf(PClass::FindActor(NAME_Ammo))) + item->IsKindOf(NAME_Ammo)) { // Nothing to do here, except maybe res = false;? Would it make sense? result = false; @@ -1146,10 +1148,12 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) // //============================================================================ -bool AActor::GiveAmmo (PClassInventory *type, int amount) +bool AActor::GiveAmmo (PClassActor *type, int amount) { if (type != NULL) { + if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false; + AInventory *item = static_cast(Spawn (type)); if (item) { @@ -1542,7 +1546,7 @@ bool AActor::IsVisibleToPlayer() const bool visible = false; for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i) { - PClassPlayerPawn *cls = GetClass()->VisibleToPlayerClass[i]; + auto cls = GetClass()->VisibleToPlayerClass[i]; if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls)) { visible = true; @@ -7488,7 +7492,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) } -DDropItem *AActor::GetDropItems() const +FDropItem *AActor::GetDropItems() const { return GetClass()->DropItems; } @@ -8096,16 +8100,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors) // //---------------------------------------------------------------------------- -IMPLEMENT_CLASS(DDropItem, false, true) - -IMPLEMENT_POINTERS_START(DDropItem) -IMPLEMENT_POINTER(Next) -IMPLEMENT_POINTERS_END - -DEFINE_FIELD(DDropItem, Next) -DEFINE_FIELD(DDropItem, Name) -DEFINE_FIELD(DDropItem, Probability) -DEFINE_FIELD(DDropItem, Amount) +DEFINE_FIELD(FDropItem, Next) +DEFINE_FIELD(FDropItem, Name) +DEFINE_FIELD(FDropItem, Probability) +DEFINE_FIELD(FDropItem, Amount) void PrintMiscActorInfo(AActor *query) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 7a8c85ed1..bdf074fa5 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -170,7 +170,7 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id) if (Next && Next->ID == ID && ID != 0) Next->Destroy(); // Replace it. - if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + if (Caller->IsKindOf(NAME_Weapon) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn))) Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST); } @@ -357,7 +357,7 @@ void DPSprite::SetState(FState *newstate, bool pending) } else if (!(newstate->UseFlags & SUF_WEAPON)) { - if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (Caller->IsKindOf(NAME_Weapon)) { auto so = FState::StaticFindStateOwner(newstate); Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates)); @@ -1399,7 +1399,7 @@ void player_t::TickPSprites() // or if it's from an inventory item that the player no longer owns. if ((pspr->Caller == nullptr || (pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast(pspr->Caller)->Owner != pspr->Owner->mo) || - (pspr->Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) && pspr->Caller != pspr->Owner->ReadyWeapon))) + (pspr->Caller->IsKindOf(NAME_Weapon) && pspr->Caller != pspr->Owner->ReadyWeapon))) { pspr->Destroy(); } diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index d40c542a1..f4ebe5ebd 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -57,21 +57,23 @@ class USDFParser : public UDMFParserBase PClassActor *CheckActorType(const char *key) { + PClassActor *type = nullptr; if (namespace_bits == St) { - return GetStrifeType(CheckInt(key)); + type = GetStrifeType(CheckInt(key)); } else if (namespace_bits == Zd) { PClassActor *cls = PClass::FindActor(CheckString(key)); - if (cls == NULL) + if (cls == nullptr) { sc.ScriptMessage("Unknown actor class '%s'", key); - return NULL; + return nullptr; } - return cls; + type = cls; } - return NULL; + if (type && type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return type; + return nullptr; } //=========================================================================== @@ -92,7 +94,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = dyn_cast(CheckActorType(key)); + check.Item = CheckActorType(key); break; case NAME_Amount: @@ -266,7 +268,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = dyn_cast(CheckActorType(key)); + check.Item = CheckActorType(key); break; case NAME_Count: diff --git a/src/p_user.cpp b/src/p_user.cpp index 6fd790731..7c9cf07c4 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -84,6 +84,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO P_PredictionLerpReset(); } +ColorSetList ColorSets; +PainFlashList PainFlashes; + struct PredictPos { int gametic; @@ -145,7 +148,7 @@ bool FPlayerClass::CheckSkin (int skin) // //=========================================================================== -FString GetPrintableDisplayName(PClassPlayerPawn *cls) +FString GetPrintableDisplayName(PClassActor *cls) { // Fixme; This needs a decent way to access the string table without creating a mess. // [RH] ???? @@ -164,7 +167,7 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name) Printf("Invalid player class '%s'\n", name); return false; } - else if (static_cast(ti)->DisplayName.IsEmpty()) + else if (ti->DisplayName.IsEmpty()) { Printf ("Missing displayname for player class '%s'\n", name); return false; @@ -183,7 +186,7 @@ void SetupPlayerClasses () if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i])) { newclass.Flags = 0; - newclass.Type = static_cast(cls); + newclass.Type = cls; if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU)) { newclass.Flags |= PCF_NOMENU; @@ -211,7 +214,7 @@ CCMD (addplayerclass) { FPlayerClass newclass; - newclass.Type = static_cast(ti); + newclass.Type = ti; newclass.Flags = 0; int arg = 2; @@ -534,61 +537,34 @@ int player_t::GetSpawnClass() //=========================================================================== // -// PClassPlayerPawn +// EnumColorsets +// +// Only used by the menu so it doesn't really matter that it's a bit +// inefficient. // //=========================================================================== -IMPLEMENT_CLASS(PClassPlayerPawn, false, false) - -PClassPlayerPawn::PClassPlayerPawn() -{ - for (size_t i = 0; i < countof(HexenArmor); ++i) - { - HexenArmor[i] = 0; - } - ColorRangeStart = 0; - ColorRangeEnd = 0; -} - -void PClassPlayerPawn::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - Super::DeriveData(newclass); - PClassPlayerPawn *newp = static_cast(newclass); - size_t i; - - newp->DisplayName = DisplayName; - newp->SoundClass = SoundClass; - newp->Face = Face; - newp->InvulMode = InvulMode; - newp->HealingRadiusType = HealingRadiusType; - newp->ColorRangeStart = ColorRangeStart; - newp->ColorRangeEnd = ColorRangeEnd; - newp->ColorSets = ColorSets; - for (i = 0; i < countof(HexenArmor); ++i) - { - newp->HexenArmor[i] = HexenArmor[i]; - } - for (i = 0; i < countof(Slot); ++i) - { - newp->Slot[i] = Slot[i]; - } -} - static int intcmp(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } -void PClassPlayerPawn::EnumColorSets(TArray *out) +void EnumColorSets(PClassActor *cls, TArray *out) { - out->Clear(); - FPlayerColorSetMap::Iterator it(ColorSets); - FPlayerColorSetMap::Pair *pair; + TArray deleteds; - while (it.NextPair(pair)) + out->Clear(); + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - out->Push(pair->Key); + if (std::get<0>(ColorSets[i])->IsAncestorOf(cls)) + { + int v = std::get<1>(ColorSets[i]); + if (out->Find(v) == out->Size() && deleteds.Find(v) == deleteds.Size()) + { + if (std::get<2>(ColorSets[i]).Name == NAME_None) deleteds.Push(v); + else out->Push(v); + } + } } qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); } @@ -598,20 +574,41 @@ void PClassPlayerPawn::EnumColorSets(TArray *out) // //========================================================================== -bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const +FPlayerColorSet *GetColorSet(PClassActor *cls, int setnum) { - const PClassPlayerPawn *info = this; - - while (info != NULL) + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - const PalEntry *flash = info->PainFlashes.CheckKey(type); - if (flash != NULL) + if (std::get<1>(ColorSets[i]) == setnum && + std::get<0>(ColorSets[i])->IsAncestorOf(cls)) { - *color = *flash; + auto c = &std::get<2>(ColorSets[i]); + return c->Name != NAME_None ? c : nullptr; + } + } + return nullptr; +} + +//========================================================================== +// +// +//========================================================================== + +bool player_t::GetPainFlash(FName type, PalEntry *color) const +{ + PClass *info = mo->GetClass(); + + // go backwards through the list and return the first item with a + // matching damage type for an ancestor of our class. + // This will always return the best fit because any parent class + // must be processed before its children. + for (int i = PainFlashes.Size() - 1; i >= 0; i--) + { + if (std::get<1>(PainFlashes[i]) == type && + std::get<0>(PainFlashes[i])->IsAncestorOf(info)) + { + *color = std::get<2>(PainFlashes[i]); return true; } - // Try parent class - info = dyn_cast(info->ParentClass); } return false; } @@ -660,7 +657,6 @@ IMPLEMENT_CLASS(APlayerPawn, false, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) IMPLEMENT_POINTER(InvSel) - IMPLEMENT_POINTER(FlechetteType) IMPLEMENT_POINTERS_END void APlayerPawn::Serialize(FSerializer &arc) @@ -952,7 +948,7 @@ bool APlayerPawn::UseInventory (AInventory *item) // //=========================================================================== -AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype) { AWeapon *bestMatch = NULL; int bestOrder = INT_MAX; @@ -963,7 +959,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) // Find the best weapon the player has. for (item = Inventory; item != NULL; item = item->Inventory) { - if (!item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (!item->IsKindOf(NAME_Weapon)) continue; weap = static_cast (item); @@ -1014,7 +1010,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) // //=========================================================================== -AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype) { AWeapon *best = BestWeapon (ammotype); @@ -1042,7 +1038,7 @@ AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) // //=========================================================================== -void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) +void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype) { if (!player->userinfo.GetNeverSwitch() && player->PendingWeapon == WP_NOCHANGE && @@ -1061,7 +1057,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) { PARAM_SELF_PROLOGUE(APlayerPawn); - PARAM_OBJECT(ammotype, PClassInventory); + PARAM_OBJECT(ammotype, PClassActor); self->CheckWeaponSwitch(ammotype); return 0; } @@ -1136,29 +1132,29 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) if ((dmflags & DF_COOP_LOSE_KEYS) && defitem == NULL && - item->IsKindOf(PClass::FindActor(NAME_Key))) + item->IsKindOf(NAME_Key)) { item->Destroy(); } else if ((dmflags & DF_COOP_LOSE_WEAPONS) && defitem == NULL && - item->IsKindOf(RUNTIME_CLASS(AWeapon))) + item->IsKindOf(NAME_Weapon)) { item->Destroy(); } else if ((dmflags & DF_COOP_LOSE_ARMOR) && - item->IsKindOf(PClass::FindActor(NAME_Armor))) + item->IsKindOf(NAME_Armor)) { if (defitem == NULL) { item->Destroy(); } - else if (item->IsKindOf(PClass::FindActor(NAME_BasicArmor))) + else if (item->IsKindOf(NAME_BasicArmor)) { item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent); item->Amount = defitem->Amount; } - else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor))) + else if (item->IsKindOf(NAME_HexenArmor)) { double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr); double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr); @@ -1167,12 +1163,12 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) } else if ((dmflags & DF_COOP_LOSE_POWERUPS) && defitem == NULL && - item->IsKindOf(PClass::FindActor(NAME_PowerupGiver))) + item->IsKindOf(NAME_PowerupGiver)) { item->Destroy(); } else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) && - item->IsKindOf(PClass::FindActor(NAME_Ammo))) + item->IsKindOf(NAME_Ammo)) { if (defitem == NULL) { @@ -1229,8 +1225,8 @@ const char *APlayerPawn::GetSoundClass() const } // [GRB] - PClassPlayerPawn *pclass = GetClass(); - return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass.GetChars() : "player"; + auto pclass = GetClass(); + return SoundClass != NAME_None? SoundClass.GetChars() : "player"; } //=========================================================================== @@ -1367,16 +1363,16 @@ void APlayerPawn::GiveDefaultInventory () // HexenArmor must always be the first item in the inventory because // it provides player class based protection that should not affect // any other protection item. - PClassPlayerPawn *myclass = GetClass(); + auto myclass = GetClass(); GiveInventoryType(PClass::FindActor(NAME_HexenArmor)); auto harmor = FindInventory(NAME_HexenArmor); double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr); - Slots[4] = myclass->HexenArmor[0]; + Slots[4] = HexenArmor[0]; for (int i = 0; i < 4; ++i) { - SlotsIncrement[i] = myclass->HexenArmor[i + 1]; + SlotsIncrement[i] = HexenArmor[i + 1]; } // BasicArmor must come right after that. It should not affect any @@ -1387,7 +1383,7 @@ void APlayerPawn::GiveDefaultInventory () AddInventory (barmor); // Now add the items from the DECORATE definition - DDropItem *di = GetDropItems(); + auto di = GetDropItems(); while (di) { @@ -1412,7 +1408,7 @@ void APlayerPawn::GiveDefaultInventory () item = static_cast(Spawn(ti)); item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here item->Amount = di->Amount; - if (item->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { // To allow better control any weapon is emptied of // ammo before being given to the player. @@ -1432,7 +1428,7 @@ void APlayerPawn::GiveDefaultInventory () item = NULL; } } - if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)) && + if (item != NULL && item->IsKindOf(NAME_Weapon) && static_cast(item)->CheckAmmo(AWeapon::EitherFire, false)) { player->ReadyWeapon = player->PendingWeapon = static_cast (item); @@ -1517,7 +1513,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) AInventory *item; // kgDROP - start - modified copy from a_action.cpp - DDropItem *di = weap->GetDropItems(); + auto di = weap->GetDropItems(); if (di != NULL) { @@ -1536,7 +1532,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) weap->SpawnState != ::GetDefault()->SpawnState) { item = P_DropItem (this, weap->GetClass(), -1, 256); - if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (item != NULL && item->IsKindOf(NAME_Weapon)) { if (weap->AmmoGive1 && weap->Ammo1) { @@ -1709,9 +1705,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) player_t *player; // [GRB] Parameterized version - if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk"))) + if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk")) { - spawntype = dyn_cast(PClass::FindClass("BloodySkull")); + spawntype = PClass::FindActor("BloodySkull"); if (spawntype == NULL) return 0; } @@ -3249,18 +3245,17 @@ DEFINE_FIELD(APlayerPawn, DamageFade) DEFINE_FIELD(APlayerPawn, ViewBob) DEFINE_FIELD(APlayerPawn, FullHeight) -DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType) -DEFINE_FIELD(PClassPlayerPawn, DisplayName) -DEFINE_FIELD(PClassPlayerPawn, SoundClass) -DEFINE_FIELD(PClassPlayerPawn, Face) -DEFINE_FIELD(PClassPlayerPawn, Portrait) -DEFINE_FIELD(PClassPlayerPawn, Slot) -DEFINE_FIELD(PClassPlayerPawn, InvulMode) -DEFINE_FIELD(PClassPlayerPawn, HexenArmor) -DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart) -DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd) -DEFINE_FIELD(PClassPlayerPawn, ColorSets) -DEFINE_FIELD(PClassPlayerPawn, PainFlashes) +DEFINE_FIELD(APlayerPawn, HealingRadiusType) +DEFINE_FIELD(APlayerPawn, SoundClass) +DEFINE_FIELD(APlayerPawn, Face) +DEFINE_FIELD(APlayerPawn, Portrait) +DEFINE_FIELD(APlayerPawn, Slot) +DEFINE_FIELD(APlayerPawn, InvulMode) +DEFINE_FIELD(APlayerPawn, HexenArmor) +DEFINE_FIELD(APlayerPawn, ColorRangeStart) +DEFINE_FIELD(APlayerPawn, ColorRangeEnd) + +DEFINE_FIELD(PClassActor, DisplayName) DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) diff --git a/src/portal.cpp b/src/portal.cpp index 43b7ef7b6..f354faa65 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -670,7 +670,7 @@ unsigned P_GetSkyboxPortal(AActor *actor) unsigned i = level.sectorPortals.Reserve(1); memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT; - level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf(PClass::FindActor("SkyCamCompat")) ? 0 : PORTSF_SKYFLATONLY; + level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY; level.sectorPortals[i].mSkybox = actor; level.sectorPortals[i].mDestination = actor->Sector; return i; diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 7fb59ef94..c3f73760d 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -517,7 +517,7 @@ void R_InitSkins (void) int lastlump; int aliasid; bool remove; - PClassPlayerPawn *basetype, *transtype; + PClassActor *basetype, *transtype; key[sizeof(key)-1] = 0; i = PlayerClasses.Size () - 1; @@ -602,11 +602,11 @@ void R_InitSkins (void) else if (0 == stricmp (key, "game")) { if (gameinfo.gametype == GAME_Heretic) - basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); + basetype = PClass::FindActor(NAME_HereticPlayer); else if (gameinfo.gametype == GAME_Strife) - basetype = dyn_cast(PClass::FindActor(NAME_StrifePlayer)); + basetype = PClass::FindActor(NAME_StrifePlayer); else - basetype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = PClass::FindActor(NAME_DoomPlayer); transtype = basetype; @@ -614,7 +614,7 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - transtype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); + transtype = PClass::FindActor(NAME_HereticPlayer); skins[i].othergame = true; } else if (gameinfo.gametype != GAME_Heretic) @@ -633,7 +633,7 @@ void R_InitSkins (void) { if (gameinfo.gametype == GAME_Heretic) { - transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + transtype = PClass::FindActor(NAME_DoomPlayer); skins[i].othergame = true; } else if (!(gameinfo.gametype & GAME_DoomChex)) @@ -709,12 +709,12 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - basetype = transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = transtype = PClass::FindActor(NAME_DoomPlayer); } else if (gameinfo.gametype == GAME_Heretic) { - basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); - transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = PClass::FindActor(NAME_HereticPlayer); + transtype = PClass::FindActor(NAME_DoomPlayer); skins[i].othergame = true; } else @@ -725,18 +725,22 @@ void R_InitSkins (void) if (!remove) { - skins[i].range0start = transtype->ColorRangeStart; - skins[i].range0end = transtype->ColorRangeEnd; + auto transdef = ((APlayerPawn*)GetDefaultByType(transtype)); + auto basedef = ((APlayerPawn*)GetDefaultByType(basetype)); + + skins[i].range0start = transdef->ColorRangeStart; + skins[i].range0end = transdef->ColorRangeEnd; remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) { - PClassPlayerPawn *type = PlayerClasses[j].Type; + auto type = PlayerClasses[j].Type; + auto type_def = ((APlayerPawn*)GetDefaultByType(type)); if (type->IsDescendantOf (basetype) && GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite && - type->ColorRangeStart == basetype->ColorRangeStart && - type->ColorRangeEnd == basetype->ColorRangeEnd) + type_def->ColorRangeStart == basedef->ColorRangeStart && + type_def->ColorRangeEnd == basedef->ColorRangeEnd) { PlayerClasses[j].Skins.Push ((int)i); remove = false; @@ -935,10 +939,10 @@ void R_InitSprites () memset (skins, 0, sizeof(*skins) * numskins); for (i = 0; i < numskins; i++) { // Assume Doom skin by default - PClassPlayerPawn *type = PlayerClasses[0].Type; + auto type = ((APlayerPawn*)GetDefaultByType(PlayerClasses[0].Type)); skins[i].range0start = type->ColorRangeStart; skins[i].range0end = type->ColorRangeEnd; - skins[i].Scale = GetDefaultByType (type)->Scale; + skins[i].Scale = type->Scale; } R_InitSpriteDefs (); @@ -950,11 +954,10 @@ void R_InitSprites () // [GRB] Each player class has its own base skin for (i = 0; i < PlayerClasses.Size (); i++) { - PClassPlayerPawn *basetype = PlayerClasses[i].Type; - FString classface = basetype->Face; + auto basetype = ((APlayerPawn*)GetDefaultByType(PlayerClasses[i].Type)); strcpy (skins[i].name, "Base"); - if (classface.IsEmpty() || strcmp(classface, "None") == 0) + if (basetype->Face == NAME_None) { skins[i].face[0] = 'S'; skins[i].face[1] = 'T'; @@ -963,12 +966,12 @@ void R_InitSprites () } else { - strcpy(skins[i].face, classface); + strcpy(skins[i].face, basetype->Face); } skins[i].range0start = basetype->ColorRangeStart; skins[i].range0end = basetype->ColorRangeEnd; - skins[i].Scale = GetDefaultByType (basetype)->Scale; - skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite; + skins[i].Scale = basetype->Scale; + skins[i].sprite = basetype->SpawnState->sprite; skins[i].namespc = ns_global; PlayerClasses[i].Skins.Push (i); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 856156322..bae1fbaf6 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -711,6 +711,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, { case SOURCE_None: default: + pos->Zero(); break; case SOURCE_Actor: diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/backend/codegen.cpp similarity index 99% rename from src/scripting/codegeneration/codegen.cpp rename to src/scripting/backend/codegen.cpp index a3dc066e9..c05ab6d64 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6558,23 +6558,10 @@ FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition FxStackVariable::~FxStackVariable() { - // Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap. membervar->ObjectFlags |= OF_YesReallyDelete; delete membervar; } -//========================================================================== -// -// -//========================================================================== - -void FxStackVariable::ReplaceField(PField *newfield) -{ - membervar->ObjectFlags |= OF_YesReallyDelete; - delete membervar; - membervar = newfield; -} - //========================================================================== // // @@ -6730,7 +6717,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) { auto parentfield = static_cast(classx)->membervar; // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + auto newfield = new PField(NAME_None, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); newfield->BitValue = membervar->BitValue; static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/backend/codegen.h similarity index 99% rename from src/scripting/codegeneration/codegen.h rename to src/scripting/backend/codegen.h index c64ec2094..abbcbd54e 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/backend/codegen.h @@ -1417,7 +1417,6 @@ class FxStackVariable : public FxMemberBase public: FxStackVariable(PType *type, int offset, const FScriptPosition&); ~FxStackVariable(); - void ReplaceField(PField *newfield); FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/backend/dynarrays.cpp similarity index 99% rename from src/scripting/codegeneration/dynarrays.cpp rename to src/scripting/backend/dynarrays.cpp index 05e18a3ca..0152c6520 100644 --- a/src/scripting/codegeneration/dynarrays.cpp +++ b/src/scripting/backend/dynarrays.cpp @@ -1,10 +1,10 @@ /* ** dynarray.cpp ** -** Compiler backend / code generation for dynamic arrays +** internal data types for dynamic arrays ** **--------------------------------------------------------------------------- -** Copyright 2016 Christoph Oelckers +** Copyright 2016-2017 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp similarity index 99% rename from src/scripting/vm/vmbuilder.cpp rename to src/scripting/backend/vmbuilder.cpp index 19fe81c32..74f845248 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -32,7 +32,7 @@ */ #include "vmbuilder.h" -#include "codegeneration/codegen.h" +#include "codegen.h" #include "info.h" #include "m_argv.h" #include "thingdef.h" diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/backend/vmbuilder.h similarity index 100% rename from src/scripting/vm/vmbuilder.h rename to src/scripting/backend/vmbuilder.h diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/backend/vmdisasm.cpp similarity index 100% rename from src/scripting/vm/vmdisasm.cpp rename to src/scripting/backend/vmdisasm.cpp diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 5861138d6..50e8f9c6a 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -47,7 +47,7 @@ #include "decallib.h" #include "i_system.h" #include "thingdef.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "r_data/r_translate.h" // TYPES ------------------------------------------------------------------- @@ -541,7 +541,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - static_cast(bag.Info)->PickupMsg = sc.String; + bag.Info->PickupMsg = sc.String; } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 2b0866dd8..6757a2382 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -49,7 +49,7 @@ #include "thingdef.h" #include "p_lnspec.h" #include "doomstat.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" FRandom pr_exrandom ("EX_Random"); diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index fc411186a..23ffc48e8 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -49,7 +49,7 @@ #include "v_palette.h" #include "doomerrors.h" #include "i_system.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "w_wad.h" #include "v_video.h" #include "version.h" diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 8e08fc038..63269eeeb 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -53,10 +53,10 @@ #include "s_sound.h" #include "i_system.h" #include "colormatcher.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "version.h" #include "templates.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" //========================================================================== //*** diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp new file mode 100644 index 000000000..b6adb33e7 --- /dev/null +++ b/src/scripting/symbols.cpp @@ -0,0 +1,406 @@ +/* +** symbols.cpp +** Implements the symbol types and symbol table +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2006-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "dobject.h" +#include "i_system.h" + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FNamespaceManager Namespaces; + +// Symbol tables ------------------------------------------------------------ + +IMPLEMENT_CLASS(PTypeBase, true, false); +IMPLEMENT_CLASS(PSymbol, true, false); +IMPLEMENT_CLASS(PSymbolConst, false, false); +IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); +IMPLEMENT_CLASS(PSymbolConstString, false, false); +IMPLEMENT_CLASS(PSymbolTreeNode, false, false) +IMPLEMENT_CLASS(PSymbolType, false, false) +IMPLEMENT_CLASS(PSymbolVMFunction, false, false) +IMPLEMENT_CLASS(PFunction, false, false) +IMPLEMENT_CLASS(PNamespace, false, true) + +IMPLEMENT_POINTERS_START(PNamespace) +IMPLEMENT_POINTER(Parent) +IMPLEMENT_POINTERS_END + + +//========================================================================== +// +// +// +//========================================================================== + +PSymbolConstString::PSymbolConstString(FName name, const FString &str) + : PSymbolConst(name, TypeString), Str(str) +{ +} + +//========================================================================== +// +// PFunction :: AddVariant +// +// Adds a new variant for this function. Does not check if a matching +// variant already exists. +// +//========================================================================== + +unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) +{ + Variant variant; + + // I do not think we really want to deal with overloading here... + assert(Variants.Size() == 0); + + variant.Flags = flags; + variant.UseFlags = useflags; + variant.Proto = proto; + variant.ArgFlags = std::move(argflags); + variant.ArgNames = std::move(argnames); + variant.Implementation = impl; + if (impl != nullptr) impl->Proto = proto; + + // SelfClass can differ from OwningClass, but this is variant-dependent. + // Unlike the owner there can be cases where different variants can have different SelfClasses. + // (Of course only if this ever gets enabled...) + if (flags & VARF_Method) + { + assert(proto->ArgumentTypes.Size() > 0); + auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); + assert(selftypeptr != nullptr); + variant.SelfClass = dyn_cast(selftypeptr->PointedType); + assert(variant.SelfClass != nullptr); + } + else + { + variant.SelfClass = nullptr; + } + + return Variants.Push(variant); +} + +//========================================================================== +// +// +// +//========================================================================== + +int PFunction::GetImplicitArgs() +{ + if (Variants[0].Flags & VARF_Action) return 3; + else if (Variants[0].Flags & VARF_Method) return 1; + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbolTable::PSymbolTable() +: ParentSymbolTable(nullptr) +{ +} + +PSymbolTable::PSymbolTable(PSymbolTable *parent) +: ParentSymbolTable(parent) +{ +} + +PSymbolTable::~PSymbolTable () +{ + ReleaseSymbols(); +} + +//========================================================================== +// +// this must explicitly delete all content because the symbols have +// been released from the GC. +// +//========================================================================== + +void PSymbolTable::ReleaseSymbols() +{ + auto it = GetIterator(); + MapType::Pair *pair; + while (it.NextPair(pair)) + { + delete pair->Value; + } + Symbols.Clear(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::SetParentTable (PSymbolTable *parent) +{ + ParentSymbolTable = parent; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == nullptr && searchparents && ParentSymbolTable != nullptr) + { + return ParentSymbolTable->FindSymbol(symname, searchparents); + } + return value != nullptr ? *value : nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == nullptr) + { + if (ParentSymbolTable != nullptr) + { + return ParentSymbolTable->FindSymbolInTable(symname, symtable); + } + symtable = nullptr; + return nullptr; + } + symtable = this; + return *value; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) +{ + // Symbols that already exist are not inserted. + if (Symbols.CheckKey(sym->SymbolName) != nullptr) + { + return nullptr; + } + Symbols.Insert(sym->SymbolName, sym); + sym->Release(); // no more GC, please! + return sym; +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::RemoveSymbol(PSymbol *sym) +{ + auto mysym = Symbols.CheckKey(sym->SymbolName); + if (mysym == nullptr || *mysym != sym) return; + Symbols.Remove(sym->SymbolName); + delete sym; +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::ReplaceSymbol(PSymbol *newsym) +{ + // If a symbol with a matching name exists, take its place and return it. + PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); + if (symslot != nullptr) + { + PSymbol *oldsym = *symslot; + delete oldsym; + *symslot = newsym; + } + // Else, just insert normally and return nullptr since there was no + // symbol to replace. + newsym->Release(); // no more GC, please! + Symbols.Insert(newsym->SymbolName, newsym); +} + +//========================================================================== +// +// +// +//========================================================================== + +//========================================================================== +// +// +// +//========================================================================== + +PNamespace::PNamespace(int filenum, PNamespace *parent) +{ + Parent = parent; + if (parent) Symbols.SetParentTable(&parent->Symbols); + FileNum = filenum; +} + +//========================================================================== +// +// +// +//========================================================================== + +FNamespaceManager::FNamespaceManager() +{ + GlobalNamespace = nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +PNamespace *FNamespaceManager::NewNamespace(int filenum) +{ + PNamespace *parent = nullptr; + // The parent will be the last namespace with this or a lower filenum. + // This ensures that DECORATE won't see the symbols of later files. + for (int i = AllNamespaces.Size() - 1; i >= 0; i--) + { + if (AllNamespaces[i]->FileNum <= filenum) + { + parent = AllNamespaces[i]; + break; + } + } + auto newns = new PNamespace(filenum, parent); + AllNamespaces.Push(newns); + return newns; +} + +//========================================================================== +// +// +// +//========================================================================== + +size_t FNamespaceManager::MarkSymbols() +{ + for (auto ns : AllNamespaces) + { + GC::Mark(ns); + } + return AllNamespaces.Size(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FNamespaceManager::ReleaseSymbols() +{ + RemoveSymbols(); + GlobalNamespace = nullptr; + AllNamespaces.Clear(); +} + +//========================================================================== +// +// removes all symbols from the symbol tables. +// After running the compiler these are not needed anymore. +// Only the namespaces themselves are kept because the type table references them. +// +//========================================================================== + +int FNamespaceManager::RemoveSymbols() +{ + int count = 0; + for (auto ns : AllNamespaces) + { + count += ns->Symbols.Symbols.CountUsed(); + ns->Symbols.ReleaseSymbols(); + } + return count; +} + +//========================================================================== +// +// Clean out all compiler-only data from the symbol tables +// +//========================================================================== + +void RemoveUnusedSymbols() +{ + // Global symbols are not needed anymore after running the compiler. + int count = Namespaces.RemoveSymbols(); + + // We do not need any non-field and non-function symbols in structs and classes anymore. + // struct/class fields and functions are still needed so that the game can access the script data, + // but all the rest serves no purpose anymore and can be entirely removed. + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) + { + if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) + { + auto it = ty->Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction))) + { + ty->Symbols.RemoveSymbol(pair->Value); + count++; + } + } + } + } + } + DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count); +} diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h new file mode 100644 index 000000000..3c9d1f8f3 --- /dev/null +++ b/src/scripting/symbols.h @@ -0,0 +1,272 @@ +// Note: This must not be included by anything but dobject.h! +#pragma once + +#ifndef __DOBJECT_H__ +#error You must #include "dobject.h" to get symbols.h +#endif + + +class VMFunction; +class PType; +class PPrototype; +struct ZCC_TreeNode; +class PStruct; + +// Symbol information ------------------------------------------------------- + +class PTypeBase : public DObject +{ + DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) + +public: +}; + +class PSymbol : public DObject +{ + DECLARE_ABSTRACT_CLASS(PSymbol, DObject); +public: + FName SymbolName; + +protected: + PSymbol(FName name) { SymbolName = name; } +}; + +// A VM function ------------------------------------------------------------ + +class PSymbolVMFunction : public PSymbol +{ + DECLARE_CLASS(PSymbolVMFunction, PSymbol); +public: + VMFunction *Function; + + PSymbolVMFunction(FName name) : PSymbol(name) {} + PSymbolVMFunction() : PSymbol(NAME_None) {} +}; + +// A symbol for a type ------------------------------------------------------ + +class PSymbolType : public PSymbol +{ + DECLARE_CLASS(PSymbolType, PSymbol); +public: + PType *Type; + + PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} + PSymbolType() : PSymbol(NAME_None) {} +}; + +// A symbol for a compiler tree node ---------------------------------------- + +class PSymbolTreeNode : public PSymbol +{ + DECLARE_CLASS(PSymbolTreeNode, PSymbol); +public: + struct ZCC_TreeNode *Node; + + PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {} + PSymbolTreeNode() : PSymbol(NAME_None) {} +}; + +// Struct/class fields ------------------------------------------------------ + +// A PField describes a symbol that takes up physical space in the struct. +class PField : public PSymbol +{ + DECLARE_CLASS(PField, PSymbol); + HAS_OBJECT_POINTERS +public: + PField(FName name, PType *type, uint32_t flags = 0, size_t offset = 0, int bitvalue = 0); + + size_t Offset; + PType *Type; + uint32_t Flags; + int BitValue; +protected: + PField(); +}; + +// Properties ------------------------------------------------------ + +// For setting properties in class defaults. +class PProperty : public PSymbol +{ + DECLARE_CLASS(PProperty, PSymbol); +public: + PProperty(FName name, TArray &variables); + + TArray Variables; + +protected: + PProperty(); +}; + +class PPropFlag : public PSymbol +{ + DECLARE_CLASS(PPropFlag, PSymbol); +public: + PPropFlag(FName name, PField *offset, int bitval); + + PField *Offset; + int bitval; + +protected: + PPropFlag(); +}; + +// A constant value --------------------------------------------------------- + +class PSymbolConst : public PSymbol +{ + DECLARE_CLASS(PSymbolConst, PSymbol); +public: + PType *ValueType; + + PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} + PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} +}; + +// A constant numeric value ------------------------------------------------- + +class PSymbolConstNumeric : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); +public: + union + { + int Value; + double Float; + void *Pad; + }; + + PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} + PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} + PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} + PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} + PSymbolConstNumeric() {} +}; + +// A constant string value -------------------------------------------------- + +class PSymbolConstString : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstString, PSymbolConst); +public: + FString Str; + + PSymbolConstString(FName name, const FString &str); + PSymbolConstString() {} +}; + + +// A function for the VM -------------------------------------------------- + +// TBD: Should we really support overloading? +class PFunction : public PSymbol +{ + DECLARE_CLASS(PFunction, PSymbol); +public: + struct Variant + { + PPrototype *Proto; + VMFunction *Implementation; + TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes + TArray ArgNames; // we need the names to access them later when the function gets compiled. + uint32_t Flags; + int UseFlags; + PStruct *SelfClass; + }; + TArray Variants; + PStruct *OwningClass = nullptr; + + unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); + int GetImplicitArgs(); + + PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} +}; + +// A symbol table ----------------------------------------------------------- + +struct PSymbolTable +{ + PSymbolTable(); + PSymbolTable(PSymbolTable *parent); + ~PSymbolTable(); + + // Sets the table to use for searches if this one doesn't contain the + // requested symbol. + void SetParentTable (PSymbolTable *parent); + PSymbolTable *GetParentTable() const + { + return ParentSymbolTable; + } + + // Finds a symbol in the table, optionally searching parent tables + // as well. + PSymbol *FindSymbol (FName symname, bool searchparents) const; + + // Like FindSymbol with searchparents set true, but also returns the + // specific symbol table the symbol was found in. + PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); + + + // Places the symbol in the table and returns a pointer to it or NULL if + // a symbol with the same name is already in the table. This symbol is + // not copied and will be freed when the symbol table is destroyed. + PSymbol *AddSymbol (PSymbol *sym); + + // Similar to AddSymbol but always succeeds. Returns the symbol that used + // to be in the table with this name, if any. + void ReplaceSymbol(PSymbol *sym); + + void RemoveSymbol(PSymbol *sym); + + // Frees all symbols from this table. + void ReleaseSymbols(); + + typedef TMap MapType; + + MapType::Iterator GetIterator() + { + return MapType::Iterator(Symbols); + } + +private: + + PSymbolTable *ParentSymbolTable; + MapType Symbols; + + friend class DObject; + friend struct FNamespaceManager; +}; + +// Namespaces -------------------------------------------------- + +class PNamespace : public PTypeBase +{ + DECLARE_CLASS(PNamespace, PTypeBase) + HAS_OBJECT_POINTERS; + +public: + PSymbolTable Symbols; + PNamespace *Parent; + int FileNum; // This is for blocking DECORATE access to later files. + + PNamespace() {} + PNamespace(int filenum, PNamespace *parent); +}; + +struct FNamespaceManager +{ + PNamespace *GlobalNamespace; + TArray AllNamespaces; + + FNamespaceManager(); + PNamespace *NewNamespace(int filenum); + size_t MarkSymbols(); + void ReleaseSymbols(); + int RemoveSymbols(); +}; + +extern FNamespaceManager Namespaces; + + diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 6776e70e8..a43c741ce 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -60,9 +60,9 @@ #include "p_conversation.h" #include "v_text.h" #include "thingdef.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "a_sharedglobal.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "stats.h" // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -246,7 +246,7 @@ static void CheckForUnsafeStates(PClassActor *obj) TMap checked; ENamedName *test; - if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (obj->IsDescendantOf(NAME_Weapon)) { if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables. test = weaponstates; @@ -336,11 +336,11 @@ static void CheckStates(PClassActor *obj) CheckStateLabels(obj, actorstates, SUF_ACTOR, "actor sprites"); - if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (obj->IsDescendantOf(NAME_Weapon)) { CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites"); } - else if (obj->IsDescendantOf(PClass::FindActor(NAME_CustomInventory))) + else if (obj->IsDescendantOf(NAME_CustomInventory)) { CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain"); } @@ -396,8 +396,9 @@ void LoadActors() { Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::WarnCounter++; - DObject::StaticPointerSubstitution(ti, nullptr); - PClassActor::AllActorClasses.Delete(i); + // the class must be rendered harmless so that it won't cause problems. + ti->ParentClass = RUNTIME_CLASS(AActor); + ti->Size = sizeof(AActor); } else { diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 37c247cbe..5558ffe3f 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -110,7 +110,7 @@ FScriptPosition & GetStateSource(FState *state); // Extra info maintained while defining an actor. // //========================================================================== -class DDropItem; +struct FDropItem; struct Baggage { @@ -126,7 +126,7 @@ struct Baggage int Lumpnum; FStateDefinitions statedef; - DDropItem *DropItemList; + FDropItem *DropItemList; FScriptPosition ScriptPosition; }; diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 859ccb3f5..50b81310c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -66,9 +66,10 @@ #include "teaminfo.h" #include "v_video.h" #include "r_data/colormaps.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "a_keys.h" #include "g_levellocals.h" +#include "d_player.h" //========================================================================== // @@ -97,7 +98,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool } static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); + return static_cast(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); } static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) { @@ -920,7 +921,7 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) bag.DropItemList = NULL; } - DDropItem *di = new DDropItem; + FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem)); di->Name = type; di->Probability = 255; @@ -938,7 +939,6 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== @@ -1699,12 +1699,12 @@ DEFINE_PROPERTY(distancecheck, S, Actor) //========================================================================== DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) { - static_cast(info)->RestrictedToPlayerClass.Clear(); + static_cast(info)->RestrictedToPlayerClass.Clear(); for(int i = 0;i < PROP_PARM_COUNT;++i) { PROP_STRING_PARM(n, i); if (*n != 0) - static_cast(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1713,12 +1713,12 @@ DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory) { - static_cast(info)->ForbiddenToPlayerClass.Clear(); + static_cast(info)->ForbiddenToPlayerClass.Clear(); for(int i = 0;i < PROP_PARM_COUNT;++i) { PROP_STRING_PARM(n, i); if (*n != 0) - static_cast(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1734,31 +1734,47 @@ DEFINE_CLASS_PROPERTY(amount, I, Inventory) //========================================================================== // //========================================================================== -DEFINE_CLASS_PROPERTY(icon, S, Inventory) +static void SetIcon(FTextureID &icon, Baggage &bag, const char *i) { - PROP_STRING_PARM(i, 0); - if (i == NULL || i[0] == '\0') { - defaults->Icon.SetNull(); + icon.SetNull(); } else { - defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); - if (!defaults->Icon.isValid()) + icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); + if (!icon.isValid()) { // Don't print warnings if the item is for another game or if this is a shareware IWAD. // Strife's teaser doesn't contain all the icon graphics of the full game. - if ((info->GameFilter == GAME_Any || info->GameFilter & gameinfo.gametype) && + if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) && !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, - "Icon '%s' for '%s' not found\n", i, info->TypeName.GetChars()); + "Icon '%s' for '%s' not found\n", i, bag.Info->TypeName.GetChars()); } } } } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(icon, S, Inventory) +{ + PROP_STRING_PARM(i, 0); + SetIcon(defaults->Icon, bag, i); +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(althudicon, S, Inventory) +{ + PROP_STRING_PARM(i, 0); + SetIcon(defaults->AltHUDIcon, bag, i); +} + //========================================================================== // //========================================================================== @@ -1801,8 +1817,8 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); - static_cast(info)->PickupMsg = str; + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->PickupMsg = str; } //========================================================================== @@ -1845,8 +1861,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory) { PROP_INT_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); - static_cast(info)->GiveQuest = i; + defaults->GiveQuest = i; } //========================================================================== @@ -2096,9 +2111,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) int alpha; PalEntry *pBlendColor; - bool isgiver = info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)); + bool isgiver = info->IsDescendantOf(NAME_PowerupGiver); - if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || isgiver) + if (info->IsDescendantOf(NAME_Powerup) || isgiver) { pBlendColor = &defaults->ColorVar(NAME_BlendColor); } @@ -2148,7 +2163,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) { PalEntry BlendColor; - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n"); return; @@ -2183,7 +2198,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) { - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n"); return; @@ -2198,7 +2213,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory) { - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n"); return; @@ -2214,7 +2229,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory) { PROP_STRING_PARM(str, 0); - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n"); return; @@ -2261,8 +2276,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->DisplayName = str; + info->DisplayName = str; } //========================================================================== @@ -2274,8 +2288,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn) FString tmp = str; tmp.ReplaceChars (' ', '_'); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->SoundClass = tmp; + defaults->SoundClass = tmp.IsNotEmpty()? FName(tmp) : NAME_None; } //========================================================================== @@ -2286,21 +2299,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) PROP_STRING_PARM(str, 0); FString tmp = str; - tmp.ToUpper(); - bool valid = (tmp.Len() == 3 && - (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && - (((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) && - (((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9'))) - ); - if (!valid) + if (tmp.Len() == 0) defaults->Face = NAME_None; + else { - bag.ScriptPosition.Message(MSG_OPTERROR, - "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", - tmp.GetChars(), info->TypeName.GetChars ()); + tmp.ToUpper(); + bool valid = (tmp.Len() == 3 && + (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && + (((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) && + (((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9'))) + ); + if (!valid) + { + bag.ScriptPosition.Message(MSG_OPTERROR, + "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", + tmp.GetChars(), info->TypeName.GetChars()); + } + defaults->Face = tmp; } - - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->Face = tmp; } //========================================================================== @@ -2314,9 +2329,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) if (start > end) swapvalues (start, end); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorRangeStart = start; - static_cast(info)->ColorRangeEnd = end; + defaults->ColorRangeStart = start; + defaults->ColorRangeEnd = end; } //========================================================================== @@ -2371,8 +2385,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2398,8 +2411,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) } else if (color.Lump >= 0) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2416,8 +2428,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Remove(setnum); + FPlayerColorSet color; + memset(&color, 0, sizeof(color)); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2651,8 +2664,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) PROP_STRING_PARM(type, 3); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->PainFlashes.Insert(type, color); + PainFlashes.Push(std::make_tuple(info, type, color)); } } @@ -2672,7 +2684,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) bag.DropItemList = NULL; } - DDropItem *di = new DDropItem; + FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem)); di->Name = str; di->Probability = 255; @@ -2684,7 +2696,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== @@ -2693,8 +2704,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->InvulMode = str; + defaults->InvulMode = str; } //========================================================================== @@ -2703,8 +2713,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->HealingRadiusType = str; + defaults->HealingRadiusType = str; } //========================================================================== @@ -2712,11 +2721,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); for (int i = 0; i < 5; i++) { PROP_DOUBLE_PARM(val, i); - static_cast(info)->HexenArmor[i] = val; + defaults->HexenArmor[i] = val; } } @@ -2725,9 +2733,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); PROP_STRING_PARM(val, 0); - static_cast(info)->Portrait = val; + defaults->Portrait = val; } //========================================================================== @@ -2737,7 +2744,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss { PROP_INT_PARM(slot, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); if (slot < 0 || slot > 9) { I_Error("Slot must be between 0 and 9."); @@ -2751,7 +2757,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss PROP_STRING_PARM(str, i); weapons << ' ' << str; } - static_cast(info)->Slot[slot] = &weapons[1]; + defaults->Slot[slot] = weapons.IsEmpty()? NAME_None : FName(weapons); } } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 8b8e3c864..36619ef5b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -6,6 +6,9 @@ #include "vectors.h" #include "cmdlib.h" #include "doomerrors.h" +#include "memarena.h" + +extern FMemArena ClassDataAllocator; #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return #define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function @@ -693,10 +696,8 @@ do_double: if (inexact) } }; -class VMFunction : public DObject +class VMFunction { - DECLARE_ABSTRACT_CLASS(VMFunction, DObject); - HAS_OBJECT_POINTERS; public: bool Native; bool Final = false; // cannot be overridden @@ -709,7 +710,29 @@ public: class PPrototype *Proto; - VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {} + VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) + { + AllFunctions.Push(this); + } + virtual ~VMFunction() {} + + void *operator new(size_t size) + { + return ClassDataAllocator.Alloc(size); + } + + void operator delete(void *block) {} + void operator delete[](void *block) {} + static void DeleteAll() + { + for (auto f : AllFunctions) + { + f->~VMFunction(); + } + AllFunctions.Clear(); + } + static TArray AllFunctions; +protected: }; // VM frame layout: @@ -838,11 +861,9 @@ struct FStatementInfo class VMScriptFunction : public VMFunction { - DECLARE_CLASS(VMScriptFunction, VMFunction); public: VMScriptFunction(FName name=NAME_None); ~VMScriptFunction(); - size_t PropagateMark(); void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } @@ -910,7 +931,6 @@ private: class VMNativeFunction : public VMFunction { - DECLARE_CLASS(VMNativeFunction, VMFunction); public: typedef int (*NativeCallType)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret); diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index c44fbb2ea..d5eaed5bd 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -42,14 +42,9 @@ cycle_t VMCycles[10]; int VMCalls[10]; IMPLEMENT_CLASS(VMException, false, false) -IMPLEMENT_CLASS(VMFunction, true, true) -IMPLEMENT_POINTERS_START(VMFunction) - IMPLEMENT_POINTER(Proto) -IMPLEMENT_POINTERS_END +TArray VMFunction::AllFunctions; -IMPLEMENT_CLASS(VMScriptFunction, false, false) -IMPLEMENT_CLASS(VMNativeFunction, false, false) VMScriptFunction::VMScriptFunction(FName name) { @@ -87,7 +82,6 @@ VMScriptFunction::~VMScriptFunction() KonstS[i].~FString(); } } - M_Free(Code); } } @@ -100,7 +94,7 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko assert(numkonsts >= 0 && numkonsts <= 65535); assert(numkonsta >= 0 && numkonsta <= 65535); assert(numlinenumbers >= 0 && numlinenumbers <= 65535); - void *mem = M_Malloc(numops * sizeof(VMOP) + + void *mem = ClassDataAllocator.Alloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + @@ -166,24 +160,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko NumKonstA = numkonsta; } -size_t VMScriptFunction::PropagateMark() -{ - if (KonstA != NULL) - { - FVoidObj *konsta = KonstA; - VM_UBYTE *atag = KonstATags(); - for (int count = NumKonstA; count > 0; --count) - { - if (*atag++ == ATAG_OBJECT) - { - GC::Mark(konsta->o); - } - konsta++; - } - } - return NumKonstA * sizeof(void *) + Super::PropagateMark(); -} - void VMScriptFunction::InitExtra(void *addr) { char *caddr = (char*)addr; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 93f41746f..4972e1344 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -48,7 +48,7 @@ #include "p_lnspec.h" #include "i_system.h" #include "gdtoa.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "version.h" static int GetIntConst(FxExpression *ex, FCompileContext &ctx) diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index a14443b7d..dc5fea565 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -2,7 +2,7 @@ #define ZCC_COMPILE_H #include -#include "codegeneration/codegen.h" +#include "backend/codegen.h" struct Baggage; struct FPropertyInfo; diff --git a/src/serializer.h b/src/serializer.h index e4dc8f226..4f0d90cec 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -246,11 +246,6 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimat template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def); -template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, PClassPlayerPawn *&clst, PClassPlayerPawn **def) -{ - return Serialize(arc, key, (PClassActor *&)clst, (PClassActor **)def); -} - FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode); template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) { diff --git a/src/v_blend.cpp b/src/v_blend.cpp index ffc16cd5c..41e6fe7ff 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -123,7 +123,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int } PalEntry painFlash = CPlayer->mo->DamageFade; - CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); + CPlayer->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); if (painFlash.a != 0) { diff --git a/src/zstring.h b/src/zstring.h index c696f7fd6..c58fb111a 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -449,4 +449,14 @@ template<> struct THashTraits // Compares two keys, returning zero if they are the same. int Compare(const FString &left, const FString &right) { return left.Compare(right); } }; + +class FStringNoInit +{ + char mem[sizeof(FString)]; + operator FString&() + { + return *reinterpret_cast(&mem); + } +}; + #endif diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 4ff19b24b..27f3c08fe 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -498,7 +498,7 @@ class Actor : Thinker native native bool UsePuzzleItem(int PuzzleItemType); native float AccuracyFactor(); native bool MorphMonster (Class spawntype, int duration, int style, Class enter_flash, Class exit_flash); - native void SetCamera(Actor cam, bool revert = false); + action native void SetCamera(Actor cam, bool revert = false); // DECORATE compatible functions native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 83d714684..1ff8a5e92 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -256,7 +256,7 @@ class BlockThingsIterator : Object native native bool Next(); } -class DropItem : Object native +struct DropItem native { native readonly DropItem Next; native readonly name Name; diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index da915f170..28b20cdd5 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -24,7 +24,7 @@ class Inventory : Actor native native bool bCreateCopyMoved; native bool bInitEffectFailed; native meta String PickupMsg; - native meta int GiveQuest; + native /*meta*/ int GiveQuest; Default { diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index 7bda52e52..c1fbf4384 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -252,7 +252,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: TryPickup + // Weapon :: TryPickup // // If you can't see the weapon when it's active, then you can't pick it up. // @@ -277,7 +277,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: TryPickup + // Weapon :: TryPickup // //=========================================================================== @@ -293,7 +293,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: Use + // Weapon :: Use // // Make the player switch to self weapon. // @@ -324,7 +324,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: Destroy + // Weapon :: Destroy // //=========================================================================== @@ -347,7 +347,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: HandlePickup + // Weapon :: HandlePickup // // Try to leach ammo from the weapon if you have it already. // @@ -372,7 +372,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: PickupForAmmo + // Weapon :: PickupForAmmo // // The player already has self weapon, so try to pick it up for ammo. // @@ -411,7 +411,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: CreateCopy + // Weapon :: CreateCopy // //=========================================================================== @@ -428,7 +428,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: CreateTossable + // Weapon :: CreateTossable // // A weapon that's tossed out should contain no ammo, so you can't cheat // by dropping it and then picking it back up. @@ -464,7 +464,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AttachToOwner + // Weapon :: AttachToOwner // //=========================================================================== @@ -491,7 +491,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddAmmo + // Weapon :: AddAmmo // // Give some ammo to the owner, even if it's just 0. // @@ -536,7 +536,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddExistingAmmo + // Weapon :: AddExistingAmmo // // Give the owner some more ammo he already has. // @@ -563,7 +563,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddWeapon + // Weapon :: AddWeapon // // Give the owner a weapon if they don't have it already. // @@ -588,7 +588,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: ShouldStay + // Weapon :: ShouldStay // //=========================================================================== @@ -606,7 +606,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: EndPowerUp + // Weapon :: EndPowerUp // // The Tome of Power just expired. // diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 1be556c7b..09955e0b2 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -9,17 +9,16 @@ class PlayerPawn : Actor native native Inventory InvFirst; // first inventory item displayed on inventory bar native Inventory InvSel; // selected inventory item native meta String DisplayName; // Display name (used in menus, etc.) - native meta String SoundClass; // Sound class - native meta String Face; // Doom status bar face (when used) - native meta String Portrait; - native meta String Slot[10]; - native meta Name InvulMode; - native meta Name HealingRadiusType; - native meta double HexenArmor[5]; - native meta uint8 ColorRangeStart; // Skin color range - native meta uint8 ColorRangeEnd; - //FPlayerColorSetMap ColorSets; - //PainFlashList PainFlashes; + + native /*meta*/ Name SoundClass; // Sound class + native /*meta*/ Name Face; // Doom status bar face (when used) + native /*meta*/ Name Portrait; + native /*meta*/ Name Slot[10]; + native /*meta*/ Name InvulMode; + native /*meta*/ Name HealingRadiusType; + native /*meta*/ double HexenArmor[5]; + native /*meta*/ uint8 ColorRangeStart; // Skin color range + native /*meta*/ uint8 ColorRangeEnd; // [GRB] Player class properties native double JumpZ;