From 3cbd62479b827a69d59f15cee7ea1c614c9d533e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 11:13:41 +0100 Subject: [PATCH 01/17] - took VMFunction out of the DObject hierarchy. As it stood, just compiling the internal ZScript code created more than 9000 DObjects, none of which really need to be subjected to garbage collection, aside from allowing lazy deallocation. This puts an incredible drag on the garbage collector which often needs several minutes to finish processing before actual deletion can start. The VM functions with roughly 1800 of these objects were by far the easiest to refactor so they are now. They also use a memory arena now which significantly reduces their memory footprint. --- src/dobjgc.cpp | 20 ++++++++------------ src/dobjtype.cpp | 2 +- src/info.cpp | 26 -------------------------- src/info.h | 1 - src/memarena.cpp | 20 ++++++++++++++++++++ src/memarena.h | 1 + src/scripting/vm/vm.h | 33 ++++++++++++++++++++++++++------- src/scripting/vm/vmframe.cpp | 29 +++-------------------------- 8 files changed, 59 insertions(+), 73 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index df1760dd7..5b6a34bdc 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -361,17 +361,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) @@ -776,7 +765,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 +780,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 +809,4 @@ CCMD(gc) } } } + diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 54cc64675..6dc4483a0 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2698,7 +2698,6 @@ 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(); } @@ -2947,6 +2946,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. diff --git a/src/info.cpp b/src/info.cpp index c86486b5e..18eecc2d1 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -351,32 +351,6 @@ void PClassActor::DeriveData(PClass *newclass) } -//========================================================================== -// -// 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(); -} - //========================================================================== // // PClassActor :: SetReplacement diff --git a/src/info.h b/src/info.h index 3a20994f5..64be2d92f 100644 --- a/src/info.h +++ b/src/info.h @@ -256,7 +256,6 @@ 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); 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/scripting/vm/vm.h b/src/scripting/vm/vm.h index 8b8e3c864..6d758f1bc 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -6,6 +6,7 @@ #include "vectors.h" #include "cmdlib.h" #include "doomerrors.h" +#include "memarena.h" #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 +694,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 +708,30 @@ 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 Allocator.Alloc(size); + } + + void operator delete(void *block) {} + void operator delete[](void *block) {} + static void DeleteAll() + { + for (auto f : AllFunctions) + { + f->~VMFunction(); + } + AllFunctions.Clear(); + } + static FMemArena Allocator; + static TArray AllFunctions; +protected: }; // VM frame layout: @@ -838,11 +860,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 +930,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..5fa82ad0c 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -42,14 +42,10 @@ 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 +FMemArena VMFunction::Allocator(32768); +TArray VMFunction::AllFunctions; -IMPLEMENT_CLASS(VMScriptFunction, false, false) -IMPLEMENT_CLASS(VMNativeFunction, false, false) VMScriptFunction::VMScriptFunction(FName name) { @@ -87,7 +83,6 @@ VMScriptFunction::~VMScriptFunction() KonstS[i].~FString(); } } - M_Free(Code); } } @@ -100,7 +95,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 = Allocator.Alloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + @@ -166,24 +161,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; From f6d6f310a96d89279f2ec06910edda50b9389e06 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 11:56:12 +0100 Subject: [PATCH 02/17] - fixed comments. --- src/scripting/codegeneration/dynarrays.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/codegeneration/dynarrays.cpp index 05e18a3ca..0152c6520 100644 --- a/src/scripting/codegeneration/dynarrays.cpp +++ b/src/scripting/codegeneration/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 From 5a81a4ca16e27dc01991abd06dbc2425992a55e1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 12:24:08 +0100 Subject: [PATCH 03/17] - moved a few things around to have them into better fitting places. --- src/CMakeLists.txt | 16 ++++++++-------- src/d_dehacked.cpp | 2 +- src/d_main.cpp | 2 +- src/dobjgc.cpp | 2 +- src/dobjtype.cpp | 6 +----- src/dobjtype.h | 1 - .../{codegeneration => backend}/codegen.cpp | 0 .../{codegeneration => backend}/codegen.h | 0 .../{codegeneration => backend}/dynarrays.cpp | 0 src/scripting/{vm => backend}/vmbuilder.cpp | 2 +- src/scripting/{vm => backend}/vmbuilder.h | 0 src/scripting/{vm => backend}/vmdisasm.cpp | 0 src/scripting/decorate/olddecorations.cpp | 2 +- src/scripting/decorate/thingdef_exp.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/decorate/thingdef_states.cpp | 4 ++-- src/scripting/thingdef.cpp | 4 ++-- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 2 +- src/scripting/zscript/zcc_compile.h | 2 +- 20 files changed, 23 insertions(+), 28 deletions(-) rename src/scripting/{codegeneration => backend}/codegen.cpp (100%) rename src/scripting/{codegeneration => backend}/codegen.h (100%) rename src/scripting/{codegeneration => backend}/dynarrays.cpp (100%) rename src/scripting/{vm => backend}/vmbuilder.cpp (99%) rename src/scripting/{vm => backend}/vmbuilder.h (100%) rename src/scripting/{vm => backend}/vmdisasm.cpp (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 200164d7b..ce60111fa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -778,7 +778,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 @@ -1197,14 +1197,14 @@ set (PCH_SOURCES 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 @@ -1421,9 +1421,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/d_dehacked.cpp b/src/d_dehacked.cpp index 7fecec550..7ad5e6344 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 diff --git a/src/d_main.cpp b/src/d_main.cpp index 573c19071..e91c2ccaa 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2717,7 +2717,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/dobjgc.cpp b/src/dobjgc.cpp index 5b6a34bdc..ca57e6aca 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -783,7 +783,7 @@ CCMD(gc) else if (stricmp(argv[1], "count") == 0) { int cnt = 0; - for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++) + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++); Printf("%d active objects counted\n", cnt); } else if (stricmp(argv[1], "pause") == 0) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 6dc4483a0..c39e316a7 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3877,11 +3877,7 @@ 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 +IMPLEMENT_CLASS(PSymbolVMFunction, false, false) //========================================================================== // diff --git a/src/dobjtype.h b/src/dobjtype.h index 3858585e9..6fd2f9b1d 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -84,7 +84,6 @@ struct FNamespaceManager; class PSymbolVMFunction : public PSymbol { DECLARE_CLASS(PSymbolVMFunction, PSymbol); - HAS_OBJECT_POINTERS; public: VMFunction *Function; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/backend/codegen.cpp similarity index 100% rename from src/scripting/codegeneration/codegen.cpp rename to src/scripting/backend/codegen.cpp diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/backend/codegen.h similarity index 100% rename from src/scripting/codegeneration/codegen.h rename to src/scripting/backend/codegen.h diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/backend/dynarrays.cpp similarity index 100% rename from src/scripting/codegeneration/dynarrays.cpp rename to src/scripting/backend/dynarrays.cpp 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..575bbf0a4 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 ------------------------------------------------------------------- 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/thingdef.cpp b/src/scripting/thingdef.cpp index 6776e70e8..f2849eb39 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 -------------------------------------------- diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 859ccb3f5..22d6610ce 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -66,7 +66,7 @@ #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" 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; From 18c532c3076e856dccc9c8818c53cd0be139bc75 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 13:17:25 +0100 Subject: [PATCH 04/17] - moved the compiler symbols into their own file. - removed all pointer declarations to types from the symbols. All types must be placed into the type table which means that they can be considered static. --- src/CMakeLists.txt | 1 + src/dobject.h | 1 + src/dobjtype.cpp | 288 ------------------------- src/dobjtype.h | 276 ------------------------ src/scripting/symbols.cpp | 440 ++++++++++++++++++++++++++++++++++++++ src/scripting/symbols.h | 286 +++++++++++++++++++++++++ 6 files changed, 728 insertions(+), 564 deletions(-) create mode 100644 src/scripting/symbols.cpp create mode 100644 src/scripting/symbols.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ce60111fa..d0d31984d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1194,6 +1194,7 @@ 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 diff --git a/src/dobject.h b/src/dobject.h index ef7560909..6ad8ded6f 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -603,6 +603,7 @@ static inline void GC::WriteBarrier(DObject *pointed) } } +#include "symbols.h" #include "dobjtype.h" inline bool DObject::IsKindOf (const PClass *base) const diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c39e316a7..eda59bcc1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -66,7 +66,6 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. -FNamespaceManager Namespaces; FTypeTable TypeTable; TArray PClass::AllClasses; @@ -2683,68 +2682,6 @@ 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); - } - 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) @@ -3863,228 +3800,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, false) - -//========================================================================== -// -// -// -//========================================================================== - -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 6fd2f9b1d..c999f3f50 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,100 +49,6 @@ struct VMReturn; class VMFunction; struct FNamespaceManager; -// 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); - 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. @@ -536,52 +412,6 @@ 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 @@ -729,36 +559,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 --------------------------- @@ -914,82 +714,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/scripting/symbols.cpp b/src/scripting/symbols.cpp new file mode 100644 index 000000000..ba0704433 --- /dev/null +++ b/src/scripting/symbols.cpp @@ -0,0 +1,440 @@ +/* +** 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 + + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol::~PSymbol() +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +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(); +} + +//========================================================================== +// +// +// +//========================================================================== + +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; +} + +//========================================================================== +// +// +// +//========================================================================== + +//========================================================================== +// +// +// +//========================================================================== + +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; +} + +//========================================================================== +// +// 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..52d7ac60a --- /dev/null +++ b/src/scripting/symbols.h @@ -0,0 +1,286 @@ +// 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: + 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; } +}; + +// 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(); + + 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; +}; + +// 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; + + From f1b3d60b2f606b3fd2f96209de3c4d81211ca70b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 13:37:13 +0100 Subject: [PATCH 05/17] - PSymbol does not need to inherit from PTypeBase. This also means that there are no remaining references to any symbol object outside of the symbol tables. --- src/dobject.h | 1 + src/dobjtype.cpp | 14 -------------- src/dobjtype.h | 1 - src/scripting/symbols.cpp | 10 ---------- src/scripting/symbols.h | 15 ++------------- 5 files changed, 3 insertions(+), 38 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 6ad8ded6f..7c2fd4c22 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -205,6 +205,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; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index eda59bcc1..3c556da3b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -489,20 +489,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) diff --git a/src/dobjtype.h b/src/dobjtype.h index c999f3f50..cfae5e169 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -224,7 +224,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 -------------------------------------------------------------- diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index ba0704433..68b9d522c 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -59,16 +59,6 @@ IMPLEMENT_POINTER(Parent) IMPLEMENT_POINTERS_END -//========================================================================== -// -// -// -//========================================================================== - -PSymbol::~PSymbol() -{ -} - //========================================================================== // // diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index 52d7ac60a..af5bfb80e 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -19,23 +19,12 @@ class PTypeBase : public DObject DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) public: - virtual FString QualifiedName() const - { - return ""; - } }; -class PSymbol : public PTypeBase +class PSymbol : public DObject { - DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase); + DECLARE_ABSTRACT_CLASS(PSymbol, DObject); public: - virtual ~PSymbol(); - - virtual FString QualifiedName() const - { - return SymbolName.GetChars(); - } - FName SymbolName; protected: From 31223ca180b0b3199fa0c6a04e47548ec356150d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 14:34:39 +0100 Subject: [PATCH 06/17] - remove all symbols that get linked into the symbol table from the garbage collector. Symbols are very easy to manage once they are in a symbol table and there's lots of them so this reduces the amount of work the GC needs to do quite considerably. After cleaning out compile-time-only symbols there will still be more than 2000 left, one for each function and one for each member variable of a class or struct. This means more than 2000 object that won't need to tracked constantly by the garbage collector. Note that loose fields which do occur during code generation will be GC'd just as before. --- src/dobject.cpp | 70 ++++++++++++++++++------------- src/dobject.h | 3 ++ src/dobjgc.cpp | 6 ++- src/dobjtype.cpp | 26 +----------- src/dobjtype.h | 4 -- src/scripting/backend/codegen.cpp | 13 ------ src/scripting/backend/codegen.h | 1 - src/scripting/symbols.cpp | 52 +++++++---------------- src/scripting/symbols.h | 5 +-- 9 files changed, 64 insertions(+), 116 deletions(-) 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 7c2fd4c22..82051e3bd 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -468,6 +468,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; diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index ca57e6aca..e6ff9c734 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -277,7 +277,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) { @@ -551,6 +553,8 @@ void Barrier(DObject *pointing, DObject *pointed) 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) { diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 3c556da3b..f0e7b2fc1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -185,18 +185,6 @@ PType::~PType() { } -//========================================================================== -// -// PType :: PropagateMark -// -//========================================================================== - -size_t PType::PropagateMark() -{ - size_t marked = Symbols.MarkSymbols(); - return marked + Super::PropagateMark(); -} - //========================================================================== // // PType :: WriteValue @@ -2413,7 +2401,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); @@ -2444,18 +2432,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 diff --git a/src/dobjtype.h b/src/dobjtype.h index cfae5e169..6c07b047b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -171,8 +171,6 @@ public: const char *DescriptiveName() const; - size_t PropagateMark(); - static void StaticInit(); }; @@ -520,8 +518,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; diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index a3dc066e9..910dba19f 100644 --- a/src/scripting/backend/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; -} - //========================================================================== // // diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index c64ec2094..abbcbd54e 100644 --- a/src/scripting/backend/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/symbols.cpp b/src/scripting/symbols.cpp index 68b9d522c..b6adb33e7 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -149,34 +149,19 @@ PSymbolTable::~PSymbolTable () //========================================================================== // -// -// -//========================================================================== - -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); -} - -//========================================================================== -// -// +// this must explicitly delete all content because the symbols have +// been released from the GC. // //========================================================================== void PSymbolTable::ReleaseSymbols() { - // The GC will take care of deleting the symbols. We just need to - // clear our references to them. + auto it = GetIterator(); + MapType::Pair *pair; + while (it.NextPair(pair)) + { + delete pair->Value; + } Symbols.Clear(); } @@ -243,6 +228,7 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) return nullptr; } Symbols.Insert(sym->SymbolName, sym); + sym->Release(); // no more GC, please! return sym; } @@ -257,6 +243,7 @@ void PSymbolTable::RemoveSymbol(PSymbol *sym) auto mysym = Symbols.CheckKey(sym->SymbolName); if (mysym == nullptr || *mysym != sym) return; Symbols.Remove(sym->SymbolName); + delete sym; } //========================================================================== @@ -265,20 +252,20 @@ void PSymbolTable::RemoveSymbol(PSymbol *sym) // //========================================================================== -PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) +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; - return oldsym; } // 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); - return nullptr; } //========================================================================== @@ -306,18 +293,6 @@ PNamespace::PNamespace(int filenum, PNamespace *parent) // //========================================================================== -size_t PNamespace::PropagateMark() -{ - GC::Mark(Parent); - return Symbols.MarkSymbols() + 1; -} - -//========================================================================== -// -// -// -//========================================================================== - FNamespaceManager::FNamespaceManager() { GlobalNamespace = nullptr; @@ -370,6 +345,7 @@ size_t FNamespaceManager::MarkSymbols() void FNamespaceManager::ReleaseSymbols() { + RemoveSymbols(); GlobalNamespace = nullptr; AllNamespaces.Clear(); } diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index af5bfb80e..3c9d1f8f3 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -192,8 +192,6 @@ struct 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); @@ -218,7 +216,7 @@ struct PSymbolTable // 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 ReplaceSymbol(PSymbol *sym); void RemoveSymbol(PSymbol *sym); @@ -255,7 +253,6 @@ public: PNamespace() {} PNamespace(int filenum, PNamespace *parent); - size_t PropagateMark(); }; struct FNamespaceManager From a6785afddbd8d9891e10cbbfbf8a1e2405094020 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 15:47:22 +0100 Subject: [PATCH 07/17] - optimized the FName versions of IsDescendantOf and IsKindOf. These can be done without first looking up the class type itself. --- src/am_map.cpp | 2 +- src/b_bot.cpp | 2 +- src/b_think.cpp | 2 +- src/c_cmds.cpp | 2 +- src/d_dehacked.cpp | 4 +-- src/dobject.h | 6 ++++ src/dobjtype.h | 13 +++++++ src/fragglescript/t_func.cpp | 12 +++---- src/g_inventory/a_keys.cpp | 2 +- src/g_inventory/a_weapons.cpp | 12 +++---- src/g_shared/a_morph.cpp | 2 +- src/g_shared/shared_hud.cpp | 6 ++-- src/g_statusbar/sbarinfo_commands.cpp | 38 ++++++++++----------- src/gl/dynlights/gl_dynlight.cpp | 2 +- src/info.cpp | 2 +- src/m_cheat.cpp | 4 +-- src/p_acs.cpp | 6 ++-- src/p_actionfunctions.cpp | 6 ++-- src/p_conversation.cpp | 4 +-- src/p_enemy.cpp | 4 +-- src/p_mobj.cpp | 4 +-- src/p_pspr.cpp | 6 ++-- src/p_user.cpp | 24 ++++++------- src/portal.cpp | 2 +- src/scripting/thingdef.cpp | 6 ++-- src/scripting/thingdef_properties.cpp | 12 +++---- src/zstring.h | 10 ++++++ wadsrc/static/zscript/inventory/weapons.txt | 28 +++++++-------- 28 files changed, 126 insertions(+), 97 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index be92fd37a..57eccc19d 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 7ad5e6344..c30fc64ae 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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/dobject.h b/src/dobject.h index 82051e3bd..f3c290443 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -458,6 +458,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); @@ -615,6 +616,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/dobjtype.h b/src/dobjtype.h index 6c07b047b..42280a12b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -622,11 +622,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)); } diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 0ee391e21..e8cde0222 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -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_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_weapons.cpp b/src/g_inventory/a_weapons.cpp index a916531be..888259098 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -528,7 +528,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 +635,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 +650,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 +982,7 @@ void FWeaponSlots::AddExtraWeapons() { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!cls->IsDescendantOf(NAME_Weapon)) { continue; } @@ -1342,7 +1342,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 +1441,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_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 0c95c77b8..cd72bca79 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -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)) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 4ab0c8133..79c51350b 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -612,7 +612,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) // Now check for the remaining weapons that are in the inventory but not in the weapon slots for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory) { - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (inv->IsKindOf(NAME_Weapon)) { AddAmmoToList((AWeapon*)inv); } @@ -713,7 +713,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 +767,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)); 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 18eecc2d1..48a22c2d4 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()); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 23c2f1ded..bf687c09d 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -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) || diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bddcd7f95..8b0075475 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -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); } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index c732ea18c..ea271967b 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; } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index a77a7358d..e9ad0ff0d 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1331,7 +1331,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 +1357,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_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..d39786311 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -789,7 +789,7 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) item->ClearCounters(); if (!givecheat || amount > 0) { - if (type->IsDescendantOf (PClass::FindActor(NAME_BasicArmorPickup)) || type->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus))) + if (type->IsDescendantOf (NAME_BasicArmorPickup) || type->IsDescendantOf(NAME_BasicArmorBonus)) { item->IntVar(NAME_SaveAmount) *= amount; } @@ -903,7 +903,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; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index c443ca7da..bf6c79a82 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -166,7 +166,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); } @@ -353,7 +353,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)); @@ -1333,7 +1333,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_user.cpp b/src/p_user.cpp index c6b0a7d58..1b9cedf4a 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -963,7 +963,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); @@ -1136,29 +1136,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 +1167,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) { @@ -1412,7 +1412,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 +1432,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); @@ -1536,7 +1536,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,7 +1709,7 @@ 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")); if (spawntype == NULL) 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/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index f2849eb39..51fb0239c 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -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"); } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 22d6610ce..8cffbc347 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2096,9 +2096,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 +2148,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 +2183,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 +2198,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 +2214,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; 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/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. // From 2ca0e347850a94231f4dbfdd9c1603fbb1964aa0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 16:42:13 +0100 Subject: [PATCH 08/17] - turned many of PClassPlayerPawn's strings into names and moved all scalar properties into APlayerPawn. The goal is to get rid of PClassPlayerPawn and PClassInventory so that the old assumption that all actor class descriptors have the same size can be restored This is important to remove some code that seriously blocks optimization of the type table because that can only be done if types do not need to be replaced. --- src/d_player.h | 20 ++++++----- src/g_inventory/a_weapons.cpp | 5 +-- src/g_shared/a_morph.cpp | 6 ++-- src/g_statusbar/sbar_mugshot.cpp | 2 +- src/menu/playerdisplay.cpp | 6 ++-- src/p_user.cpp | 46 +++++++----------------- src/r_data/sprites.cpp | 27 +++++++------- src/scripting/thingdef_properties.cpp | 47 ++++++++++++------------- wadsrc/static/zscript/shared/player.txt | 21 ++++++----- 9 files changed, 82 insertions(+), 98 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e09db38a3..b79e56862 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -82,15 +82,6 @@ public: bool GetPainFlash(FName type, PalEntry *color) const; 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; }; @@ -176,6 +167,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; + }; // diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 888259098..afa55cc10 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1154,11 +1154,12 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *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); } } } diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index cd72bca79..246073010 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -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; @@ -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_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/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index 57c8ecf26..821c2ea70 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -557,11 +557,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/p_user.cpp b/src/p_user.cpp index 1b9cedf4a..ab1920ae8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -542,12 +542,6 @@ 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) @@ -555,24 +549,9 @@ 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) @@ -1230,7 +1209,7 @@ const char *APlayerPawn::GetSoundClass() const // [GRB] PClassPlayerPawn *pclass = GetClass(); - return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass.GetChars() : "player"; + return SoundClass != NAME_None? SoundClass.GetChars() : "player"; } //=========================================================================== @@ -1373,10 +1352,10 @@ void APlayerPawn::GiveDefaultInventory () 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 @@ -3248,16 +3227,17 @@ DEFINE_FIELD(APlayerPawn, DamageFade) DEFINE_FIELD(APlayerPawn, ViewBob) DEFINE_FIELD(APlayerPawn, FullHeight) -DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType) +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(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) diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 7fb59ef94..be44e9d82 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -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_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/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 8cffbc347..ef9a905a3 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2274,8 +2274,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 +2285,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 +2315,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; } //========================================================================== @@ -2693,8 +2693,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; } //========================================================================== @@ -2704,7 +2703,7 @@ 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; } //========================================================================== @@ -2716,7 +2715,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) for (int i = 0; i < 5; i++) { PROP_DOUBLE_PARM(val, i); - static_cast(info)->HexenArmor[i] = val; + defaults->HexenArmor[i] = val; } } @@ -2727,7 +2726,7 @@ 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; } //========================================================================== @@ -2751,7 +2750,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/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 0a7798ace..dc1d1ba1d 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; From eebe09fb59760d48ed71bba09272ef9a837697dd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 16:57:48 +0100 Subject: [PATCH 09/17] - moved the scalar class properties of PClassInventory into AInventory. What's left is the non-scalars, they will need different treatment to get them out of the way. --- src/g_inventory/a_pickups.cpp | 9 ++--- src/g_inventory/a_pickups.h | 4 +- src/g_shared/shared_hud.cpp | 34 ++++++---------- src/scripting/thingdef_properties.cpp | 40 ++++++++++++------- wadsrc/static/zscript/inventory/inventory.txt | 2 +- 5 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 66f51e92e..796036c2d 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -29,8 +29,6 @@ IMPLEMENT_CLASS(PClassInventory, false, false) PClassInventory::PClassInventory() { - GiveQuest = 0; - AltHUDIcon.SetNull(); } void PClassInventory::DeriveData(PClass *newclass) @@ -40,8 +38,6 @@ void PClassInventory::DeriveData(PClass *newclass) PClassInventory *newc = static_cast(newclass); newc->PickupMsg = PickupMsg; - newc->GiveQuest = GiveQuest; - newc->AltHUDIcon = AltHUDIcon; newc->ForbiddenToPlayerClass = ForbiddenToPlayerClass; newc->RestrictedToPlayerClass = RestrictedToPlayerClass; } @@ -98,8 +94,8 @@ DEFINE_FIELD(AInventory, DropTime) DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) +DEFINE_FIELD(AInventory, GiveQuest) DEFINE_FIELD(PClassInventory, PickupMsg) -DEFINE_FIELD(PClassInventory, GiveQuest) //=========================================================================== // @@ -163,7 +159,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); } //=========================================================================== diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index be6280c0a..f467ae984 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -60,8 +60,6 @@ public: void Finalize(FStateDefinitions &statedef); FString PickupMsg; - int GiveQuest; // Optionally give one of the quest items. - FTextureID AltHUDIcon; TArray RestrictedToPlayerClass; TArray ForbiddenToPlayerClass; }; @@ -104,6 +102,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_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 79c51350b..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;j=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(); @@ -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/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index ef9a905a3..d1273da18 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -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); +} + //========================================================================== // //========================================================================== @@ -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; } //========================================================================== @@ -2651,7 +2666,6 @@ 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); } } @@ -2702,7 +2716,6 @@ 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))); defaults->HealingRadiusType = str; } @@ -2711,7 +2724,6 @@ 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); @@ -2724,7 +2736,6 @@ 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); defaults->Portrait = val; } @@ -2736,7 +2747,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."); 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 { From c77f6636f82cb3bd15050f454ea8845fd7dc4e4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 18:11:23 +0100 Subject: [PATCH 10/17] - moved the three remaining variables from PClassInventory to PClassActor so that PClassInventory can be removed. --- src/actor.h | 4 +- src/d_dehacked.cpp | 2 +- src/d_player.h | 6 +-- src/dobject.h | 1 - src/dobjtype.cpp | 1 - src/doomtype.h | 3 -- src/fragglescript/t_func.cpp | 14 +++---- src/g_inventory/a_pickups.cpp | 48 +---------------------- src/g_inventory/a_pickups.h | 16 +------- src/g_inventory/a_weapons.h | 2 +- src/info.cpp | 28 +++++++++++++ src/info.h | 5 +++ src/p_acs.cpp | 4 +- src/p_conversation.cpp | 8 +++- src/p_conversation.h | 2 +- src/p_mobj.cpp | 12 ++++-- src/p_usdf.cpp | 16 ++++---- src/p_user.cpp | 10 ++--- src/scripting/decorate/olddecorations.cpp | 2 +- src/scripting/thingdef_properties.cpp | 14 +++---- 20 files changed, 89 insertions(+), 109 deletions(-) diff --git a/src/actor.h b/src/actor.h index 4016d447b..0b33ed3e3 100644 --- a/src/actor.h +++ b/src/actor.h @@ -699,7 +699,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 +736,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/d_dehacked.cpp b/src/d_dehacked.cpp index c30fc64ae..8062faf5a 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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; diff --git a/src/d_player.h b/src/d_player.h index b79e56862..f6009edec 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -110,9 +110,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); diff --git a/src/dobject.h b/src/dobject.h index f3c290443..7b93a30c6 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -93,7 +93,6 @@ enum { CLASSREG_PClass, CLASSREG_PClassActor, - CLASSREG_PClassInventory, CLASSREG_PClassPlayerPawn, }; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f0e7b2fc1..486c72249 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2955,7 +2955,6 @@ PClass *ClassReg::RegisterClass() { &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, - &PClassInventory::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, }; diff --git a/src/doomtype.h b/src/doomtype.h index 248aee33b..11e4f96e2 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -155,12 +155,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 e8cde0222..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)) { diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 796036c2d..53e7d84ed 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -25,50 +25,6 @@ EXTERN_CVAR(Bool, sv_unlimited_pickup) -IMPLEMENT_CLASS(PClassInventory, false, false) - -PClassInventory::PClassInventory() -{ -} - -void PClassInventory::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory))); - Super::DeriveData(newclass); - PClassInventory *newc = static_cast(newclass); - - newc->PickupMsg = PickupMsg; - 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); @@ -95,7 +51,7 @@ DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) DEFINE_FIELD(AInventory, GiveQuest) -DEFINE_FIELD(PClassInventory, PickupMsg) +DEFINE_FIELD(PClassActor, PickupMsg) //=========================================================================== // @@ -545,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 f467ae984..3a67a3b6d 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -50,23 +50,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; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; -}; - class AInventory : public AActor { - DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) + DECLARE_CLASS(AInventory, AActor) HAS_OBJECT_POINTERS public: diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 50862bc47..4ea56b355 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -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/info.cpp b/src/info.cpp index 48a22c2d4..90e2b7db9 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -349,6 +349,11 @@ void PClassActor::DeriveData(PClass *newclass) *newa->PainChances = *PainChances; } + // Inventory stuff + newa->PickupMsg = PickupMsg; + newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; + newa->RestrictedToPlayerClass = RestrictedToPlayerClass; + } //========================================================================== @@ -637,6 +642,29 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *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 64be2d92f..28e75a121 100644 --- a/src/info.h +++ b/src/info.h @@ -317,6 +317,11 @@ public: FName MissileName; double MissileHeight; + // These are only valid for inventory items. + FString PickupMsg; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; + // For those times when being able to scan every kind of actor is convenient static TArray AllActorClasses; }; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 8b0075475..1423c48c4 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); } } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index e9ad0ff0d..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(); 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_mobj.cpp b/src/p_mobj.cpp index d39786311..846a25ca5 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; @@ -789,7 +791,7 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) item->ClearCounters(); if (!givecheat || amount > 0) { - if (type->IsDescendantOf (NAME_BasicArmorPickup) || type->IsDescendantOf(NAME_BasicArmorBonus)) + if (type->IsDescendantOf (PClass::FindActor(NAME_BasicArmorPickup)) || type->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus))) { item->IntVar(NAME_SaveAmount) *= amount; } @@ -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; 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 ab1920ae8..98221de1f 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -931,7 +931,7 @@ bool APlayerPawn::UseInventory (AInventory *item) // //=========================================================================== -AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype) { AWeapon *bestMatch = NULL; int bestOrder = INT_MAX; @@ -993,7 +993,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) // //=========================================================================== -AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype) { AWeapon *best = BestWeapon (ammotype); @@ -1021,7 +1021,7 @@ AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) // //=========================================================================== -void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) +void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype) { if (!player->userinfo.GetNeverSwitch() && player->PendingWeapon == WP_NOCHANGE && @@ -1040,7 +1040,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; } @@ -1346,7 +1346,7 @@ 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); diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 575bbf0a4..50e8f9c6a 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -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/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index d1273da18..7f363b623 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -97,7 +97,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) { @@ -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)); } } @@ -1817,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; } //========================================================================== From dd102caf13d2e558a680be604d12d12b5b651da7 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 8 Feb 2017 08:30:00 -0600 Subject: [PATCH 11/17] - Fixed: SetCamera didn't have the 'action' identifier, nor did it use the actual 'cam' actor provided, rendering it nonfunctional. --- src/p_actionfunctions.cpp | 10 +++++----- wadsrc/static/zscript/actor.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index ea271967b..518d2fb63 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -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/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9b6f42b88..ceda20bd8 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); From 68e9918ed5b3b110bca97567a9000c5d59c38523 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 19:10:11 +0100 Subject: [PATCH 12/17] - moved player color sets and pain flashes into global variables. There's simply never enough of them and they are used far too infrequently to justify the hassle of tagging along two TMaps per class. For what they provide, single global lists that handle all player classes at once are fully sufficient. --- src/d_main.cpp | 2 + src/d_netinfo.cpp | 4 +- src/d_player.h | 17 ++++--- src/doomtype.h | 2 + src/g_pch.h | 1 + src/menu/playerdisplay.cpp | 2 +- src/menu/playermenu.cpp | 6 +-- src/p_user.cpp | 73 ++++++++++++++++++++------- src/scripting/thingdef_properties.cpp | 14 ++--- src/v_blend.cpp | 2 +- 10 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index e91c2ccaa..e0cbcbefa 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2707,6 +2707,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 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 f6009edec..8a5415bc6 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -66,8 +66,11 @@ struct FPlayerColorSet ExtraRange Extra[6]; }; -typedef TMap FPlayerColorSetMap; -typedef TMap PainFlashList; +typedef TArray> PainFlashList; +typedef TArray> ColorSetList; + +extern PainFlashList PainFlashes; +extern ColorSetList ColorSets; class PClassPlayerPawn : public PClassActor { @@ -76,14 +79,8 @@ 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; FString DisplayName; // Display name (used in menus, etc.) - FPlayerColorSetMap ColorSets; - PainFlashList PainFlashes; }; FString GetPrintableDisplayName(PClassPlayerPawn *cls); @@ -541,12 +538,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/doomtype.h b/src/doomtype.h index 11e4f96e2..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" 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/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index 821c2ea70..ba99aba36 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -435,7 +435,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]); } } diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 7116608b3..4126bc80b 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(); diff --git a/src/p_user.cpp b/src/p_user.cpp index 98221de1f..161d15121 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; @@ -551,23 +554,38 @@ void PClassPlayerPawn::DeriveData(PClass *newclass) PClassPlayerPawn *newp = static_cast(newclass); newp->DisplayName = DisplayName; - newp->ColorSets = ColorSets; } +//=========================================================================== +// +// EnumColorsets +// +// Only used by the menu so it doesn't really matter that it's a bit +// inefficient. +// +//=========================================================================== + 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); } @@ -577,20 +595,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; } @@ -3238,8 +3277,6 @@ DEFINE_FIELD(APlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd) DEFINE_FIELD(PClassPlayerPawn, DisplayName) -DEFINE_FIELD(PClassPlayerPawn, ColorSets) -DEFINE_FIELD(PClassPlayerPawn, PainFlashes) DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 7f363b623..33d97dccf 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -69,6 +69,7 @@ #include "backend/vmbuilder.h" #include "a_keys.h" #include "g_levellocals.h" +#include "d_player.h" //========================================================================== // @@ -2386,8 +2387,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)); } } @@ -2413,8 +2413,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)); } } @@ -2431,8 +2430,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)); } } @@ -2666,7 +2666,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) PROP_STRING_PARM(type, 3); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - static_cast(info)->PainFlashes.Insert(type, color); + PainFlashes.Push(std::make_tuple(info, type, color)); } } 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) { From 17a2666bd443b44eb65c4f1eac237ce34ea8601a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 19:42:24 +0100 Subject: [PATCH 13/17] - moved DisplayName, the last remaining PlayerPawn meta property, to PClassActor so that PClassPlayerPawn could be removed. Now all actors have the same metaclass and therefore it will always be the same size which will finally allow some needed changes to the type system which couldn't be done because it was occasionally necessary to replace tentatively created classes due to size mismatches. --- src/d_net.cpp | 2 +- src/d_player.h | 22 +++++------------ src/dobject.h | 1 - src/dobjtype.cpp | 1 - src/g_game.cpp | 2 +- src/g_inventory/a_pickups.h | 1 - src/g_inventory/a_weapons.cpp | 4 +-- src/g_inventory/a_weapons.h | 4 +-- src/g_shared/a_morph.cpp | 2 +- src/g_shared/a_morph.h | 2 +- src/info.cpp | 7 +++--- src/info.h | 10 +++++--- src/m_cheat.cpp | 6 ++--- src/m_cheat.h | 4 +-- src/menu/playermenu.cpp | 2 +- src/p_acs.cpp | 2 +- src/p_user.cpp | 35 ++++++--------------------- src/r_data/sprites.cpp | 20 +++++++-------- src/scripting/thingdef_properties.cpp | 3 +-- src/serializer.h | 5 ---- 20 files changed, 49 insertions(+), 86 deletions(-) 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_player.h b/src/d_player.h index 8a5415bc6..65f401f2d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -72,21 +72,11 @@ typedef TArray> ColorSetList; extern PainFlashList PainFlashes; extern ColorSetList ColorSets; -class PClassPlayerPawn : public PClassActor -{ - DECLARE_CLASS(PClassPlayerPawn, PClassActor); -protected: -public: - PClassPlayerPawn(); - virtual void DeriveData(PClass *newclass); - - FString DisplayName; // Display name (used in menus, etc.) -}; -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: @@ -271,7 +261,7 @@ public: bool CheckSkin (int skin); - PClassPlayerPawn *Type; + PClassActor *Type; DWORD Flags; TArray Skins; }; @@ -343,7 +333,7 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_PlayerClass)); } - PClassPlayerPawn *GetPlayerClassType() const + PClassActor *GetPlayerClassType() const { return PlayerClasses[GetPlayerClassNum()].Type; } @@ -401,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 @@ -459,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 diff --git a/src/dobject.h b/src/dobject.h index 7b93a30c6..6797d2436 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -93,7 +93,6 @@ enum { CLASSREG_PClass, CLASSREG_PClassActor, - CLASSREG_PClassPlayerPawn, }; struct ClassReg diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 486c72249..76e6a3786 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2955,7 +2955,6 @@ PClass *ClassReg::RegisterClass() { &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, - &PClassPlayerPawn::RegistrationInfo, }; // Skip classes that have already been registered 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_pickups.h b/src/g_inventory/a_pickups.h index 3a67a3b6d..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; /************************************************************************/ diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index afa55cc10..839de49a8 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1058,7 +1058,7 @@ void FWeaponSlots::SetFromGameInfo() // //=========================================================================== -void FWeaponSlots::StandardSetup(PClassPlayerPawn *type) +void FWeaponSlots::StandardSetup(PClassActor *type) { SetFromPlayer(type); AddExtraWeapons(); @@ -1151,7 +1151,7 @@ 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; diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 4ea56b355..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); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 246073010..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; 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/info.cpp b/src/info.cpp index 90e2b7db9..28509a0db 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -354,6 +354,7 @@ void PClassActor::DeriveData(PClass *newclass) newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; newa->RestrictedToPlayerClass = RestrictedToPlayerClass; + newa->DisplayName = DisplayName; } //========================================================================== @@ -638,7 +639,7 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (VisibleToPlayerClass[i] == oldclass) { - VisibleToPlayerClass[i] = static_cast(newclass); + VisibleToPlayerClass[i] = static_cast(newclass); changed++; } } @@ -647,7 +648,7 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (ForbiddenToPlayerClass[i] == oldclass) { - ForbiddenToPlayerClass[i] = static_cast(newclass); + ForbiddenToPlayerClass[i] = static_cast(newclass); changed++; } } @@ -655,7 +656,7 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (RestrictedToPlayerClass[i] == oldclass) { - RestrictedToPlayerClass[i] = static_cast(newclass); + RestrictedToPlayerClass[i] = static_cast(newclass); changed++; } } diff --git a/src/info.h b/src/info.h index 28e75a121..564342d76 100644 --- a/src/info.h +++ b/src/info.h @@ -235,7 +235,6 @@ private: }; class DDropItem; -class PClassPlayerPawn; class PClassActor : public PClass { @@ -287,7 +286,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 @@ -319,8 +318,11 @@ public: // These are only valid for inventory items. FString PickupMsg; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; + 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 bf687c09d..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: @@ -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/menu/playermenu.cpp b/src/menu/playermenu.cpp index 4126bc80b..add8e5680 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -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 1423c48c4..197a0616d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -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_user.cpp b/src/p_user.cpp index 161d15121..78882b52b 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -148,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] ???? @@ -167,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; @@ -186,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; @@ -214,7 +214,7 @@ CCMD (addplayerclass) { FPlayerClass newclass; - newclass.Type = static_cast(ti); + newclass.Type = ti; newclass.Flags = 0; int arg = 2; @@ -535,27 +535,6 @@ int player_t::GetSpawnClass() return static_cast(GetDefaultByType(type))->SpawnMask; } -//=========================================================================== -// -// PClassPlayerPawn -// -//=========================================================================== - -IMPLEMENT_CLASS(PClassPlayerPawn, false, false) - -PClassPlayerPawn::PClassPlayerPawn() -{ -} - -void PClassPlayerPawn::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - Super::DeriveData(newclass); - PClassPlayerPawn *newp = static_cast(newclass); - - newp->DisplayName = DisplayName; -} - //=========================================================================== // // EnumColorsets @@ -1247,7 +1226,7 @@ const char *APlayerPawn::GetSoundClass() const } // [GRB] - PClassPlayerPawn *pclass = GetClass(); + auto pclass = GetClass(); return SoundClass != NAME_None? SoundClass.GetChars() : "player"; } @@ -1729,7 +1708,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) // [GRB] Parameterized version if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk")) { - spawntype = dyn_cast(PClass::FindClass("BloodySkull")); + spawntype = PClass::FindActor("BloodySkull"); if (spawntype == NULL) return 0; } @@ -3276,7 +3255,7 @@ DEFINE_FIELD(APlayerPawn, HexenArmor) DEFINE_FIELD(APlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd) -DEFINE_FIELD(PClassPlayerPawn, DisplayName) +DEFINE_FIELD(PClassActor, DisplayName) DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index be44e9d82..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 @@ -734,7 +734,7 @@ void R_InitSkins (void) 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) && diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 33d97dccf..33f455e3d 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2277,8 +2277,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; } //========================================================================== 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) { From 9499c22dfe191294bdb65ef87b117941ee2a8970 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 19:52:33 +0100 Subject: [PATCH 14/17] - restored ZDoom 2.8.1's version of FindClassTentative which just modified the existing class instead of replacing it and having to run a costly and volatile PointerSubstitution call to replace all pointers to the old one. --- src/dobjtype.cpp | 56 ++++++++++---------------------------- src/scripting/thingdef.cpp | 5 ++-- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 76e6a3786..72bf033b0 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2029,7 +2029,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); @@ -3238,48 +3238,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) @@ -3288,22 +3271,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; } diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 51fb0239c..a43c741ce 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -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 { From 8277299135163d3a8eab2b2f937a6c58f93bdac5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 20:37:22 +0100 Subject: [PATCH 15/17] - Turned DropItem into a plain struct again like it was before the scripting branch got merged. Making this an object had little to no advantage, except being able to remove the deleter code. Now, with some of the class data already being allocated in a memory arena so that freeing it is easier, this can also be used for the drop item lists which makes it unnecessary to subject them to the GC. This also merges the memory arenas for VM functions and flat pointers because both get deleted at the same time so they can share the same one. --- src/actor.h | 9 +++------ src/d_dehacked.cpp | 2 +- src/dobjtype.cpp | 9 ++++----- src/g_shared/a_action.cpp | 2 +- src/info.cpp | 9 ++------- src/info.h | 7 +++---- src/p_mobj.cpp | 16 +++++----------- src/p_user.cpp | 4 ++-- src/scripting/thingdef.h | 4 ++-- src/scripting/thingdef_properties.cpp | 6 ++---- src/scripting/vm/vm.h | 5 +++-- src/scripting/vm/vmframe.cpp | 3 +-- wadsrc/static/zscript/base.txt | 2 +- 13 files changed, 30 insertions(+), 48 deletions(-) diff --git a/src/actor.h b/src/actor.h index 0b33ed3e3..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); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 8062faf5a..36c32bf5b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 72bf033b0..68d30dc31 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -64,8 +64,7 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. +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; @@ -2858,7 +2857,7 @@ void PClass::StaticShutdown () // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. TypeTable.Clear(); Namespaces.ReleaseSymbols(); - FlatpointerArena.FreeAllBlocks(); + ClassDataAllocator.FreeAllBlocks(); bShutdown = true; for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i) @@ -3448,7 +3447,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); @@ -3514,7 +3513,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); 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/info.cpp b/src/info.cpp index 28509a0db..58c7241ad 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -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) //========================================================================== // @@ -394,10 +390,9 @@ bool PClassActor::SetReplacement(FName replaceName) // //========================================================================== -void PClassActor::SetDropItems(DDropItem *drops) +void PClassActor::SetDropItems(FDropItem *drops) { DropItems = drops; - GC::WriteBarrier(this, DropItems); } diff --git a/src/info.h b/src/info.h index 564342d76..05785f90b 100644 --- a/src/info.h +++ b/src/info.h @@ -234,12 +234,11 @@ private: static DamageTypeDefinition *Get(FName type); }; -class DDropItem; +struct FDropItem; class PClassActor : public PClass { DECLARE_CLASS(PClassActor, PClass); - HAS_OBJECT_POINTERS; protected: public: static void StaticInit (); @@ -256,7 +255,7 @@ public: void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); 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); @@ -303,7 +302,7 @@ public: FName BloodType2; // Bloopsplatter replacement type FName BloodType3; // AxeBlood replacement type - DDropItem *DropItems; + FDropItem *DropItems; FString SourceLumpName; FIntCVar *distancecheck; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 846a25ca5..2650224be 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7492,7 +7492,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) } -DDropItem *AActor::GetDropItems() const +FDropItem *AActor::GetDropItems() const { return GetClass()->DropItems; } @@ -8100,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_user.cpp b/src/p_user.cpp index 78882b52b..b0d1d127f 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1384,7 +1384,7 @@ void APlayerPawn::GiveDefaultInventory () AddInventory (barmor); // Now add the items from the DECORATE definition - DDropItem *di = GetDropItems(); + auto di = GetDropItems(); while (di) { @@ -1514,7 +1514,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) { diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 37c247cbe..e98aeed88 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; +class 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 33f455e3d..50b81310c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -921,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; @@ -939,7 +939,6 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== @@ -2685,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; @@ -2697,7 +2696,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 6d758f1bc..36619ef5b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -8,6 +8,8 @@ #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 @@ -716,7 +718,7 @@ public: void *operator new(size_t size) { - return Allocator.Alloc(size); + return ClassDataAllocator.Alloc(size); } void operator delete(void *block) {} @@ -729,7 +731,6 @@ public: } AllFunctions.Clear(); } - static FMemArena Allocator; static TArray AllFunctions; protected: }; diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 5fa82ad0c..d5eaed5bd 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -43,7 +43,6 @@ int VMCalls[10]; IMPLEMENT_CLASS(VMException, false, false) -FMemArena VMFunction::Allocator(32768); TArray VMFunction::AllFunctions; @@ -95,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 = Allocator.Alloc(numops * sizeof(VMOP) + + void *mem = ClassDataAllocator.Alloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + 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; From 36a07b8e6ead5c52f614da44ad82b36485d2518c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 22:43:20 +0100 Subject: [PATCH 16/17] - remove all type table entries from garbage collection. Like the symbols and the VM functions this is data that is static from startup until shutdown and has no need to be subjected to garbage collection. All things combined this reduces the amount of GC-sensitive objects at startup from 9600 to 600. --- src/dobjgc.cpp | 19 +++-- src/dobjtype.cpp | 125 +++++------------------------- src/dobjtype.h | 12 --- src/g_inventory/a_weapons.cpp | 3 - src/scripting/backend/codegen.cpp | 2 +- src/scripting/thingdef.h | 2 +- 6 files changed, 34 insertions(+), 129 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index e6ff9c734..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++; @@ -363,12 +371,6 @@ static void MarkRoot() } Mark(SectorMarker); Mark(interpolator.Head); - // 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. @@ -449,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; } @@ -550,6 +552,7 @@ 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); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 68d30dc31..34709cddc 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -151,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) //========================================================================== // @@ -444,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) //========================================================================== // @@ -1303,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) //========================================================================== // @@ -1510,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) //========================================================================== // @@ -1595,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) //========================================================================== // @@ -1651,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) //========================================================================== // @@ -1888,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) //========================================================================== // @@ -2143,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) //========================================================================== // @@ -2645,11 +2612,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray /* PClass *****************************************************************/ -IMPLEMENT_CLASS(PClass, false, true) - -IMPLEMENT_POINTERS_START(PClass) - IMPLEMENT_POINTER(ParentClass) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClass, false, false) //========================================================================== // @@ -2855,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(); ClassDataAllocator.FreeAllBlocks(); - bShutdown = true; - - for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i) - { - PClass *type = PClass::AllClasses[i]; - PClass::AllClasses[i] = NULL; - type->Destroy(); - } - AllClasses.Clear(); PClassActor::AllActorClasses.Clear(); @@ -3591,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 @@ -3632,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(); } //========================================================================== @@ -3655,7 +3585,7 @@ void FTypeTable::AddType(PType *type) type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; - GC::WriteBarrier(type); + type->Release(); } //========================================================================== @@ -3694,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)); } diff --git a/src/dobjtype.h b/src/dobjtype.h index 42280a12b..cc0a17da8 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -77,7 +77,6 @@ struct ZCC_ExprConstant; class PType : public PTypeBase { DECLARE_ABSTRACT_CLASS(PType, PTypeBase) - HAS_OBJECT_POINTERS; protected: public: @@ -208,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 @@ -364,7 +362,6 @@ public: class PPointer : public PBasicType { DECLARE_CLASS(PPointer, PBasicType); - HAS_OBJECT_POINTERS; public: PPointer(); PPointer(PType *pointsat, bool isconst = false); @@ -397,7 +394,6 @@ public: class PClassPointer : public PPointer { DECLARE_CLASS(PClassPointer, PPointer); - HAS_OBJECT_POINTERS; public: PClassPointer(class PClass *restrict = nullptr); @@ -414,7 +410,6 @@ public: class PEnum : public PInt { DECLARE_CLASS(PEnum, PInt); - HAS_OBJECT_POINTERS; public: PEnum(FName name, PTypeBase *outer); @@ -427,7 +422,6 @@ protected: class PArray : public PCompoundType { DECLARE_CLASS(PArray, PCompoundType); - HAS_OBJECT_POINTERS; public: PArray(PType *etype, unsigned int ecount); @@ -451,7 +445,6 @@ protected: class PResizableArray : public PArray { DECLARE_CLASS(PResizableArray, PArray); - HAS_OBJECT_POINTERS; public: PResizableArray(PType *etype); @@ -465,7 +458,6 @@ protected: class PDynArray : public PCompoundType { DECLARE_CLASS(PDynArray, PCompoundType); - HAS_OBJECT_POINTERS; public: PDynArray(PType *etype, PStruct *backing); @@ -489,7 +481,6 @@ protected: class PMap : public PCompoundType { DECLARE_CLASS(PMap, PCompoundType); - HAS_OBJECT_POINTERS; public: PMap(PType *keytype, PType *valtype); @@ -565,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; @@ -672,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); diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 839de49a8..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) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 910dba19f..c05ab6d64 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6717,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/thingdef.h b/src/scripting/thingdef.h index e98aeed88..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 FDropItem; +struct FDropItem; struct Baggage { From 4e685f2b78668a1563ef3808e930f35a7c02116c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 23:29:52 +0100 Subject: [PATCH 17/17] - fixed: for unpositioned sounds the play position was never initialized and depended on random memory contents. --- src/p_user.cpp | 1 - src/s_sound.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index b0d1d127f..0860796ef 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -657,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) 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: