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 df1760dd70..5b6a34bdc1 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 54cc646756..6dc4483a00 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 c86486b5e0..18eecc2d18 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 3a20994f54..64be2d92f3 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 8ea8b5806b..af9f915471 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 3601469bf8..14b735eda5 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 8b8e3c8643..6d758f1bc4 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 c44fbb2ea6..5fa82ad0c2 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 05e18a3caf..0152c65205 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 200164d7bd..ce60111fa5 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 7fecec550f..7ad5e63443 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 573c190716..e91c2ccaa3 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 5b6a34bdc1..ca57e6aca0 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 6dc4483a00..c39e316a78 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 3858585e92..6fd2f9b1d9 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 19fe81c32b..74f845248c 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 5861138d66..575bbf0a44 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 2b0866dd87..6757a23823 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 fc411186a6..23ffc48e85 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 8e08fc0380..63269eeeb5 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 6776e70e87..f2849eb39b 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 859ccb3f5e..22d6610ce8 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 93f41746f2..4972e1344b 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 a14443b7da..dc5fea565c 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 ce60111fa5..d0d31984d9 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 ef75609095..6ad8ded6fd 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 c39e316a78..eda59bcc1f 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 6fd2f9b1d9..c999f3f50a 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 0000000000..ba0704433e --- /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 0000000000..52d7ac60aa --- /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 6ad8ded6fd..7c2fd4c224 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 eda59bcc1f..3c556da3bc 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 c999f3f50a..cfae5e1694 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 ba0704433e..68b9d522c9 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 52d7ac60aa..af5bfb80e9 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 63c7bb688d..68f3aab8ec 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 7c2fd4c224..82051e3bd7 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 ca57e6aca0..e6ff9c734f 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 3c556da3bc..f0e7b2fc1c 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 cfae5e1694..6c07b047bc 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 a3dc066e98..910dba19f3 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 c64ec20941..abbcbd54e3 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 68b9d522c9..b6adb33e76 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 af5bfb80e9..3c9d1f8f32 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 be92fd37ab..57eccc19d2 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 54d154a3e0..637494333c 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 7ce276aa00..da3fb61246 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 7428fceea2..e8f9509e56 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 7ad5e63443..c30fc64aec 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 82051e3bd7..f3c2904430 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 6c07b047bc..42280a12b5 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 0ee391e215..e8cde02224 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 0ad6b72f13..75d98c2c7d 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 a916531be6..8882590985 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 0c95c77b8e..cd72bca796 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 4ab0c81338..79c51350b7 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 c3950571f1..6e6b55bec6 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 7a548eaa24..5ce79fd09a 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 18eecc2d18..48a22c2d42 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 23c2f1ded7..bf687c09df 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 bddcd7f95d..8b0075475f 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 c732ea18ca..ea271967be 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 a77a7358d5..e9ad0ff0d5 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 bd5a9cb17e..2fb040a933 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 758b4ac18a..d39786311e 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 c443ca7da1..bf6c79a82e 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 c6b0a7d583..1b9cedf4a5 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 43b7ef7b6d..f354faa65d 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 f2849eb39b..51fb0239c0 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 22d6610ce8..8cffbc347b 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 c696f7fd6a..c58fb111a3 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 7bda52e528..c1fbf43846 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 e09db38a3c..b79e568626 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 8882590985..afa55cc10c 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 cd72bca796..2460730109 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 d88ad40f2f..d24298b949 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 57c8ecf262..821c2ea70d 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 1b9cedf4a5..ab1920ae8c 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 7fb59ef949..be44e9d82f 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 8cffbc347b..ef9a905a34 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 0a7798ace9..dc1d1ba1d4 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 66f51e92ef..796036c2da 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 be6280c0a7..f467ae9843 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 79c51350b7..d39c16d88e 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 ef9a905a34..d1273da181 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 da915f1704..28b20cdd5d 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 4016d447b4..0b33ed3e36 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 c30fc64aec..8062faf5ab 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 b79e568626..f6009edec9 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 f3c2904430..7b93a30c6e 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 f0e7b2fc1c..486c72249a 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 248aee33b0..11e4f96e2c 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 e8cde02224..68d9407046 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 796036c2da..53e7d84ed7 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 f467ae9843..3a67a3b6d9 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 50862bc470..4ea56b355b 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 48a22c2d42..90e2b7db92 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 64be2d92f3..28e75a1215 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 8b0075475f..1423c48c4a 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 e9ad0ff0d5..54be79e3ca 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 bd674aa101..8771d95aef 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 d39786311e..846a25ca5c 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 d40c542a14..f4ebe5ebd3 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 ab1920ae8c..98221de1fb 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 575bbf0a44..50e8f9c6a8 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 d1273da181..7f363b623c 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 ea271967be..518d2fb631 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 9b6f42b88a..ceda20bd85 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 e91c2ccaa3..e0cbcbefaf 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 d3ce8c9437..62beb54601 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 f6009edec9..8a5415bc6c 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 11e4f96e2c..c88ec842d9 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 2c3676f5ac..e5653796ba 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 821c2ea70d..ba99aba364 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 7116608b34..4126bc80b7 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 98221de1fb..161d151215 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 7f363b623c..33d97dccf3 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 ffc16cd5ce..41e6fe7ff0 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 c38a7cefeb..97f6be9bb2 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 8a5415bc6c..65f401f2d6 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 7b93a30c6e..6797d24365 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 486c72249a..76e6a3786c 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 e5c3274727..9417f40b9f 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 3a67a3b6d9..817fcf1769 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 afa55cc10c..839de49a84 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 4ea56b355b..606c96e98e 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 2460730109..359e8a1742 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 e770e418e3..1c0047c69d 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 90e2b7db92..28509a0db8 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 28e75a1215..564342d760 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 bf687c09df..15dd90a076 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 11f89c4d78..baab5a4513 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 4126bc80b7..add8e5680b 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 1423c48c4a..197a0616da 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 161d151215..78882b52bb 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 be44e9d82f..c3f73760db 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 33d97dccf3..33f455e3d3 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 e4dc8f2263..4f0d90cecd 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 76e6a3786c..72bf033b0a 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 51fb0239c0..a43c741ce9 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 0b33ed3e36..13511b617d 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 8062faf5ab..36c32bf5bb 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 72bf033b0a..68d30dc31e 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 aed8457f8c..2d1a95cdd1 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 28509a0db8..58c7241ade 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 564342d760..05785f90b6 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 846a25ca5c..2650224be4 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 78882b52bb..b0d1d127f2 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 37c247cbec..e98aeed886 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 33f455e3d3..50b81310ca 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 6d758f1bc4..36619ef5b9 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 5fa82ad0c2..d5eaed5bd8 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 83d7146844..1ff8a5e922 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 e6ff9c734f..8e93339344 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 68d30dc31e..34709cddc1 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 42280a12b5..cc0a17da8d 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 839de49a84..af180a4eab 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 910dba19f3..c05ab6d644 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 e98aeed886..5558ffe3fc 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 b0d1d127f2..0860796ef5 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 8561563227..bae1fbaf6f 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: