From b570d0819b9a46e350efd12a38a93ac37dd122b8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 13:14:22 +0100 Subject: [PATCH 01/50] - streamlined font handling for scripts a bit. - moved the two 'you raised the alarm' messages for Strife to the string table --- src/c_console.cpp | 3 +- src/d_main.cpp | 3 + src/dobjtype.cpp | 2 + src/dobjtype.h | 1 + src/r_utility.cpp | 2 - src/scripting/codegeneration/codegen.cpp | 78 ++++++++++++++++++++ src/scripting/codegeneration/codegen.h | 20 +++++ src/serializer.cpp | 8 +- src/v_font.cpp | 40 +++++----- src/v_font.h | 6 +- wadsrc/static/language.enu | 3 + wadsrc/static/zscript/base.txt | 5 +- wadsrc/static/zscript/compatibility.txt | 4 +- wadsrc/static/zscript/strife/strifeitems.txt | 4 +- 14 files changed, 144 insertions(+), 35 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 4340cc3f8..493625bf9 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1752,11 +1752,10 @@ void C_MidPrintBold (FFont *font, const char *msg) DEFINE_ACTION_FUNCTION(_Console, MidPrint) { PARAM_PROLOGUE; - PARAM_STRING(font); + PARAM_POINTER_NOT_NULL(fnt, FFont); PARAM_STRING(text); PARAM_BOOL_DEF(bold); - FFont *fnt = FFont::FindFont(font); const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars(); if (!bold) C_MidPrint(fnt, txt); else C_MidPrintBold(fnt, txt); diff --git a/src/d_main.cpp b/src/d_main.cpp index 9a966e6d5..573c19071 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2467,6 +2467,9 @@ void D_DoomMain (void) TexMan.Init(); C_InitConback(); + StartScreen->Progress(); + V_InitFonts(); + // [CW] Parse any TEAMINFO lumps. if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n"); TeamLibrary.ParseTeamInfo (); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7468b6dab..e4d9fc177 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -88,6 +88,7 @@ PColor *TypeColor; PTextureID *TypeTextureID; PSpriteID *TypeSpriteID; PStatePointer *TypeState; +PPointer *TypeFont; PStateLabel *TypeStateLabel; PStruct *TypeVector2; PStruct *TypeVector3; @@ -437,6 +438,7 @@ void PType::StaticInit() TypeVoidPtr = NewPointer(TypeVoid, false); TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. TypeStringStruct = NewNativeStruct("Stringstruct", nullptr); + TypeFont = NewPointer(NewNativeStruct("Font", nullptr)); #ifdef __BIG_ENDIAN__ TypeColorStruct->AddField(NAME_a, TypeUInt8); TypeColorStruct->AddField(NAME_r, TypeUInt8); diff --git a/src/dobjtype.h b/src/dobjtype.h index 2726ebff1..8cbe79966 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -940,6 +940,7 @@ extern PStruct *TypeVector3; extern PStruct *TypeColorStruct; extern PStruct *TypeStringStruct; extern PStatePointer *TypeState; +extern PPointer *TypeFont; extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; extern PPointer *TypeVoidPtr; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index d2358d8b3..a7a3860bb 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -337,8 +337,6 @@ void R_Init () { atterm (R_Shutdown); - StartScreen->Progress(); - V_InitFonts(); StartScreen->Progress(); // Colormap init moved back to InitPalette() //R_InitColormaps (); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index a23811390..a3641269f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1420,6 +1420,76 @@ ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build) return to; } +//========================================================================== +// +// +// +//========================================================================== + +FxFontCast::FxFontCast(FxExpression *x) + : FxExpression(EFX_FontCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeSound; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFontCast::~FxFontCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxFontCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeFont) + { + FxExpression *x = basex; + basex = nullptr; + delete this; + return x; + } + // This intentionally does not convert non-constants. + // The sole reason for this cast is to allow passing both font pointers and string constants to printing functions and have the font names checked at compile time. + else if ((basex->ValueType == TypeString || basex->ValueType == TypeName) && basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FFont *font = V_GetFont(constval.GetString()); + // Font must exist. Most internal functions working with fonts do not like null pointers. + // If checking is needed scripts will have to call Font.GetFont themselves. + if (font == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unknown font '%s'", constval.GetString().GetChars()); + delete this; + return nullptr; + } + + FxExpression *x = new FxConstant(font, ScriptPosition); + delete this; + return x; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to font"); + delete this; + return nullptr; + } +} + + //========================================================================== // // generic type cast operator @@ -1649,6 +1719,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) { goto basereturn; } + else if (ValueType == TypeFont) + { + FxExpression *x = new FxFontCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } // todo: pointers to class objects. // All other types are only compatible to themselves and have already been handled above by the equality check. // Anything that falls through here is not compatible and must print an error. diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 69ad192f5..6438e0868 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -294,6 +294,7 @@ enum EFxType EFX_StrLen, EFX_ColorLiteral, EFX_GetDefaultByType, + EFX_FontCast, EFX_COUNT }; @@ -488,6 +489,13 @@ public: isresolved = true; } + FxConstant(FFont *state, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) + { + value.pointer = state; + ValueType = value.Type = TypeFont; + isresolved = true; + } + FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value.pointer = nullptr; @@ -664,6 +672,18 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +class FxFontCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxFontCast(FxExpression *x); + ~FxFontCast(); + FxExpression *Resolve(FCompileContext&); +}; + + //========================================================================== // // FxTypeCast diff --git a/src/serializer.cpp b/src/serializer.cpp index 6d7a6ef7c..dcb7acab6 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -2187,13 +2187,13 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon { if (arc.isWriting()) { - const char *n = font->GetName(); - return arc.StringPtr(key, n); + FName n = font->GetName(); + return arc(key, n); } else { - const char *n; - arc.StringPtr(key, n); + FName n; + arc(key, n); font = V_GetFont(n); if (font == nullptr) { diff --git a/src/v_font.cpp b/src/v_font.cpp index 2854be8c2..6a4f60826 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -340,6 +340,14 @@ FFont *V_GetFont(const char *name) return font; } +DEFINE_ACTION_FUNCTION(FFont, GetFont) +{ + PARAM_PROLOGUE; + PARAM_NAME(name); + ACTION_RETURN_POINTER(V_GetFont(name.GetChars())); +} + + //========================================================================== // // FFont :: FFont @@ -366,7 +374,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, LastChar = first + count - 1; FontHeight = 0; GlobalKerning = false; - Name = copystring (name); + FontName = name; Next = FirstFont; FirstFont = this; Cursor = '_'; @@ -478,11 +486,6 @@ FFont::~FFont () delete[] PatchRemap; PatchRemap = NULL; } - if (Name) - { - delete[] Name; - Name = NULL; - } FFont **prev = &FirstFont; FFont *font = *prev; @@ -508,27 +511,26 @@ FFont::~FFont () // //========================================================================== -FFont *FFont::FindFont (const char *name) +FFont *FFont::FindFont (FName name) { - if (name == NULL) + if (name == NAME_None) { - return NULL; + return nullptr; } FFont *font = FirstFont; - while (font != NULL) + while (font != nullptr) { - if (stricmp (font->Name, name) == 0) - break; + if (font->FontName == name) return font; font = font->Next; } - return font; + return nullptr; } DEFINE_ACTION_FUNCTION(FFont, FindFont) { PARAM_PROLOGUE; - PARAM_STRING(name); + PARAM_NAME(name); ACTION_RETURN_POINTER(FFont::FindFont(name)); } @@ -935,7 +937,7 @@ FFont::FFont (int lump) Lump = lump; Chars = NULL; PatchRemap = NULL; - Name = NULL; + FontName = NAME_None; Cursor = '_'; } @@ -951,7 +953,7 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump) { assert(lump >= 0); - Name = copystring (name); + FontName = name; FMemLump data1 = Wads.ReadLump (lump); const BYTE *data = (const BYTE *)data1.GetMem(); @@ -1189,7 +1191,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) if (destSize < 0) { i += FirstChar; - I_FatalError ("Overflow decompressing char %d (%c) of %s", i, i, Name); + I_FatalError ("Overflow decompressing char %d (%c) of %s", i, i, FontName.GetChars()); } } @@ -1491,7 +1493,7 @@ FSinglePicFont::FSinglePicFont(const char *picname) : FTexture *pic = TexMan[picnum]; - Name = copystring(picname); + FontName = picname; FontHeight = pic->GetScaledHeight(); SpaceWidth = pic->GetScaledWidth(); GlobalKerning = 0; @@ -1903,7 +1905,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l memcpy(this->notranslate, notranslate, 256*sizeof(bool)); - Name = copystring(name); + FontName = name; Chars = new CharData[count]; charlumps = new FTexture*[count]; PatchRemap = new BYTE[256]; diff --git a/src/v_font.h b/src/v_font.h index b31c51471..124f29a4e 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -88,9 +88,9 @@ public: int GetDefaultKerning () const { return GlobalKerning; } virtual void LoadTranslations(); void Preload() const; - const char *GetName() const { return Name; } + FName GetName() const { return FontName; } - static FFont *FindFont (const char *fontname); + static FFont *FindFont(FName fontname); static void StaticPreloadFonts(); // Return width of string in pixels (unscaled) @@ -127,7 +127,7 @@ protected: BYTE *PatchRemap; int Lump; - char *Name; + FName FontName; FFont *Next; static FFont *FirstFont; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index bdc1ce3ae..4d567d3ca 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1417,6 +1417,9 @@ TXT_KILLED_ORACLE = "You've Killed The Oracle!"; TXT_KILLED_MACIL = "You Killed Macil!"; TXT_KILLED_LOREMASTER = "You've Killed the Loremaster!"; +TXT_YOUFOOL = "You Fool! You've set off the alarm."; +TXT_YOUREDEAD = "You're dead! You set off the alarm."; + // Strife pickup messages TXT_METALARMOR = "You picked up the Metal Armor."; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b84d72a51..f1df373c3 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -70,13 +70,14 @@ struct Screen native struct Font native { - native static Font FindFont(String name); + native static Font FindFont(Name fontname); + native static Font GetFont(Name fontname); } struct Console native { native static void HideConsole(); - native static void MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable. + native static void MidPrint(Font fontname, string textlabel, bool bold = false); } struct DamageTypeDefinition native diff --git a/wadsrc/static/zscript/compatibility.txt b/wadsrc/static/zscript/compatibility.txt index 752de8016..1ae88ab85 100644 --- a/wadsrc/static/zscript/compatibility.txt +++ b/wadsrc/static/zscript/compatibility.txt @@ -9,7 +9,9 @@ extend class Object deprecated static void C_MidPrint(string fontname, string textlabel, bool bold = false) // deprecated for 2.4.x { - return Console.MidPrint(fontname, textlabel, bold); + let f = Font.GetFont(fontname); + if (f == null) return; + return Console.MidPrint(f, textlabel, bold); } } diff --git a/wadsrc/static/zscript/strife/strifeitems.txt b/wadsrc/static/zscript/strife/strifeitems.txt index 970478cae..4c7311b56 100644 --- a/wadsrc/static/zscript/strife/strifeitems.txt +++ b/wadsrc/static/zscript/strife/strifeitems.txt @@ -632,7 +632,7 @@ class RaiseAlarm : DummyStrifeItem dropper.target.SoundAlert(dropper.target); if (dropper.target.CheckLocalView(consoleplayer)) { - A_Log("You Fool! You've set off the alarm."); + Console.MidPrint(SmallFont, "$TXT_YOUFOOL"); } } Destroy (); @@ -672,7 +672,7 @@ class CloseDoor222 : DummyStrifeItem { if (dropper.target.CheckLocalView(consoleplayer)) { - A_Log("You're dead! You set off the alarm."); + Console.MidPrint(SmallFont, "$TXT_YOUREDEAD"); } dropper.target.SoundAlert(dropper.target); } From ef871ec09faf26d87ffdd7981caa9970d31ba654 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 5 Feb 2017 14:52:17 +0200 Subject: [PATCH 02/50] Fixed compilation with GCC/Clang error: cannot pass non-trivial object of type 'FName' to variadic function; expected type from format string was 'char *' [-Wnon-pod-varargs] --- src/serializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serializer.cpp b/src/serializer.cpp index dcb7acab6..a577056af 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -2197,7 +2197,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon font = V_GetFont(n); if (font == nullptr) { - Printf(TEXTCOLOR_ORANGE "Could not load font %s\n", n); + Printf(TEXTCOLOR_ORANGE "Could not load font %s\n", n.GetChars()); font = SmallFont; } return arc; From d8a1ce88b01eb43b815cae0a43fc0c800d814782 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 13:55:05 +0100 Subject: [PATCH 03/50] - a few more exports from FFont. --- src/v_font.cpp | 76 ++++++++++++++++++++++++++++++---- src/v_font.h | 2 - src/v_text.cpp | 42 ------------------- wadsrc/static/zscript/base.txt | 3 ++ 4 files changed, 70 insertions(+), 53 deletions(-) diff --git a/src/v_font.cpp b/src/v_font.cpp index 6a4f60826..00d3b10f7 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -94,6 +94,7 @@ The FON2 header is followed by variable length data: #include "r_data/r_translate.h" #include "colormatcher.h" #include "v_palette.h" +#include "v_text.h" // MACROS ------------------------------------------------------------------ @@ -845,6 +846,65 @@ int FFont::GetCharWidth (int code) const return (code < 0) ? SpaceWidth : Chars[code - FirstChar].XMove; } +DEFINE_ACTION_FUNCTION(FFont, GetCharWidth) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_INT(code); + ACTION_RETURN_INT(self->GetCharWidth(code)); +} + +//========================================================================== +// +// Find string width using this font +// +//========================================================================== + +int FFont::StringWidth(const BYTE *string) const +{ + int w = 0; + int maxw = 0; + + while (*string) + { + if (*string == TEXTCOLOR_ESCAPE) + { + ++string; + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (*string == '\n') + { + if (w > maxw) + maxw = w; + w = 0; + ++string; + } + else + { + w += GetCharWidth(*string++) + GlobalKerning; + } + } + + return MAX(maxw, w); +} + +DEFINE_ACTION_FUNCTION(FFont, StringWidth) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(str); + ACTION_RETURN_INT(self->StringWidth(str)); +} + //========================================================================== // // FFont :: LoadTranslations @@ -2492,6 +2552,13 @@ EColorRange V_FindFontColor (FName name) return CR_UNTRANSLATED; } +DEFINE_ACTION_FUNCTION(FFont, FindFontColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_NAME(code); + ACTION_RETURN_INT((int)V_FindFontColor(code)); +} + //========================================================================== // // V_LogColorFromColorRange @@ -2666,12 +2733,3 @@ void V_ClearFonts() SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL; } -void V_RetranslateFonts() -{ - FFont *font = FFont::FirstFont; - while(font) - { - font->LoadTranslations(); - font = font->Next; - } -} diff --git a/src/v_font.h b/src/v_font.h index 124f29a4e..4c78b3007 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -134,7 +134,6 @@ protected: friend struct FontsDeleter; friend void V_ClearFonts(); - friend void V_RetranslateFonts(); }; @@ -147,6 +146,5 @@ PalEntry V_LogColorFromColorRange (EColorRange range); EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int boldcolor); FFont *V_GetFont(const char *); void V_InitFontColors(); -void V_RetranslateFonts(); #endif //__V_FONT_H__ diff --git a/src/v_text.cpp b/src/v_text.cpp index 3fcac5541..47fbf6f1b 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -167,48 +167,6 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s } -// -// Find string width using this font -// -int FFont::StringWidth (const BYTE *string) const -{ - int w = 0; - int maxw = 0; - - while (*string) - { - if (*string == TEXTCOLOR_ESCAPE) - { - ++string; - if (*string == '[') - { - while (*string != '\0' && *string != ']') - { - ++string; - } - } - if (*string != '\0') - { - ++string; - } - continue; - } - else if (*string == '\n') - { - if (w > maxw) - maxw = w; - w = 0; - ++string; - } - else - { - w += GetCharWidth (*string++) + GlobalKerning; - } - } - - return MAX (maxw, w); -} - // // Break long lines of text into multiple lines no longer than maxwidth pixels // diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index f1df373c3..cb5239a37 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -70,6 +70,9 @@ struct Screen native struct Font native { + native int GetCharWidth(int code); + native int StringWidth(String code); + native static int FindFontColor(Name color); native static Font FindFont(Name fontname); native static Font GetFont(Name fontname); } From 52bec33c0d30cef75b7a990bce6f6ef4198e2591 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 16:18:41 +0100 Subject: [PATCH 04/50] - exported BrokenLines to scripting as a new class. - removed the hard limit of 128 lines for V_BreakLines. --- src/v_text.cpp | 92 +++++++++++++++++++++++++++++----- src/v_text.h | 10 ++-- wadsrc/static/zscript/base.txt | 8 +++ 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/src/v_text.cpp b/src/v_text.cpp index 47fbf6f1b..324e22bc0 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -47,11 +47,14 @@ #include "doomstat.h" #include "templates.h" +//========================================================================== // // DrawChar // // Write a single character using the given font // +//========================================================================== + void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...) { if (font == NULL) @@ -79,11 +82,14 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch } } +//========================================================================== // // DrawText // // Write a string using the given font // +//========================================================================== + void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...) { int w; @@ -167,9 +173,12 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s } +//========================================================================== // // Break long lines of text into multiple lines no longer than maxwidth pixels // +//========================================================================== + static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const BYTE *stop, FString &linecolor) { if (!linecolor.IsEmpty()) @@ -181,20 +190,19 @@ static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const B line->Width = font->StringWidth (line->Text); } -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor) +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor, unsigned int *count) { - FBrokenLines lines[128]; // Support up to 128 lines (should be plenty) + TArray Lines(128); const BYTE *space = NULL, *start = string; - size_t i, ii; int c, w, nw; FString lastcolor, linecolor; bool lastWasSpace = false; int kerning = font->GetDefaultKerning (); - i = w = 0; + w = 0; - while ( (c = *string++) && i < countof(lines) ) + while ( (c = *string++) ) { if (c == TEXTCOLOR_ESCAPE) { @@ -241,14 +249,14 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool if (!space) space = string - 1; - breakit (&lines[i], font, start, space, linecolor); + auto index = Lines.Reserve(1); + breakit (&Lines[index], font, start, space, linecolor); if (c == '\n' && !preservecolor) { lastcolor = ""; // Why, oh why, did I do it like this? } linecolor = lastcolor; - i++; w = 0; lastWasSpace = false; start = space; @@ -270,7 +278,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool } // String here is pointing one character after the '\0' - if (i < countof(lines) && --string - start >= 1) + if (--string - start >= 1) { const BYTE *s = start; @@ -279,20 +287,25 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool // If there is any non-white space in the remainder of the string, add it. if (!isspace (*s++)) { - breakit (&lines[i++], font, start, string, linecolor); + auto i = Lines.Reserve(1); + breakit (&Lines[i], font, start, string, linecolor); break; } } } // Make a copy of the broken lines and return them - FBrokenLines *broken = new FBrokenLines[i+1]; + FBrokenLines *broken = new FBrokenLines[Lines.Size() + 1]; - for (ii = 0; ii < i; ++ii) + for (unsigned ii = 0; ii < Lines.Size(); ++ii) { - broken[ii] = lines[ii]; + broken[ii] = Lines[ii]; + } + broken[Lines.Size()].Width = -1; + if (count != nullptr) + { + *count = Lines.Size(); } - broken[ii].Width = -1; return broken; } @@ -304,3 +317,56 @@ void V_FreeBrokenLines (FBrokenLines *lines) delete[] lines; } } + +class DBrokenLines : public DObject +{ + DECLARE_ABSTRACT_CLASS(DBrokenLines, DObject) + +public: + FBrokenLines *mBroken; + unsigned int mCount; + + DBrokenLines(FBrokenLines *broken, unsigned int count) + { + mBroken = broken; + mCount = count; + } + + void OnDestroy() override + { + V_FreeBrokenLines(mBroken); + } +}; + +IMPLEMENT_CLASS(DBrokenLines, true, false); + +DEFINE_ACTION_FUNCTION(DBrokenLines, Count) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + ACTION_RETURN_INT(self->mCount); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringWidth) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_INT((unsigned)index >= self->mCount? -1 : self->mBroken[index].Width); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringAt) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_STRING((unsigned)index >= self->mCount? -1 : self->mBroken[index].Text); +} + +DEFINE_ACTION_FUNCTION(FFont, BreakLines) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(text); + PARAM_INT(maxwidth); + + unsigned int count; + FBrokenLines *broken = V_BreakLines(self, maxwidth, text, true, &count); + ACTION_RETURN_OBJECT(new DBrokenLines(broken, count)); +} diff --git a/src/v_text.h b/src/v_text.h index 3baf62af7..bd24be405 100644 --- a/src/v_text.h +++ b/src/v_text.h @@ -75,11 +75,11 @@ struct FBrokenLines #define TEXTCOLOR_CHAT "\034*" #define TEXTCOLOR_TEAMCHAT "\034!" -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false); +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false, unsigned int *count = nullptr); void V_FreeBrokenLines (FBrokenLines *lines); -inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor); } -inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor); } +inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false, unsigned int *count = nullptr) + { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor, count); } +inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false, unsigned int *count = nullptr) + { return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor, count); } #endif //__V_TEXT_H__ diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index cb5239a37..57ec1b6df 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -68,6 +68,13 @@ struct Screen native native static void DrawHUDTexture(TextureID tex, double x, double y); } +class BrokenLines : Object native +{ + native int Count(); + native int StringWidth(int line); + native String StringAt(int line); +} + struct Font native { native int GetCharWidth(int code); @@ -75,6 +82,7 @@ struct Font native native static int FindFontColor(Name color); native static Font FindFont(Name fontname); native static Font GetFont(Name fontname); + native static BrokenLines BreakLines(String text, int maxlen); } struct Console native From 9e038b75fa9d0532c8232cdfc06b58d198ec31cb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 16:47:33 +0100 Subject: [PATCH 05/50] - exported DrawChar and DrawText. --- src/v_draw.cpp | 4 +- src/v_text.cpp | 121 ++++++++++++++++++++++++++------- src/v_video.h | 8 ++- wadsrc/static/zscript/base.txt | 6 +- 4 files changed, 109 insertions(+), 30 deletions(-) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 331be9712..52f8cde7a 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -142,7 +142,7 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, .. DrawTextureParms(img, parms); } -static int ListGetInt(VMVa_List &tags); +int ListGetInt(VMVa_List &tags); void DCanvas::DrawTexture(FTexture *img, double x, double y, VMVa_List &args) { @@ -487,7 +487,7 @@ static void ListEnd(VMVa_List &tags) { } -static int ListGetInt(VMVa_List &tags) +int ListGetInt(VMVa_List &tags) { if (tags.curindex < tags.numargs && tags.args[tags.curindex].Type == REGT_INT) { diff --git a/src/v_text.cpp b/src/v_text.cpp index 324e22bc0..3394e448a 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -47,6 +47,8 @@ #include "doomstat.h" #include "templates.h" +int ListGetInt(VMVa_List &tags); + //========================================================================== // // DrawChar @@ -82,6 +84,42 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch } } +void DCanvas::DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args) +{ + if (font == NULL) + return; + + if (normalcolor >= NumTextColors) + normalcolor = CR_UNTRANSLATED; + + FTexture *pic; + int dummy; + + if (NULL != (pic = font->GetChar(character, &dummy))) + { + DrawParms parms; + uint32_t tag = ListGetInt(args); + bool res = ParseDrawTextureTags(pic, x, y, tag, args, &parms, false); + if (!res) return; + parms.remap = font->GetColorTranslation((EColorRange)normalcolor); + DrawTextureParms(pic, parms); + } +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawChar) +{ + PARAM_PROLOGUE; + PARAM_POINTER(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(chr); + + VMVa_List args = { param + 5, 0, numparam - 5 }; + screen->DrawChar(font, cr, x, y, chr, args); + return 0; +} + //========================================================================== // // DrawText @@ -90,32 +128,17 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch // //========================================================================== -void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...) +void DCanvas::DrawTextCommon(FFont *font, int normalcolor, double x, double y, const char *string, DrawParms &parms) { int w; const BYTE *ch; int c; - int cx; - int cy; + double cx; + double cy; int boldcolor; FRemapTable *range; int kerning; FTexture *pic; - DrawParms parms; - - va_list tags; - - if (font == NULL || string == NULL) - return; - - va_start(tags, tag_first); - bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true); - va_end(tags); - if (!res) - { - return; - } - if (parms.celly == 0) parms.celly = font->GetHeight() + 1; parms.celly *= parms.scaley; @@ -124,15 +147,15 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s normalcolor = CR_UNTRANSLATED; boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1; - range = font->GetColorTranslation ((EColorRange)normalcolor); + range = font->GetColorTranslation((EColorRange)normalcolor); - kerning = font->GetDefaultKerning (); + kerning = font->GetDefaultKerning(); ch = (const BYTE *)string; cx = x; cy = y; - + while ((const char *)ch - string < parms.maxstrlen) { c = *ch++; @@ -141,14 +164,14 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s if (c == TEXTCOLOR_ESCAPE) { - EColorRange newcolor = V_ParseFontColor (ch, normalcolor, boldcolor); + EColorRange newcolor = V_ParseFontColor(ch, normalcolor, boldcolor); if (newcolor != CR_UNDEFINED) { - range = font->GetColorTranslation (newcolor); + range = font->GetColorTranslation(newcolor); } continue; } - + if (c == '\n') { cx = x; @@ -156,7 +179,7 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s continue; } - if (NULL != (pic = font->GetChar (c, &w))) + if (NULL != (pic = font->GetChar(c, &w))) { parms.remap = range; SetTextureParms(&parms, pic, cx, cy); @@ -172,6 +195,54 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s } } +void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...) +{ + va_list tags; + DrawParms parms; + + if (font == NULL || string == NULL) + return; + + va_start(tags, tag_first); + bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true); + va_end(tags); + if (!res) + { + return; + } + DrawTextCommon(font, normalcolor, x, y, string, parms); +} + +void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args) +{ + DrawParms parms; + + if (font == NULL || string == NULL) + return; + + uint32_t tag = ListGetInt(args); + bool res = ParseDrawTextureTags(nullptr, 0, 0, tag, args, &parms, true); + if (!res) + { + return; + } + DrawTextCommon(font, normalcolor, x, y, string, parms); +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawText) +{ + PARAM_PROLOGUE; + PARAM_POINTER(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_STRING(chr); + + VMVa_List args = { param + 5, 0, numparam - 5 }; + screen->DrawText(font, cr, x, y, chr, args); + return 0; +} + //========================================================================== // diff --git a/src/v_video.h b/src/v_video.h index 18bb310e1..a594fa8fe 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -269,8 +269,10 @@ public: #undef DrawText // See WinUser.h for the definition of DrawText as a macro #endif // 2D Text drawing - void DrawText (FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...); - void DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...); + void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...); + void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args); + void DrawChar(FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...); + void DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args); protected: BYTE *Buffer; @@ -279,6 +281,8 @@ protected: int Pitch; int LockCount; + void DrawTextCommon(FFont *font, int normalcolor, double x, double y, const char *string, DrawParms &parms); + bool ClipBox (int &left, int &top, int &width, int &height, const BYTE *&src, const int srcpitch) const; void DrawTextureV(FTexture *img, double x, double y, uint32 tag, va_list tags) = delete; virtual void DrawTextureParms(FTexture *img, DrawParms &parms); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 57ec1b6df..802c220c9 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -66,6 +66,10 @@ struct Screen native native static int GetWidth(); native static int GetHeight(); native static void DrawHUDTexture(TextureID tex, double x, double y); + native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...); + native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...); + native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...); + } class BrokenLines : Object native @@ -357,7 +361,7 @@ struct StringStruct native { native void Replace(String pattern, String replacement); native static vararg String Format(String fmt, ...); - native vararg void AppendFormat(String fmt, ...); + native vararg void AppendFormat(String fmt, ...); } class Floor : Thinker native From 72810c969d87fd21566d6d74d2bdd5b2ede12e64 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 18:07:12 +0100 Subject: [PATCH 06/50] - added ChangeCamera script function. --- src/p_actionfunctions.cpp | 25 ++++++++++++++ wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/base.txt | 58 +++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index f89a560ab..c732ea18c 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -79,6 +79,7 @@ #include "thingdef.h" #include "math/cmath.h" #include "g_levellocals.h" +#include "r_utility.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -6913,3 +6914,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetSize) ACTION_RETURN_BOOL(true); } + +DEFINE_ACTION_FUNCTION(AActor, SetCamera) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_OBJECT(cam, AActor); + PARAM_BOOL_DEF(revert); + + if (self->player == nullptr || self->player->mo != self) return 0; + + if (camera == nullptr) + { + camera = self; + revert = false; + } + AActor *oldcamera = self->player->camera; + self->player->camera = camera; + if (revert) self->player->cheats |= CF_REVERTPLEASE; + + if (oldcamera != camera) + { + R_ClearPastViewer(camera); + } + return 0; +} diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 24afe68e9..9b6f42b88 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -498,6 +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); // DECORATE compatible functions native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 802c220c9..175f8341d 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -32,6 +32,64 @@ struct TexMan native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny); } +enum DrawTextureTags +{ + TAG_USER = (1<<30), + DTA_Base = TAG_USER + 5000, + DTA_DestWidth, // width of area to draw to + DTA_DestHeight, // height of area to draw to + DTA_Alpha, // alpha value for translucency + DTA_FillColor, // color to stencil onto the destination (RGB is the color for truecolor drawers, A is the palette index for paletted drawers) + DTA_TranslationIndex, // translation table to recolor the source + DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor + DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac + DTA_320x200, // bool: scale texture size and position to fit on a virtual 320x200 screen + DTA_Bottom320x200, // bool: same as DTA_320x200 but centers virtual screen on bottom for 1280x1024 targets + DTA_CleanNoMove, // bool: like DTA_Clean but does not reposition output position + DTA_CleanNoMove_1, // bool: like DTA_CleanNoMove, but uses Clean[XY]fac_1 instead + DTA_FlipX, // bool: flip image horizontally //FIXME: Does not work with DTA_Window(Left|Right) + DTA_ShadowColor, // color of shadow + DTA_ShadowAlpha, // alpha of shadow + DTA_Shadow, // set shadow color and alphas to defaults + DTA_VirtualWidth, // pretend the canvas is this wide + DTA_VirtualHeight, // pretend the canvas is this tall + DTA_TopOffset, // override texture's top offset + DTA_LeftOffset, // override texture's left offset + DTA_CenterOffset, // bool: override texture's left and top offsets and set them for the texture's middle + DTA_CenterBottomOffset,// bool: override texture's left and top offsets and set them for the texture's bottom middle + DTA_WindowLeft, // don't draw anything left of this column (on source, not dest) + DTA_WindowRight, // don't draw anything at or to the right of this column (on source, not dest) + DTA_ClipTop, // don't draw anything above this row (on dest, not source) + DTA_ClipBottom, // don't draw anything at or below this row (on dest, not source) + DTA_ClipLeft, // don't draw anything to the left of this column (on dest, not source) + DTA_ClipRight, // don't draw anything at or to the right of this column (on dest, not source) + DTA_Masked, // true(default)=use masks from texture, false=ignore masks + DTA_HUDRules, // use fullscreen HUD rules to position and size textures + DTA_HUDRulesC, // only used internally for marking HUD_HorizCenter + DTA_KeepRatio, // doesn't adjust screen size for DTA_Virtual* if the aspect ratio is not 4:3 + DTA_RenderStyle, // same as render style for actors + DTA_ColorOverlay, // DWORD: ARGB to overlay on top of image; limited to black for software + DTA_Internal1, + DTA_Internal2, + DTA_Internal3, + DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.) + + // floating point duplicates of some of the above: + DTA_DestWidthF, + DTA_DestHeightF, + DTA_TopOffsetF, + DTA_LeftOffsetF, + DTA_VirtualWidthF, + DTA_VirtualHeightF, + DTA_WindowLeftF, + DTA_WindowRightF, + + // For DrawText calls only: + DTA_TextLen, // stop after this many characters, even if \0 not hit + DTA_CellX, // horizontal size of character cell + DTA_CellY, // vertical size of character cell +}; + struct Screen native { enum EColorRange From 481bddf6288de9c2c646fe6ee164d36511788264 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 5 Feb 2017 11:26:17 +0200 Subject: [PATCH 07/50] Fixed incorrect offscreen rendering of player's blend --- src/gl/scene/gl_scene.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b67cf810e..e9d6b7e1e 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -866,6 +866,14 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo // This should be done after postprocessing, not before. mBuffers->BindCurrentFB(); glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); + + if (!toscreen) + { + gl_RenderState.mViewMatrix.loadIdentity(); + gl_RenderState.mProjectionMatrix.ortho(mScreenViewport.left, mScreenViewport.width, mScreenViewport.height, mScreenViewport.top, -1.0f, 1.0f); + gl_RenderState.ApplyMatrices(); + } + DrawBlend(lviewsector); } mDrawingScene2D = false; From e55406bc234f610386b0b4a4135188454ef188ff Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 18:48:49 +0100 Subject: [PATCH 08/50] - changed clean scaling factor calculation so that it doesn't prefer larger scales on high resolution displays. This was a tweak that only makes sense when the scaling factors are low, i.e. 2 vs. 3, but for modern high resolutions it will enlarge things a bit too much. --- src/v_video.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index 6077f878e..6d5913ce1 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1396,7 +1396,7 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real cy1 = MAX(cheight / designheight, 1); cx2 = MAX(realwidth / designwidth, 1); cy2 = MAX(realheight / designheight, 1); - if (abs(cx1 - cy1) <= abs(cx2 - cy2)) + if (abs(cx1 - cy1) <= abs(cx2 - cy2) || cx1 >= 4) { // e.g. 640x360 looks better with this. *cleanx = cx1; *cleany = cy1; From 810efe517df4f9228023032bc9a9b341b4dc222b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 21:38:06 +0100 Subject: [PATCH 09/50] - fixed: AActor::SetOrigin lost its 'virtual' qualifier in the ZScript merge, but ADynamicLight needs this to work properly. --- src/actor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index 652d40aa1..05b1aa076 100644 --- a/src/actor.h +++ b/src/actor.h @@ -972,7 +972,7 @@ public: { SetOrigin(Pos() + vel, true); } - void SetOrigin(double x, double y, double z, bool moving); + virtual void SetOrigin(double x, double y, double z, bool moving); void SetOrigin(const DVector3 & npos, bool moving) { SetOrigin(npos.X, npos.Y, npos.Z, moving); From a4dbbf696987747a85534fc6d194ac1829e6e0ce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 21:43:16 +0100 Subject: [PATCH 10/50] - fixed P_NightmareRespawn did not respawn a map defined spawn health and neither made skill-related adjustments. --- src/p_mobj.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index df6223242..758b4ac18 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3196,6 +3196,7 @@ void P_NightmareRespawn (AActor *mobj) // spawn it mo = AActor::StaticSpawn(mobj->GetClass(), DVector3(mobj->SpawnPoint.X, mobj->SpawnPoint.Y, z), NO_REPLACE, true); + mo->health = mobj->SpawnHealth(); if (z == ONFLOORZ) { From d90f2ba1faa0a68f3d3d0c9f1b34e447f8e41287 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Feb 2017 21:54:09 +0100 Subject: [PATCH 11/50] - wrap the va_list that gets passed around by the Draw functions into a struct so that the templates can use reliable, identical semantics for both this and the VM's arg list. --- src/v_draw.cpp | 28 ++++++++++++++-------------- src/v_text.cpp | 12 ++++++------ src/v_video.h | 5 +++++ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 52f8cde7a..6f0e8330a 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -129,12 +129,12 @@ static int PalFromRGB(uint32 rgb) void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ...) { - va_list tags; - va_start(tags, tags_first); + Va_List tags; + va_start(tags.list, tags_first); DrawParms parms; bool res = ParseDrawTextureTags(img, x, y, tags_first, tags, &parms, false); - va_end(tags); + va_end(tags.list); if (!res) { return; @@ -457,30 +457,30 @@ bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double return false; } -static void ListEnd(va_list &tags) +static void ListEnd(Va_List &tags) { - va_end(tags); + va_end(tags.list); } -static int ListGetInt(va_list &tags) +static int ListGetInt(Va_List &tags) { - return va_arg(tags, int); + return va_arg(tags.list, int); } -static inline double ListGetDouble(va_list &tags) +static inline double ListGetDouble(Va_List &tags) { - return va_arg(tags, double); + return va_arg(tags.list, double); } // These two options are only being used by the D3D version of the HUD weapon drawer, they serve no purpose anywhere else. -static inline FSpecialColormap * ListGetSpecialColormap(va_list &tags) +static inline FSpecialColormap * ListGetSpecialColormap(Va_List &tags) { - return va_arg(tags, FSpecialColormap *); + return va_arg(tags.list, FSpecialColormap *); } -static inline FColormapStyle * ListGetColormapStyle(va_list &tags) +static inline FColormapStyle * ListGetColormapStyle(Va_List &tags) { - return va_arg(tags, FColormapStyle *); + return va_arg(tags.list, FColormapStyle *); } static void ListEnd(VMVa_List &tags) @@ -946,7 +946,7 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, } // explicitly instantiate both versions for v_text.cpp. -template bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, va_list& tags, DrawParms *parms, bool fortext) const; +template bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, Va_List& tags, DrawParms *parms, bool fortext) const; template bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, VMVa_List& tags, DrawParms *parms, bool fortext) const; void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h, diff --git a/src/v_text.cpp b/src/v_text.cpp index 3394e448a..8b612e83c 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -71,10 +71,10 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch if (NULL != (pic = font->GetChar (character, &dummy))) { DrawParms parms; - va_list tags; - va_start(tags, tag_first); + Va_List tags; + va_start(tags.list, tag_first); bool res = ParseDrawTextureTags(pic, x, y, tag_first, tags, &parms, false); - va_end(tags); + va_end(tags.list); if (!res) { return; @@ -197,15 +197,15 @@ void DCanvas::DrawTextCommon(FFont *font, int normalcolor, double x, double y, c void DCanvas::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...) { - va_list tags; + Va_List tags; DrawParms parms; if (font == NULL || string == NULL) return; - va_start(tags, tag_first); + va_start(tags.list, tag_first); bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true); - va_end(tags); + va_end(tags.list); if (!res) { return; diff --git a/src/v_video.h b/src/v_video.h index a594fa8fe..a2586d5a7 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -177,6 +177,11 @@ struct DrawParms bool virtBottom; }; +struct Va_List +{ + va_list list; +}; + struct VMVa_List { VMValue *args; From 124d0251316e919b145ce959a5a37ff65ac9a5e0 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 6 Feb 2017 13:18:10 +0200 Subject: [PATCH 12/50] More string methods --- src/scripting/thingdef_data.cpp | 46 ++++++++++++++++++++++++++++++++- wadsrc/static/zscript/base.txt | 7 ++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 9c36f0e49..9b1b9aaba 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1136,4 +1136,48 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) FString s = FStringFormat(param+1, defaultparam, numparam-1, ret, numret); (*self) += s; return 0; -} \ No newline at end of file +} + +DEFINE_ACTION_FUNCTION(FStringStruct, Mid) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + PARAM_INT(len); + // validate. we don't want to crash if someone passes negative values. + // with size_t it's handled naturally I think, as it's unsigned, but not in ZScript. + if (pos < 0) pos = 0; + if (len < 0) len = 0; + int slen = self->Len(); + if (pos > slen) pos = slen - 1; + if (pos + len > slen) + len = slen - pos; + FString s = self->Mid(pos, len); + ACTION_RETURN_STRING(s); +} + +DEFINE_ACTION_FUNCTION(FStringStruct, Len) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_INT(self->Len()); +} + +// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. +DEFINE_ACTION_FUNCTION(FStringStruct, CharAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + int slen = self->Len(); + if (pos < 0 || pos >= slen) + ACTION_RETURN_STRING(""); + ACTION_RETURN_STRING(FString((*self)[pos])); +} + +DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + int slen = self->Len(); + if (pos < 0 || pos >= slen) + ACTION_RETURN_INT(0); + ACTION_RETURN_INT((*self)[pos]); +} diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 175f8341d..83d714684 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -417,9 +417,14 @@ enum EPickStart // Although String is a builtin type, this is a convenient way to attach methods to it. struct StringStruct native { - native void Replace(String pattern, String replacement); native static vararg String Format(String fmt, ...); native vararg void AppendFormat(String fmt, ...); + + native void Replace(String pattern, String replacement); + native String Mid(int pos = 0, int len = 2147483647); + native int Len(); + native String CharAt(int pos); + native int CharCodeAt(int pos); } class Floor : Thinker native From f368e70f8984b3c307a212b3fa55e0f51d4e6b2d Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 6 Feb 2017 14:22:13 +0200 Subject: [PATCH 13/50] Fixed overflows in String.Mid --- src/scripting/thingdef_data.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 9b1b9aaba..8786a31bf 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1141,13 +1141,16 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) DEFINE_ACTION_FUNCTION(FStringStruct, Mid) { PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(pos); - PARAM_INT(len); + PARAM_INT(ipos); + PARAM_INT(ilen); // validate. we don't want to crash if someone passes negative values. // with size_t it's handled naturally I think, as it's unsigned, but not in ZScript. - if (pos < 0) pos = 0; - if (len < 0) len = 0; - int slen = self->Len(); + if (ipos < 0) ipos = 0; + if (ilen < 0) ilen = 0; + // convert to size_t to prevent overflows here + size_t slen = self->Len(); + size_t pos = (size_t)ipos; + size_t len = (size_t)ilen; if (pos > slen) pos = slen - 1; if (pos + len > slen) len = slen - pos; From 12477216ef8415871719b9f596bd0980d9e6cf73 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 6 Feb 2017 19:26:45 +0100 Subject: [PATCH 14/50] - did some cleanup on the OPL files to remove all use of homegrown integer types in favor of the standard ones. This already helps getting rid of one of the MUSLIB files still left. --- src/oplsynth/deftypes.h | 28 -- src/oplsynth/fmopl.cpp | 495 ++++++++++---------- src/oplsynth/mlopl.cpp | 70 +-- src/oplsynth/mlopl_io.cpp | 44 +- src/oplsynth/music_opl_mididevice.cpp | 2 +- src/oplsynth/music_opldumper_mididevice.cpp | 2 +- src/oplsynth/muslib.h | 100 ++-- 7 files changed, 352 insertions(+), 389 deletions(-) delete mode 100644 src/oplsynth/deftypes.h diff --git a/src/oplsynth/deftypes.h b/src/oplsynth/deftypes.h deleted file mode 100644 index ff3754a5f..000000000 --- a/src/oplsynth/deftypes.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Name: General Use Types Definitions -- Header Include file - * Version: 1.24 - * Author: Vladimir Arnost (QA-Software) - * Last revision: Sep-4-1995 - * Compiler: Borland C++ 3.1, Watcom C/C++ 10.0 - * - */ - -#ifndef __DEFTYPES_H_ -#define __DEFTYPES_H_ - -/* Global type declarations */ - -#include "doomtype.h" - -/* machine dependent types */ -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; - -typedef signed char schar; -typedef signed short sshort; -typedef signed int sint; -typedef signed long slong; - -#endif // __DEFTYPES_H_ diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 5138fe0d1..0e270e6f5 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -105,12 +105,6 @@ Revision History: /* compiler dependence */ #ifndef OSD_CPU_H #define OSD_CPU_H -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ #endif #ifndef PI @@ -119,34 +113,30 @@ typedef signed int INT32; /* signed 32bit */ #ifdef _MSC_VER #pragma warning (disable: 4244) -#define INLINE __forceinline #endif -#ifdef __GNUC__ -#define INLINE __inline -#endif -#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (EG timing) */ -#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ -#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ -#define FREQ_MASK ((1<>KSR */ - UINT8 mul; /* multiple: mul_tab[ML] */ +struct OPL_SLOT +{ + uint32_t ar; /* attack rate: AR<<2 */ + uint32_t dr; /* decay rate: DR<<2 */ + uint32_t rr; /* release rate:RR<<2 */ + uint8_t KSR; /* key scale rate */ + uint8_t ksl; /* keyscale level */ + uint8_t ksr; /* key scale rate: kcode>>KSR */ + uint8_t mul; /* multiple: mul_tab[ML] */ /* Phase Generator */ - UINT32 Cnt; /* frequency counter */ - UINT32 Incr; /* frequency counter step */ - UINT8 FB; /* feedback shift value */ - INT32 *connect1; /* slot1 output pointer */ - INT32 op1_out[2]; /* slot1 output for feedback */ - UINT8 CON; /* connection (algorithm) type */ + uint32_t Cnt; /* frequency counter */ + uint32_t Incr; /* frequency counter step */ + uint8_t FB; /* feedback shift value */ + int32_t *connect1; /* slot1 output pointer */ + int32_t op1_out[2]; /* slot1 output for feedback */ + uint8_t CON; /* connection (algorithm) type */ /* Envelope Generator */ - UINT8 eg_type; /* percussive/non-percussive mode */ - UINT8 state; /* phase type */ - UINT32 TL; /* total level: TL << 2 */ - INT32 TLL; /* adjusted now TL */ - INT32 volume; /* envelope counter */ - UINT32 sl; /* sustain level: sl_tab[SL] */ - - UINT8 eg_sh_ar; /* (attack state) */ - UINT8 eg_sel_ar; /* (attack state) */ - UINT8 eg_sh_dr; /* (decay state) */ - UINT8 eg_sel_dr; /* (decay state) */ - UINT8 eg_sh_rr; /* (release state) */ - UINT8 eg_sel_rr; /* (release state) */ - - UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + uint8_t eg_type; /* percussive/non-percussive mode */ + uint8_t state; /* phase type */ + uint32_t TL; /* total level: TL << 2 */ + int32_t TLL; /* adjusted now TL */ + int32_t volume; /* envelope counter */ + uint32_t sl; /* sustain level: sl_tab[SL] */ + uint8_t eg_sh_ar; /* (attack state) */ + uint8_t eg_sel_ar; /* (attack state) */ + uint8_t eg_sh_dr; /* (decay state) */ + uint8_t eg_sel_dr; /* (decay state) */ + uint8_t eg_sh_rr; /* (release state) */ + uint8_t eg_sel_rr; /* (release state) */ + uint32_t key; /* 0 = KEY OFF, >0 = KEY ON */ /* LFO */ - UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ - UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + uint32_t AMmask; /* LFO Amplitude Modulation enable mask */ + uint8_t vib; /* LFO Phase Modulation enable flag (active high)*/ /* waveform select */ unsigned int wavetable; -} OPL_SLOT; +}; -typedef struct{ +struct OPL_CH +{ OPL_SLOT SLOT[2]; /* phase generator state */ - UINT32 block_fnum; /* block+fnum */ - UINT32 fc; /* Freq. Increment base */ - UINT32 ksl_base; /* KeyScaleLevel Base step */ - UINT8 kcode; /* key code (for key scaling) */ + uint32_t block_fnum; /* block+fnum */ + uint32_t fc; /* Freq. Increment base */ + uint32_t ksl_base; /* KeyScaleLevel Base step */ + uint8_t kcode; /* key code (for key scaling) */ float LeftVol; /* volumes for stereo panning */ float RightVol; -} OPL_CH; +}; /* OPL state */ -typedef struct fm_opl_f { +struct FM_OPL +{ /* FM channel slots */ - OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ + OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ - UINT32 eg_cnt; /* global envelope generator counter */ - UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ - UINT32 eg_timer_add; /* step of eg_timer */ - UINT32 eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */ + uint32_t eg_cnt; /* global envelope generator counter */ + uint32_t eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + uint32_t eg_timer_add; /* step of eg_timer */ + uint32_t eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */ - UINT8 rhythm; /* Rhythm mode */ + uint8_t rhythm; /* Rhythm mode */ - UINT32 fn_tab[1024]; /* fnumber->increment counter */ + uint32_t fn_tab[1024]; /* fnumber->increment counter */ /* LFO */ - UINT8 lfo_am_depth; - UINT8 lfo_pm_depth_range; - UINT32 lfo_am_cnt; - UINT32 lfo_am_inc; - UINT32 lfo_pm_cnt; - UINT32 lfo_pm_inc; - UINT32 noise_rng; /* 23 bit noise shift register */ - UINT32 noise_p; /* current noise 'phase' */ - UINT32 noise_f; /* current noise peroid */ + uint8_t lfo_am_depth; + uint8_t lfo_pm_depth_range; + uint32_t lfo_am_cnt; + uint32_t lfo_am_inc; + uint32_t lfo_pm_cnt; + uint32_t lfo_pm_inc; - UINT8 wavesel; /* waveform select enable flag */ + uint32_t noise_rng; /* 23 bit noise shift register */ + uint32_t noise_p; /* current noise 'phase' */ + uint32_t noise_f; /* current noise period */ + + uint8_t wavesel; /* waveform select enable flag */ int T[2]; /* timer counters */ - UINT8 st[2]; /* timer enable */ + uint8_t st[2]; /* timer enable */ - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - UINT8 statusmask; /* status mask */ - UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ + + uint8_t address; /* address register */ + uint8_t status; /* status flag */ + uint8_t statusmask; /* status mask */ + uint8_t mode; /* Reg.08 : CSM,notesel,etc. */ bool IsStereo; /* Write stereo output */ -} FM_OPL; +}; @@ -278,68 +271,67 @@ static const int slot_array[32]= /* table is 3dB/octave , DV converts this into 6dB/octave */ /* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ #define DV (0.1875/2.0) -static const UINT32 ksl_tab[8*16]= +static const uint32_t ksl_tab[8*16]= { /* OCT 0 */ - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), /* OCT 1 */ - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), - UINT32(0.000/DV), UINT32(0.750/DV), UINT32(1.125/DV), UINT32(1.500/DV), - UINT32(1.875/DV), UINT32(2.250/DV), UINT32(2.625/DV), UINT32(3.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), + uint32_t(0.000/DV), uint32_t(0.750/DV), uint32_t(1.125/DV), uint32_t(1.500/DV), + uint32_t(1.875/DV), uint32_t(2.250/DV), uint32_t(2.625/DV), uint32_t(3.000/DV), /* OCT 2 */ - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), - UINT32(0.000/DV), UINT32(1.125/DV), UINT32(1.875/DV), UINT32(2.625/DV), - UINT32(3.000/DV), UINT32(3.750/DV), UINT32(4.125/DV), UINT32(4.500/DV), - UINT32(4.875/DV), UINT32(5.250/DV), UINT32(5.625/DV), UINT32(6.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), + uint32_t(0.000/DV), uint32_t(1.125/DV), uint32_t(1.875/DV), uint32_t(2.625/DV), + uint32_t(3.000/DV), uint32_t(3.750/DV), uint32_t(4.125/DV), uint32_t(4.500/DV), + uint32_t(4.875/DV), uint32_t(5.250/DV), uint32_t(5.625/DV), uint32_t(6.000/DV), /* OCT 3 */ - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(1.875/DV), - UINT32(3.000/DV), UINT32(4.125/DV), UINT32(4.875/DV), UINT32(5.625/DV), - UINT32(6.000/DV), UINT32(6.750/DV), UINT32(7.125/DV), UINT32(7.500/DV), - UINT32(7.875/DV), UINT32(8.250/DV), UINT32(8.625/DV), UINT32(9.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(1.875/DV), + uint32_t(3.000/DV), uint32_t(4.125/DV), uint32_t(4.875/DV), uint32_t(5.625/DV), + uint32_t(6.000/DV), uint32_t(6.750/DV), uint32_t(7.125/DV), uint32_t(7.500/DV), + uint32_t(7.875/DV), uint32_t(8.250/DV), uint32_t(8.625/DV), uint32_t(9.000/DV), /* OCT 4 */ - UINT32(0.000/DV), UINT32(0.000/DV), UINT32(3.000/DV), UINT32(4.875/DV), - UINT32(6.000/DV), UINT32(7.125/DV), UINT32(7.875/DV), UINT32(8.625/DV), - UINT32(9.000/DV), UINT32(9.750/DV),UINT32(10.125/DV),UINT32(10.500/DV), - UINT32(10.875/DV),UINT32(11.250/DV),UINT32(11.625/DV),UINT32(12.000/DV), + uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(4.875/DV), + uint32_t(6.000/DV), uint32_t(7.125/DV), uint32_t(7.875/DV), uint32_t(8.625/DV), + uint32_t(9.000/DV), uint32_t(9.750/DV),uint32_t(10.125/DV),uint32_t(10.500/DV), + uint32_t(10.875/DV),uint32_t(11.250/DV),uint32_t(11.625/DV),uint32_t(12.000/DV), /* OCT 5 */ - UINT32(0.000/DV), UINT32(3.000/DV), UINT32(6.000/DV), UINT32(7.875/DV), - UINT32(9.000/DV),UINT32(10.125/DV),UINT32(10.875/DV),UINT32(11.625/DV), - UINT32(12.000/DV),UINT32(12.750/DV),UINT32(13.125/DV),UINT32(13.500/DV), - UINT32(13.875/DV),UINT32(14.250/DV),UINT32(14.625/DV),UINT32(15.000/DV), + uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(6.000/DV), uint32_t(7.875/DV), + uint32_t(9.000/DV),uint32_t(10.125/DV),uint32_t(10.875/DV),uint32_t(11.625/DV), + uint32_t(12.000/DV),uint32_t(12.750/DV),uint32_t(13.125/DV),uint32_t(13.500/DV), + uint32_t(13.875/DV),uint32_t(14.250/DV),uint32_t(14.625/DV),uint32_t(15.000/DV), /* OCT 6 */ - UINT32(0.000/DV), UINT32(6.000/DV), UINT32(9.000/DV),UINT32(10.875/DV), - UINT32(12.000/DV),UINT32(13.125/DV),UINT32(13.875/DV),UINT32(14.625/DV), - UINT32(15.000/DV),UINT32(15.750/DV),UINT32(16.125/DV),UINT32(16.500/DV), - UINT32(16.875/DV),UINT32(17.250/DV),UINT32(17.625/DV),UINT32(18.000/DV), + uint32_t(0.000/DV), uint32_t(6.000/DV), uint32_t(9.000/DV),uint32_t(10.875/DV), + uint32_t(12.000/DV),uint32_t(13.125/DV),uint32_t(13.875/DV),uint32_t(14.625/DV), + uint32_t(15.000/DV),uint32_t(15.750/DV),uint32_t(16.125/DV),uint32_t(16.500/DV), + uint32_t(16.875/DV),uint32_t(17.250/DV),uint32_t(17.625/DV),uint32_t(18.000/DV), /* OCT 7 */ - UINT32(0.000/DV), UINT32(9.000/DV),UINT32(12.000/DV),UINT32(13.875/DV), - UINT32(15.000/DV),UINT32(16.125/DV),UINT32(16.875/DV),UINT32(17.625/DV), - UINT32(18.000/DV),UINT32(18.750/DV),UINT32(19.125/DV),UINT32(19.500/DV), - UINT32(19.875/DV),UINT32(20.250/DV),UINT32(20.625/DV),UINT32(21.000/DV) + uint32_t(0.000/DV), uint32_t(9.000/DV),uint32_t(12.000/DV),uint32_t(13.875/DV), + uint32_t(15.000/DV),uint32_t(16.125/DV),uint32_t(16.875/DV),uint32_t(17.625/DV), + uint32_t(18.000/DV),uint32_t(18.750/DV),uint32_t(19.125/DV),uint32_t(19.500/DV), + uint32_t(19.875/DV),uint32_t(20.250/DV),uint32_t(20.625/DV),uint32_t(21.000/DV) }; #undef DV /* 0 / 3.0 / 1.5 / 6.0 dB/OCT */ -static const UINT32 ksl_shift[4] = { 31, 1, 2, 0 }; +static const uint32_t ksl_shift[4] = { 31, 1, 2, 0 }; /* sustain level table (3dB per step) */ /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) -static const UINT32 sl_tab[16]={ - SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), - SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +#define SC(db) (uint32_t) ( db * (2.0/ENV_STEP) ) +static const uint32_t sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) }; #undef SC #define RATE_STEPS (8) static const unsigned char eg_inc[15*RATE_STEPS]={ - /*cycle:0 1 2 3 4 5 6 7*/ /* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ @@ -366,7 +358,7 @@ static const unsigned char eg_inc[15*RATE_STEPS]={ #define O(a) (a*RATE_STEPS) /*note that there is no O(13) in this table - it's directly in the code */ -static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ /* 16 infinite time rates */ O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), @@ -407,7 +399,7 @@ O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), /*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ #define O(a) (a*1) -static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ /* 16 infinite time rates */ O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), @@ -446,22 +438,22 @@ O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), /* multiple table */ #define ML 2 -static const UINT8 mul_tab[16]= { +static const uint8_t mul_tab[16]= { /* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ - UINT8(0.50*ML), UINT8(1.00*ML), UINT8(2.00*ML), UINT8(3.00*ML), UINT8(4.00*ML), UINT8(5.00*ML), UINT8(6.00*ML), UINT8(7.00*ML), - UINT8(8.00*ML), UINT8(9.00*ML),UINT8(10.00*ML),UINT8(10.00*ML),UINT8(12.00*ML),UINT8(12.00*ML),UINT8(15.00*ML),UINT8(15.00*ML) + uint8_t(0.50*ML), uint8_t(1.00*ML), uint8_t(2.00*ML), uint8_t(3.00*ML), uint8_t(4.00*ML), uint8_t(5.00*ML), uint8_t(6.00*ML), uint8_t(7.00*ML), + uint8_t(8.00*ML), uint8_t(9.00*ML),uint8_t(10.00*ML),uint8_t(10.00*ML),uint8_t(12.00*ML),uint8_t(12.00*ML),uint8_t(15.00*ML),uint8_t(15.00*ML) }; #undef ML -/* TL_TAB_LEN is calculated as: -* 12 - sinus amplitude bits (Y axis) -* 2 - sinus sign bit (Y axis) -* TL_RES_LEN - sinus resolution (X axis) +/* TL_TAB_LEN is calculated as: +* 12 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) */ #define TL_TAB_LEN (12*2*TL_RES_LEN) static signed int tl_tab[TL_TAB_LEN]; -#define ENV_QUIET (TL_TAB_LEN>>4) +#define ENV_QUIET (TL_TAB_LEN>>4) /* sin waveform table in 'decibel' scale */ /* four waveforms on OPL2 type chips */ @@ -473,17 +465,17 @@ static unsigned int sin_tab[SIN_LEN * 4]; Length: 210 elements. - Each of the elements has to be repeated - exactly 64 times (on 64 consecutive samples). - The whole table takes: 64 * 210 = 13440 samples. + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. - When AM = 1 data is used directly - When AM = 0 data is divided by 4 before being used (loosing precision is important) + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (losing precision is important) */ #define LFO_AM_TAB_ELEMENTS 210 -static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +static const uint8_t lfo_am_table[LFO_AM_TAB_ELEMENTS] = { 0,0,0,0,0,0,0, 1,1,1,1, 2,2,2,2, @@ -539,39 +531,38 @@ static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { }; /* LFO Phase Modulation table (verified on real YM3812) */ -static const INT8 lfo_pm_table[8*8*2] = { - +static const int8_t lfo_pm_table[8*8*2] = { /* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ /* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ /* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ /* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ /* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ /* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ /* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ /* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ }; @@ -582,8 +573,8 @@ static int num_lock = 0; static signed int phase_modulation; /* phase modulation input (SLOT 2) */ static signed int output; -static UINT32 LFO_AM; -static INT32 LFO_PM; +static uint32_t LFO_AM; +static int32_t LFO_PM; static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length); static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length); @@ -591,21 +582,21 @@ static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length); /* status set and IRQ handling */ -INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) +static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag) { /* set status flag */ OPL->status |= flag; if(!(OPL->status & 0x80)) { if(OPL->status & OPL->statusmask) - { /* IRQ on */ + { /* IRQ on */ OPL->status |= 0x80; } } } /* status reset and IRQ handling */ -INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag) { /* reset status flag */ OPL->status &=~flag; @@ -619,7 +610,7 @@ INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) } /* IRQ mask set */ -INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) { OPL->statusmask = flag; /* IRQ handling check */ @@ -629,13 +620,13 @@ INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) /* advance LFO to next sample */ -INLINE void advance_lfo(FM_OPL *OPL) +static inline void advance_lfo(FM_OPL *OPL) { - UINT8 tmp; + uint8_t tmp; /* LFO */ OPL->lfo_am_cnt += OPL->lfo_am_inc; - if (OPL->lfo_am_cnt >= (UINT32)(LFO_AM_TAB_ELEMENTS<lfo_am_cnt >= (uint32_t)(LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= (LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; @@ -650,7 +641,7 @@ INLINE void advance_lfo(FM_OPL *OPL) } /* advance to next sample */ -INLINE void advance(FM_OPL *OPL, int loch, int hich) +static inline void advance(FM_OPL *OPL, int loch, int hich) { OPL_CH *CH; OPL_SLOT *op; @@ -690,28 +681,28 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich) } break; - case EG_DEC: /* decay phase */ + case EG_DEC: /* decay phase */ if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) { op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; - if ( op->volume >= (INT32)op->sl ) + if ( op->volume >= (int32_t)op->sl ) op->state = EG_SUS; } break; - case EG_SUS: /* sustain phase */ + case EG_SUS: /* sustain phase */ /* this is important behaviour: one can change percusive/non-percussive modes on the fly and the chip will remain in sustain phase - verified on real YM3812 */ - if(op->eg_type) /* non-percussive mode */ + if(op->eg_type) /* non-percussive mode */ { /* do nothing */ } - else /* percussive mode */ + else /* percussive mode */ { /* during sustain phase chip adds Release Rate (in percussive mode) */ if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) @@ -725,7 +716,7 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich) } break; - case EG_REL: /* release phase */ + case EG_REL: /* release phase */ if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) { op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; @@ -746,7 +737,7 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich) /* Phase Generator */ if(op->vib) { - UINT8 block; + uint8_t block; unsigned int block_fnum = CH->block_fnum; unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; @@ -772,37 +763,37 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich) } } -INLINE void advance_noise(FM_OPL *OPL) +static inline void advance_noise(FM_OPL *OPL) { int i; - /* The Noise Generator of the YM3812 is 23-bit shift register. - * Period is equal to 2^23-2 samples. - * Register works at sampling frequency of the chip, so output - * can change on every sample. + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. * - * Output of the register and input to the bit 22 is: - * bit0 XOR bit14 XOR bit15 XOR bit22 + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 * - * Simply use bit 22 as the noise output. + * Simply use bit 22 as the noise output. */ OPL->noise_p += OPL->noise_f; - i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ OPL->noise_p &= FREQ_MASK; while (i) { /* - UINT32 j; + uint32_t j; j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); */ /* - Instead of doing all the logic operations above, we - use a trick here (and use bit 0 as the noise output). - The difference is only that the noise bit changes one - step ahead. This doesn't matter since we don't know + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know what is real state of the noise_rng after the reset. */ @@ -814,9 +805,9 @@ INLINE void advance_noise(FM_OPL *OPL) } -INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +static inline signed int op_calc(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab) { - UINT32 p; + uint32_t p; p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; @@ -825,9 +816,9 @@ INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigne return tl_tab[p]; } -INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +static inline signed int op_calc1(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab) { - UINT32 p; + uint32_t p; p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; @@ -837,10 +828,10 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsign } -#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) +#define volume_calc(OP) ((OP)->TLL + ((uint32_t)(OP)->volume) + (LFO_AM & (OP)->AMmask)) /* calculate output */ -INLINE float OPL_CALC_CH( OPL_CH *CH ) +static inline float OPL_CALC_CH( OPL_CH *CH ) { OPL_SLOT *SLOT; unsigned int env; @@ -875,9 +866,9 @@ INLINE float OPL_CALC_CH( OPL_CH *CH ) } /* - operators used in the rhythm sounds generation process: + operators used in the rhythm sounds generation process: - Envelope Generator: + Envelope Generator: channel operator register number Bass High Snare Tom Top / slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal @@ -911,7 +902,7 @@ number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal /* calculate rhythm */ -INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) +static inline void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) { OPL_SLOT *SLOT; signed int out; @@ -988,7 +979,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) /* when res1 = 0 phase = 0x000 | 0xd0; */ /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ - UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + uint32_t phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; /* enable gate based on frequency of operator 2 in channel 8 */ unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; @@ -1029,7 +1020,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) /* when bit8 = 0 phase = 0x100; */ /* when bit8 = 1 phase = 0x200; */ - UINT32 phase = bit8 ? 0x200 : 0x100; + uint32_t phase = bit8 ? 0x200 : 0x100; /* Noise bit XOR'es phase by 0x100 */ /* when noisebit = 0 pass the phase from calculation above */ @@ -1059,7 +1050,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) /* when res1 = 0 phase = 0x000 | 0x100; */ /* when res1 = 1 phase = 0x200 | 0x100; */ - UINT32 phase = res1 ? 0x300 : 0x100; + uint32_t phase = res1 ? 0x300 : 0x100; /* enable gate based on frequency of operator 2 in channel 8 */ unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; @@ -1073,7 +1064,6 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) output += op_calc(phase<>= 4; /* 12 bits here */ + n = (int)m; /* 16 bits here */ + n >>= 4; /* 12 bits here */ n = (n+1)>>1; /* round to nearest */ /* 11 bits here (rounded) */ - n <<= 1; /* 12 bits here (as in real chip) */ + n <<= 1; /* 12 bits here (as in real chip) */ tl_tab[ x*2 + 0 ] = n; tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; @@ -1123,14 +1113,14 @@ static void init_tables(void) /* we never reach zero here due to ((i*2)+1) */ if (m>0.0) - o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ else - o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ o = o / (ENV_STEP/4); n = (int)(2.0*o); - if (n&1) /* round to nearest */ + if (n&1) /* round to nearest */ n = (n>>1)+1; else n = n>>1; @@ -1176,18 +1166,18 @@ static void OPL_initalize(FM_OPL *OPL) for( i=0 ; i < 1024 ; i++ ) { /* opn phase increment counter = 20bit */ - OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ + OPL->fn_tab[i] = (uint32_t)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ } /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ /* One entry from LFO_AM_TABLE lasts for 64 samples */ - OPL->lfo_am_inc = UINT32((1.0 / 64.0 ) * (1<lfo_am_inc = uint32_t((1.0 / 64.0 ) * (1<lfo_pm_inc = UINT32((1.0 / 1024.0) * (1<lfo_pm_inc = uint32_t((1.0 / 1024.0) * (1<eg_timer_add = UINT32((1<eg_timer_overflow = UINT32(( 1 ) * (1<eg_timer_add = uint32_t((1<eg_timer_overflow = uint32_t(( 1 ) * (1<IsStereo = false; @@ -1198,7 +1188,7 @@ static void OPL_initalize(FM_OPL *OPL) } } -INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) +static inline void FM_KEYON(OPL_SLOT *SLOT, uint32_t key_set) { if( !SLOT->key ) { @@ -1210,7 +1200,7 @@ INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) SLOT->key |= key_set; } -INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) +static inline void FM_KEYOFF(OPL_SLOT *SLOT, uint32_t key_clr) { if( SLOT->key ) { @@ -1226,7 +1216,7 @@ INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) } /* update phase increment counter of operator (also update the EG rates if necessary) */ -void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) { int ksr; @@ -1257,7 +1247,7 @@ void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) } /* set multi,am,vib,EG-TYP,KSR,mul */ -void set_mul(FM_OPL *OPL,int slot,int v) +static inline void set_mul(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; @@ -1271,7 +1261,7 @@ void set_mul(FM_OPL *OPL,int slot,int v) } /* set ksl & tl */ -void set_ksl_tl(FM_OPL *OPL,int slot,int v) +static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; @@ -1283,7 +1273,7 @@ void set_ksl_tl(FM_OPL *OPL,int slot,int v) } /* set attack rate & decay rate */ -INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +static inline void set_ar_dr(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; @@ -1307,7 +1297,7 @@ INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) } /* set sustain level & release rate */ -void set_sl_rr(FM_OPL *OPL,int slot,int v) +static inline void set_sl_rr(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; @@ -1333,31 +1323,32 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) switch(r&0xe0) { - case 0x00: /* 00-1f:control */ + case 0x00: /* 00-1f:control */ switch(r&0x1f) { case 0x01: /* waveform select enable */ OPL->wavesel = v&0x20; break; - case 0x02: /* Timer 1 */ + case 0x02: /* Timer 1 */ OPL->T[0] = (256-v)*4; break; - case 0x03: /* Timer 2 */ + case 0x03: /* Timer 2 */ OPL->T[1] = (256-v)*16; break; - case 0x04: /* IRQ clear / mask and Timer enable */ + case 0x04: /* IRQ clear / mask and Timer enable */ if(v&0x80) - { /* IRQ flag clear */ + { /* IRQ flag clear */ OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ } else - { /* set IRQ mask ,timer enable*/ - UINT8 st1 = v&1; - UINT8 st2 = (v>>1)&1; + { /* set IRQ mask ,timer enable*/ + uint8_t st1 = v&1; + uint8_t st2 = (v>>1)&1; /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); + /* timer 2 */ if(OPL->st[1] != st2) { @@ -1375,7 +1366,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) break; } break; - case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ slot = slot_array[r&0x1f]; if(slot < 0) return; set_mul(OPL,slot,v); @@ -1396,7 +1387,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) set_sl_rr(OPL,slot,v); break; case 0xa0: - if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ + if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ { OPL->lfo_am_depth = v & 0x80; OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; @@ -1449,11 +1440,11 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) if( (r&0x0f) > 8) return; CH = &OPL->P_CH[r&0x0f]; if(!(r&0x10)) - { /* a0-a8 */ + { /* a0-a8 */ block_fnum = (CH->block_fnum&0x1f00) | v; } else - { /* b0-b8 */ + { /* b0-b8 */ block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); if(v&0x20) @@ -1468,9 +1459,9 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) } } /* update */ - if(CH->block_fnum != (UINT32)block_fnum) + if(CH->block_fnum != (uint32_t)block_fnum) { - UINT8 block = block_fnum >> 10; + uint8_t block = block_fnum >> 10; CH->block_fnum = block_fnum; @@ -1480,13 +1471,13 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ CH->kcode = (CH->block_fnum&0x1c00)>>9; - /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ + /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ if (OPL->mode&0x40) - CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ else - CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ + CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ /* refresh Total Level in both SLOTs of this channel */ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); @@ -1527,8 +1518,8 @@ static void OPLResetChip(FM_OPL *OPL) OPL->eg_timer = 0; OPL->eg_cnt = 0; - OPL->noise_rng = 1; /* noise shift register */ - OPL->mode = 0; /* normal mode */ + OPL->noise_rng = 1; /* noise shift register */ + OPL->mode = 0; /* normal mode */ OPL_STATUS_RESET(OPL,0x7f); /* reset with register write */ @@ -1604,15 +1595,15 @@ public: { int i; - UINT8 rhythm = Chip.rhythm&0x20; + uint8_t rhythm = Chip.rhythm&0x20; - UINT32 lfo_am_cnt_bak = Chip.lfo_am_cnt; - UINT32 eg_timer_bak = Chip.eg_timer; - UINT32 eg_cnt_bak = Chip.eg_cnt; + uint32_t lfo_am_cnt_bak = Chip.lfo_am_cnt; + uint32_t eg_timer_bak = Chip.eg_timer; + uint32_t eg_cnt_bak = Chip.eg_cnt; - UINT32 lfo_am_cnt_out = lfo_am_cnt_bak; - UINT32 eg_timer_out = eg_timer_bak; - UINT32 eg_cnt_out = eg_cnt_bak; + uint32_t lfo_am_cnt_out = lfo_am_cnt_bak; + uint32_t eg_timer_out = eg_timer_bak; + uint32_t eg_cnt_out = eg_cnt_bak; for (i = 0; i <= (rhythm ? 5 : 8); ++i) { diff --git a/src/oplsynth/mlopl.cpp b/src/oplsynth/mlopl.cpp index 7baacc946..bbff8b5fd 100644 --- a/src/oplsynth/mlopl.cpp +++ b/src/oplsynth/mlopl.cpp @@ -69,12 +69,12 @@ musicBlock::~musicBlock () if (OPLinstruments != NULL) free(OPLinstruments); } -void musicBlock::writeFrequency(uint slot, uint note, int pitch, uint keyOn) +void musicBlock::writeFrequency(uint32_t slot, uint32_t note, int pitch, uint32_t keyOn) { io->OPLwriteFreq (slot, note, pitch, keyOn); } -void musicBlock::writeModulation(uint slot, struct OPL2instrument *instr, int state) +void musicBlock::writeModulation(uint32_t slot, struct OPL2instrument *instr, int state) { if (state) state = 0x40; /* enable Frequency Vibrato */ @@ -83,17 +83,17 @@ void musicBlock::writeModulation(uint slot, struct OPL2instrument *instr, int st instr->trem_vibr_2 | state); } -uint musicBlock::calcVolume(uint channelVolume, uint channelExpression, uint noteVolume) +uint32_t musicBlock::calcVolume(uint32_t channelVolume, uint32_t channelExpression, uint32_t noteVolume) { - noteVolume = ((ulong)channelVolume * channelExpression * noteVolume) / (127*127); + noteVolume = ((uint64_t)channelVolume * channelExpression * noteVolume) / (127*127); if (noteVolume > 127) return 127; else return noteVolume; } -int musicBlock::occupyChannel(uint slot, uint channel, - int note, int volume, struct OP2instrEntry *instrument, uchar secondary) +int musicBlock::occupyChannel(uint32_t slot, uint32_t channel, + int note, int volume, struct OP2instrEntry *instrument, uint8_t secondary) { struct OPL2instrument *instr; struct channelEntry *ch = &channels[slot]; @@ -142,7 +142,7 @@ int musicBlock::occupyChannel(uint slot, uint channel, return slot; } -int musicBlock::releaseChannel(uint slot, uint killed) +int musicBlock::releaseChannel(uint32_t slot, uint32_t killed) { struct channelEntry *ch = &channels[slot]; writeFrequency(slot, ch->realnote, ch->pitch, 0); @@ -157,10 +157,10 @@ int musicBlock::releaseChannel(uint slot, uint killed) return slot; } -int musicBlock::releaseSustain(uint channel) +int musicBlock::releaseSustain(uint32_t channel) { - uint i; - uint id = channel; + uint32_t i; + uint32_t id = channel; for(i = 0; i < io->OPLchannels; i++) { @@ -170,16 +170,16 @@ int musicBlock::releaseSustain(uint channel) return 0; } -int musicBlock::findFreeChannel(uint flag, uint channel, uchar note) +int musicBlock::findFreeChannel(uint32_t flag, uint32_t channel, uint8_t note) { - uint i; + uint32_t i; - ulong bestfit = 0; - uint bestvoice = 0; + uint32_t bestfit = 0; + uint32_t bestvoice = 0; for (i = 0; i < io->OPLchannels; ++i) { - ulong magic; + uint32_t magic; magic = ((channels[i].flags & CH_FREE) << 24) | ((channels[i].note == note && @@ -200,9 +200,9 @@ int musicBlock::findFreeChannel(uint flag, uint channel, uchar note) return bestvoice; } -struct OP2instrEntry *musicBlock::getInstrument(uint channel, uchar note) +struct OP2instrEntry *musicBlock::getInstrument(uint32_t channel, uint8_t note) { - uint instrnumber; + uint32_t instrnumber; if (channel == PERCUSSION) { @@ -225,7 +225,7 @@ struct OP2instrEntry *musicBlock::getInstrument(uint channel, uchar note) // code 1: play note CVAR (Bool, opl_singlevoice, 0, 0) -void musicBlock::OPLplayNote(uint channel, uchar note, int volume) +void musicBlock::OPLplayNote(uint32_t channel, uint8_t note, int volume) { int i; struct OP2instrEntry *instr; @@ -251,11 +251,11 @@ void musicBlock::OPLplayNote(uint channel, uchar note, int volume) } // code 0: release note -void musicBlock::OPLreleaseNote(uint channel, uchar note) +void musicBlock::OPLreleaseNote(uint32_t channel, uint8_t note) { - uint i; - uint id = channel; - uint sustain = driverdata.channelSustain[channel]; + uint32_t i; + uint32_t id = channel; + uint32_t sustain = driverdata.channelSustain[channel]; for(i = 0; i < io->OPLchannels; i++) { @@ -270,10 +270,10 @@ void musicBlock::OPLreleaseNote(uint channel, uchar note) } // code 2: change pitch wheel (bender) -void musicBlock::OPLpitchWheel(uint channel, int pitch) +void musicBlock::OPLpitchWheel(uint32_t channel, int pitch) { - uint i; - uint id = channel; + uint32_t i; + uint32_t id = channel; // Convert pitch from 14-bit to 7-bit, then scale it, since the player // code only understands sensitivities of 2 semitones. @@ -292,10 +292,10 @@ void musicBlock::OPLpitchWheel(uint channel, int pitch) } // code 4: change control -void musicBlock::OPLchangeControl(uint channel, uchar controller, int value) +void musicBlock::OPLchangeControl(uint32_t channel, uint8_t controller, int value) { - uint i; - uint id = channel; + uint32_t i; + uint32_t id = channel; switch (controller) { @@ -310,7 +310,7 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value) struct channelEntry *ch = &channels[i]; if (ch->channel == id) { - uchar flags = ch->flags; + uint8_t flags = ch->flags; ch->time = MLtime; if (value >= MOD_MIN) { @@ -418,7 +418,7 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value) } } -void musicBlock::OPLresetControllers(uint chan, int vol) +void musicBlock::OPLresetControllers(uint32_t chan, int vol) { driverdata.channelVolume[chan] = vol; driverdata.channelExpression[chan] = 127; @@ -429,14 +429,14 @@ void musicBlock::OPLresetControllers(uint chan, int vol) driverdata.channelPitchSens[chan] = 200; } -void musicBlock::OPLprogramChange(uint channel, int value) +void musicBlock::OPLprogramChange(uint32_t channel, int value) { driverdata.channelInstr[channel] = value; } void musicBlock::OPLplayMusic(int vol) { - uint i; + uint32_t i; for (i = 0; i < CHANNELS; i++) { @@ -446,7 +446,7 @@ void musicBlock::OPLplayMusic(int vol) void musicBlock::OPLstopMusic() { - uint i; + uint32_t i; for(i = 0; i < io->OPLchannels; i++) if (!(channels[i].flags & CH_FREE)) releaseChannel(i, 1); @@ -454,10 +454,10 @@ void musicBlock::OPLstopMusic() int musicBlock::OPLloadBank (FileReader &data) { - static const uchar masterhdr[8] = { '#','O','P','L','_','I','I','#' }; + static const uint8_t masterhdr[8] = { '#','O','P','L','_','I','I','#' }; struct OP2instrEntry *instruments; - uchar filehdr[8]; + uint8_t filehdr[8]; data.Read (filehdr, 8); if (memcmp(filehdr, masterhdr, 8)) diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index e6ed3bba8..4e88ac108 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -22,7 +22,7 @@ * Oct-30-1994 V1.40 V.Arnost * Added BLASTER variable parsing * Apr-14-1995 V1.50 V.Arnost -* Some declarations moved from adlib.h to deftypes.h +* Some declarations moved from adlib.h to doomtype.h * Jul-22-1995 V1.60 V.Arnost * Ported to Watcom C * Simplified WriteChannel() and WriteValue() @@ -63,7 +63,7 @@ void OPLio::WriteDelay(int ticks) { } -void OPLio::OPLwriteReg(int which, uint reg, uchar data) +void OPLio::OPLwriteReg(int which, uint32_t reg, uint8_t data) { if (IsOPL3) { @@ -80,13 +80,13 @@ void OPLio::OPLwriteReg(int which, uint reg, uchar data) * Write to an operator pair. To be used for register bases of 0x20, 0x40, * 0x60, 0x80 and 0xE0. */ -void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2) +void OPLio::OPLwriteChannel(uint32_t regbase, uint32_t channel, uint8_t data1, uint8_t data2) { - static const uint op_num[OPL2CHANNELS] = { + static const uint32_t op_num[OPL2CHANNELS] = { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12}; - uint which = channel / OPL2CHANNELS; - uint reg = regbase + op_num[channel % OPL2CHANNELS]; + uint32_t which = channel / OPL2CHANNELS; + uint32_t reg = regbase + op_num[channel % OPL2CHANNELS]; OPLwriteReg (which, reg, data1); OPLwriteReg (which, reg+3, data2); } @@ -95,10 +95,10 @@ void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2 * Write to channel a single value. To be used for register bases of * 0xA0, 0xB0 and 0xC0. */ -void OPLio::OPLwriteValue(uint regbase, uint channel, uchar value) +void OPLio::OPLwriteValue(uint32_t regbase, uint32_t channel, uint8_t value) { - uint which = channel / OPL2CHANNELS; - uint reg = regbase + (channel % OPL2CHANNELS); + uint32_t which = channel / OPL2CHANNELS; + uint32_t reg = regbase + (channel % OPL2CHANNELS); OPLwriteReg (which, reg, value); } @@ -174,7 +174,7 @@ static WORD frequencies[] = * That last byte in the table doesn't look right, either, but that's what * it really is. */ -void OPLio::OPLwriteFreq(uint channel, uint note, uint pitch, uint keyon) +void OPLio::OPLwriteFreq(uint32_t channel, uint32_t note, uint32_t pitch, uint32_t keyon) { int octave = 0; int j = (note << 5) + pitch; @@ -202,9 +202,9 @@ void OPLio::OPLwriteFreq(uint channel, uint note, uint pitch, uint keyon) /* * Adjust volume value (register 0x40) */ -inline uint OPLio::OPLconvertVolume(uint data, uint volume) +inline uint32_t OPLio::OPLconvertVolume(uint32_t data, uint32_t volume) { - static uchar volumetable[128] = { + static uint8_t volumetable[128] = { 0, 1, 3, 5, 6, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 27, 29, 30, 32, 33, 34, @@ -223,11 +223,11 @@ inline uint OPLio::OPLconvertVolume(uint data, uint volume) 124, 124, 125, 125, 126, 126, 127, 127}; return 0x3F - (((0x3F - data) * - (uint)volumetable[volume <= 127 ? volume : 127]) >> 7); + (uint32_t)volumetable[volume <= 127 ? volume : 127]) >> 7); } -uint OPLio::OPLpanVolume(uint volume, int pan) +uint32_t OPLio::OPLpanVolume(uint32_t volume, int pan) { if (pan >= 0) return volume; @@ -238,7 +238,7 @@ uint OPLio::OPLpanVolume(uint volume, int pan) /* * Write volume data to a channel */ -void OPLio::OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volume) +void OPLio::OPLwriteVolume(uint32_t channel, struct OPL2instrument *instr, uint32_t volume) { if (instr != 0) { @@ -251,11 +251,11 @@ void OPLio::OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volu /* * Write pan (balance) data to a channel */ -void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) +void OPLio::OPLwritePan(uint32_t channel, struct OPL2instrument *instr, int pan) { if (instr != 0) { - uchar bits; + uint8_t bits; if (pan < -36) bits = 0x10; // left else if (pan > 36) bits = 0x20; // right else bits = 0x30; // both @@ -292,7 +292,7 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) * data[5] data[12] reg. 0x40 - output level (bottom 6 bits only) * data[6] reg. 0xC0 - feedback/AM-FM (both operators) */ -void OPLio::OPLwriteInstrument(uint channel, struct OPL2instrument *instr) +void OPLio::OPLwriteInstrument(uint32_t channel, struct OPL2instrument *instr) { OPLwriteChannel(0x40, channel, 0x3F, 0x3F); // no volume OPLwriteChannel(0x20, channel, instr->trem_vibr_1, instr->trem_vibr_2); @@ -307,7 +307,7 @@ void OPLio::OPLwriteInstrument(uint channel, struct OPL2instrument *instr) */ void OPLio::OPLshutup(void) { - uint i; + uint32_t i; for(i = 0; i < OPLchannels; i++) { @@ -321,10 +321,10 @@ void OPLio::OPLshutup(void) /* * Initialize hardware upon startup */ -int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) +int OPLio::OPLinit(uint32_t numchips, bool stereo, bool initopl3) { assert(numchips >= 1 && numchips <= countof(chips)); - uint i; + uint32_t i; IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3); memset(chips, 0, sizeof(chips)); @@ -349,7 +349,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) void OPLio::OPLwriteInitState(bool initopl3) { - for (uint i = 0; i < NumChips; ++i) + for (uint32_t i = 0; i < NumChips; ++i) { int chip = i << (int)IsOPL3; if (IsOPL3 && initopl3) diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index 3cd3e625a..853a679c4 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -289,7 +289,7 @@ FString OPLMIDIDevice::GetStats() { FString out; char star[3] = { TEXTCOLOR_ESCAPE, 'A', '*' }; - for (uint i = 0; i < io->OPLchannels; ++i) + for (uint32_t i = 0; i < io->OPLchannels; ++i) { if (channels[i].flags & CH_FREE) { diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index 121ed1f58..cf20a0e73 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -336,7 +336,7 @@ DiskWriterIO::~DiskWriterIO() // //========================================================================== -int DiskWriterIO::OPLinit(uint numchips, bool, bool initopl3) +int DiskWriterIO::OPLinit(uint32_t numchips, bool, bool initopl3) { FILE *file = fopen(Filename, "wb"); if (file == NULL) diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index 7553ccc0f..e4b4ac5cb 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -76,7 +76,7 @@ Voice-mail (Czech language only, not recommended; weekends only): #define __MUSLIB_H_ #ifndef __DEFTYPES_H_ - #include "deftypes.h" + #include "doomtype.h" #endif class FileReader; @@ -119,7 +119,7 @@ struct OPL2instrument { /*0B*/ BYTE scale_2; /* OP 2: key scale level */ /*0C*/ BYTE level_2; /* OP 2: output level */ /*0D*/ BYTE unused; -/*0E*/ sshort basenote; /* base note offset */ +/*0E*/ int16_t basenote; /* base note offset */ }; /* OP2 instrument file entry */ @@ -152,41 +152,41 @@ struct OP2instrEntry { #define CH_FREE 0x80 struct OPLdata { - uint channelInstr[CHANNELS]; // instrument # - uchar channelVolume[CHANNELS]; // volume - uchar channelLastVolume[CHANNELS]; // last volume - schar channelPan[CHANNELS]; // pan, 0=normal - schar channelPitch[CHANNELS]; // pitch wheel, 64=normal - uchar channelSustain[CHANNELS]; // sustain pedal value - uchar channelModulation[CHANNELS]; // modulation pot value - ushort channelPitchSens[CHANNELS]; // pitch sensitivity, 2=default - ushort channelRPN[CHANNELS]; // RPN number for data entry - uchar channelExpression[CHANNELS]; // expression + uint32_t channelInstr[CHANNELS]; // instrument # + uint8_t channelVolume[CHANNELS]; // volume + uint8_t channelLastVolume[CHANNELS]; // last volume + int8_t channelPan[CHANNELS]; // pan, 0=normal + int8_t channelPitch[CHANNELS]; // pitch wheel, 64=normal + uint8_t channelSustain[CHANNELS]; // sustain pedal value + uint8_t channelModulation[CHANNELS]; // modulation pot value + uint16_t channelPitchSens[CHANNELS]; // pitch sensitivity, 2=default + uint16_t channelRPN[CHANNELS]; // RPN number for data entry + uint8_t channelExpression[CHANNELS]; // expression }; struct OPLio { virtual ~OPLio(); - void OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2); - void OPLwriteValue(uint regbase, uint channel, uchar value); - void OPLwriteFreq(uint channel, uint freq, uint octave, uint keyon); - uint OPLconvertVolume(uint data, uint volume); - uint OPLpanVolume(uint volume, int pan); - void OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volume); - void OPLwritePan(uint channel, struct OPL2instrument *instr, int pan); - void OPLwriteInstrument(uint channel, struct OPL2instrument *instr); + void OPLwriteChannel(uint32_t regbase, uint32_t channel, uint8_t data1, uint8_t data2); + void OPLwriteValue(uint32_t regbase, uint32_t channel, uint8_t value); + void OPLwriteFreq(uint32_t channel, uint32_t freq, uint32_t octave, uint32_t keyon); + uint32_t OPLconvertVolume(uint32_t data, uint32_t volume); + uint32_t OPLpanVolume(uint32_t volume, int pan); + void OPLwriteVolume(uint32_t channel, struct OPL2instrument *instr, uint32_t volume); + void OPLwritePan(uint32_t channel, struct OPL2instrument *instr, int pan); + void OPLwriteInstrument(uint32_t channel, struct OPL2instrument *instr); void OPLshutup(void); void OPLwriteInitState(bool initopl3); - virtual int OPLinit(uint numchips, bool stereo=false, bool initopl3=false); + virtual int OPLinit(uint32_t numchips, bool stereo=false, bool initopl3=false); virtual void OPLdeinit(void); - virtual void OPLwriteReg(int which, uint reg, uchar data); + virtual void OPLwriteReg(int which, uint32_t reg, uint8_t data); virtual void SetClockRate(double samples_per_tick); virtual void WriteDelay(int ticks); class OPLEmul *chips[MAXOPL2CHIPS]; - uint OPLchannels; - uint NumChips; + uint32_t OPLchannels; + uint32_t NumChips; bool IsOPL3; }; @@ -195,7 +195,7 @@ struct DiskWriterIO : public OPLio DiskWriterIO(const char *filename); ~DiskWriterIO(); - int OPLinit(uint numchips, bool notused, bool initopl3); + int OPLinit(uint32_t numchips, bool notused, bool initopl3); void SetClockRate(double samples_per_tick); void WriteDelay(int ticks); @@ -214,14 +214,14 @@ struct musicBlock { struct OP2instrEntry *OPLinstruments; - ulong MLtime; + uint32_t MLtime; - void OPLplayNote(uint channel, uchar note, int volume); - void OPLreleaseNote(uint channel, uchar note); - void OPLpitchWheel(uint channel, int pitch); - void OPLchangeControl(uint channel, uchar controller, int value); - void OPLprogramChange(uint channel, int value); - void OPLresetControllers(uint channel, int vol); + void OPLplayNote(uint32_t channel, uint8_t note, int volume); + void OPLreleaseNote(uint32_t channel, uint8_t note); + void OPLpitchWheel(uint32_t channel, int pitch); + void OPLchangeControl(uint32_t channel, uint8_t controller, int value); + void OPLprogramChange(uint32_t channel, int value); + void OPLresetControllers(uint32_t channel, int vol); void OPLplayMusic(int vol); void OPLstopMusic(); @@ -230,27 +230,27 @@ struct musicBlock { protected: /* OPL channel (voice) data */ struct channelEntry { - uchar channel; /* MUS channel number */ - uchar note; /* note number */ - uchar flags; /* see CH_xxx below */ - uchar realnote; /* adjusted note number */ - schar finetune; /* frequency fine-tune */ - sint pitch; /* pitch-wheel value */ - uint volume; /* note volume */ - uint realvolume; /* adjusted note volume */ + uint8_t channel; /* MUS channel number */ + uint8_t note; /* note number */ + uint8_t flags; /* see CH_xxx below */ + uint8_t realnote; /* adjusted note number */ + int8_t finetune; /* frequency fine-tune */ + int pitch; /* pitch-wheel value */ + uint32_t volume; /* note volume */ + uint32_t realvolume; /* adjusted note volume */ struct OPL2instrument *instr; /* current instrument */ - ulong time; /* note start time */ + uint32_t time; /* note start time */ } channels[MAXCHANNELS]; - void writeFrequency(uint slot, uint note, int pitch, uint keyOn); - void writeModulation(uint slot, struct OPL2instrument *instr, int state); - uint calcVolume(uint channelVolume, uint channelExpression, uint noteVolume); - int occupyChannel(uint slot, uint channel, - int note, int volume, struct OP2instrEntry *instrument, uchar secondary); - int releaseChannel(uint slot, uint killed); - int releaseSustain(uint channel); - int findFreeChannel(uint flag, uint channel, uchar note); - struct OP2instrEntry *getInstrument(uint channel, uchar note); + void writeFrequency(uint32_t slot, uint32_t note, int pitch, uint32_t keyOn); + void writeModulation(uint32_t slot, struct OPL2instrument *instr, int state); + uint32_t calcVolume(uint32_t channelVolume, uint32_t channelExpression, uint32_t noteVolume); + int occupyChannel(uint32_t slot, uint32_t channel, + int note, int volume, struct OP2instrEntry *instrument, uint8_t secondary); + int releaseChannel(uint32_t slot, uint32_t killed); + int releaseSustain(uint32_t channel); + int findFreeChannel(uint32_t flag, uint32_t channel, uint8_t note); + struct OP2instrEntry *getInstrument(uint32_t channel, uint8_t note); friend class Stat_opl; From ca48a687f838b8a7e2ede55ab88ef6bfd895ce4e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 6 Feb 2017 21:39:21 +0100 Subject: [PATCH 15/50] - major work on dynamic array support. Mostly working, some issues still exist with Move and Copy methods and with assignments in stack variables. --- src/dobjtype.cpp | 32 +++- src/dobjtype.h | 4 +- src/namedef.h | 2 + src/scripting/codegeneration/codegen.cpp | 180 +++++++++++++++++------ src/scripting/codegeneration/codegen.h | 1 + src/scripting/zscript/zcc_compile.cpp | 11 +- 6 files changed, 175 insertions(+), 55 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index e4d9fc177..958cd4275 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2012,8 +2012,8 @@ PDynArray::PDynArray() // //========================================================================== -PDynArray::PDynArray(PType *etype) -: ElementType(etype) +PDynArray::PDynArray(PType *etype,PStruct *backing) +: ElementType(etype), BackingType(backing) { mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); Size = sizeof(FArray); @@ -2061,7 +2061,33 @@ PDynArray *NewDynArray(PType *type) PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); if (atype == NULL) { - atype = new PDynArray(type); + FString backingname; + + switch (type->GetRegType()) + { + case REGT_INT: + backingname.Format("DynArray_I%d", type->Size * 8); + break; + + case REGT_FLOAT: + backingname.Format("DynArray_F%d", type->Size * 8); + break; + + case REGT_STRING: + backingname = "DynArray_String"; + break; + + case REGT_POINTER: + backingname = "DynArray_Ptr"; + break; + + default: + I_Error("Unsupported dynamic array requested"); + break; + } + + auto backing = NewNativeStruct(backingname, nullptr); + atype = new PDynArray(type, backing); TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket); } return (PDynArray *)atype; diff --git a/src/dobjtype.h b/src/dobjtype.h index 8cbe79966..60d410918 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -6,6 +6,7 @@ #endif typedef std::pair FTypeAndOffset; +class PStruct; #include "vm.h" @@ -649,9 +650,10 @@ class PDynArray : public PCompoundType DECLARE_CLASS(PDynArray, PCompoundType); HAS_OBJECT_POINTERS; public: - PDynArray(PType *etype); + PDynArray(PType *etype, PStruct *backing); PType *ElementType; + PStruct *BackingType; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; diff --git a/src/namedef.h b/src/namedef.h index 2bdb74ee6..a010fbb8a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -821,6 +821,8 @@ xx(DamageFunction) xx(Length) xx(Unit) xx(Size) +xx(Copy) +xx(Move) xx(Voidptr) xx(StateLabel) xx(SpriteID) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index a3641269f..fadc17269 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6946,20 +6946,33 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return nullptr; } - PArray *arraytype = dyn_cast(Array->ValueType); - if (arraytype == nullptr) + PArray *arraytype = nullptr; + PType *elementtype = nullptr; + if (Array->IsDynamicArray()) { - // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. - PPointer *ptype = dyn_cast(Array->ValueType); - if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) - { - ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); - delete this; - return nullptr; - } - arraytype = static_cast(ptype->PointedType); + PDynArray *darraytype = static_cast(Array->ValueType); + elementtype = darraytype->ElementType; + Array->ValueType = NewPointer(NewResizableArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged. arrayispointer = true; } + else + { + arraytype = dyn_cast(Array->ValueType); + if (arraytype == nullptr) + { + // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. + PPointer *ptype = dyn_cast(Array->ValueType); + if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) + { + ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); + delete this; + return nullptr; + } + arraytype = static_cast(ptype->PointedType); + arrayispointer = true; + } + elementtype = arraytype->ElementType; + } if (Array->IsResizableArray()) { @@ -6967,12 +6980,17 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) { auto parentfield = static_cast(Array)->membervar; - SizeAddr = parentfield->Offset + parentfield->Type->Align; + SizeAddr = parentfield->Offset + sizeof(void*); } else if (Array->ExprType == EFX_GlobalVariable) { auto parentfield = static_cast(Array)->membervar; - SizeAddr = parentfield->Offset + parentfield->Type->Align; + SizeAddr = parentfield->Offset + sizeof(void*); + } + else if (Array->ExprType == EFX_StackVariable) + { + auto parentfield = static_cast(Array)->membervar; + SizeAddr = parentfield->Offset + sizeof(void*); } else { @@ -6981,54 +6999,52 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return nullptr; } } - else if (index->isConstant()) + // constant indices can only be resolved at compile time for statically sized arrays. + else if (index->isConstant() && arraytype != nullptr && !arrayispointer) { unsigned indexval = static_cast(index)->GetValue().GetInt(); - if (indexval >= arraytype->ElementCount && !Array->IsResizableArray()) + if (indexval >= arraytype->ElementCount) { ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); delete this; return nullptr; } - if (!arrayispointer) + // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) { - // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) - { - auto parentfield = static_cast(Array)->membervar; - // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_StackVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->ReplaceField(newfield); - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } + auto parentfield = static_cast(Array)->membervar; + // PFields are garbage collected so this will be automatically taken care of later. + auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_GlobalVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_StackVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->ReplaceField(newfield); + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; } } - ValueType = arraytype->ElementType; + ValueType = elementtype; if (!Array->RequestAddress(ctx, &AddressWritable)) { ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); @@ -7804,6 +7820,72 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // same for String methods. It also uses a hidden struct type to define them. Self->ValueType = TypeStringStruct; } + else if (Self->IsDynamicArray()) + { + if (MethodName == NAME_Size) + { + FxExpression *x = new FxMemberIdentifier(Self, NAME_Size, ScriptPosition); // todo: obfuscate the name to prevent direct access. + Self = nullptr; + delete this; + return x->Resolve(ctx); + } + else + { + auto elementType = static_cast(Self->ValueType)->ElementType; + Self->ValueType = static_cast(Self->ValueType)->BackingType; + // this requires some added type checks for the passed types. + for (auto &a : ArgList) + { + a = a->Resolve(ctx); + if (a == nullptr) + { + delete this; + return nullptr; + } + if (a->IsDynamicArray()) + { + // Copy and Move must turn their parameter into a pointer to the backing struct type. + auto backingtype = static_cast(a->ValueType)->BackingType; + a->ValueType = NewPointer(backingtype); + + // Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.) + if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember) + { + auto member = static_cast(a); + auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset); + member->membervar = newfield; + Self = nullptr; + delete this; + member->ValueType = TypeUInt32; + return member; + } + else if (Self->ExprType == EFX_StackVariable) + { + auto member = static_cast(Self); + auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset); + member->membervar = newfield; + Self = nullptr; + delete this; + member->ValueType = TypeUInt32; + return member; + } + + } + else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + { + // the only case which must be checked up front is for pointer arrays receiving a new element. + // Since there is only one native backing class it uses a neutral void pointer as its argument, + // meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here. + if (a->ValueType != elementType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), elementType->DescriptiveName()); + delete this; + return nullptr; + } + } + } + } + } else if (Self->IsArray()) { if (MethodName == NAME_Size) diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 6438e0868..c3af91729 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -333,6 +333,7 @@ public: bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form. + bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); } virtual ExpEmit Emit(VMFunctionBuilder *build); void EmitStatement(VMFunctionBuilder *build); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 610e7554d..44428ab88 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1358,9 +1358,16 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n case AST_DynArrayType: if (allowarraytypes) { - Error(field, "%s: Dynamic array types not implemented yet", name.GetChars()); auto atype = static_cast(ztype); - retval = NewDynArray(DetermineType(outertype, field, name, atype->ElementType, false, false)); + auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true); + if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1) + { + Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); + } + else + { + retval = NewDynArray(ftype); + } break; } break; From 96b2cb0a4586d80da29f0482389ac50b69de2f69 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 6 Feb 2017 22:57:42 +0100 Subject: [PATCH 16/50] - fixed code generation for local dynamic arrays. - removed some code repetition by inherit all variable types which reference a PField for a variable offset from a base class so that PField replacements can be done with one set of code. --- src/scripting/codegeneration/codegen.cpp | 130 ++++------------------- src/scripting/codegeneration/codegen.h | 33 +++--- 2 files changed, 41 insertions(+), 122 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index fadc17269..f59320fa6 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6368,11 +6368,8 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) //========================================================================== FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) - : FxExpression(EFX_GlobalVariable, pos) + : FxMemberBase(EFX_GlobalVariable, mem, pos) { - membervar = mem; - AddressRequested = false; - AddressWritable = true; // must be true unless classx tells us otherwise if requested. } //========================================================================== @@ -6548,11 +6545,8 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) //========================================================================== FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos) - : FxExpression(EFX_StackVariable, pos) + : FxMemberBase(EFX_StackVariable, new PField(NAME_None, type, 0, offset), pos) { - membervar = new PField(NAME_None, type, 0, offset); - AddressRequested = false; - AddressWritable = true; // must be true unless classx tells us otherwise if requested. } //========================================================================== @@ -6651,14 +6645,16 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) // // //========================================================================== +FxMemberBase::FxMemberBase(EFxType type, PField *f, const FScriptPosition &p) + :FxExpression(type, p), membervar(f) +{ +} + FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos) - : FxExpression(EFX_StructMember, pos) + : FxMemberBase(EFX_StructMember, mem, pos) { classx = x; - membervar = mem; - AddressRequested = false; - AddressWritable = true; // must be true unless classx tells us otherwise if requested. } //========================================================================== @@ -6730,35 +6726,13 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) { // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember) + if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember || classx->ExprType == EFX_GlobalVariable || classx->ExprType == EFX_StackVariable) { - auto parentfield = static_cast(classx)->membervar; + 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); 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. - auto x = classx->Resolve(ctx); - classx = nullptr; - return x; - } - else if (classx->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, 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. - auto x = classx->Resolve(ctx); - classx = nullptr; - return x; - } - else if (classx->ExprType == EFX_StackVariable) - { - auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); - newfield->BitValue = membervar->BitValue; - static_cast(classx)->ReplaceField(newfield); + static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); classx = nullptr; @@ -6977,19 +6951,9 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) if (Array->IsResizableArray()) { // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable) { - auto parentfield = static_cast(Array)->membervar; - SizeAddr = parentfield->Offset + sizeof(void*); - } - else if (Array->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(Array)->membervar; - SizeAddr = parentfield->Offset + sizeof(void*); - } - else if (Array->ExprType == EFX_StackVariable) - { - auto parentfield = static_cast(Array)->membervar; + auto parentfield = static_cast(Array)->membervar; SizeAddr = parentfield->Offset + sizeof(void*); } else @@ -7011,32 +6975,12 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) } // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable) { - auto parentfield = static_cast(Array)->membervar; + auto parentfield = static_cast(Array)->membervar; // PFields are garbage collected so this will be automatically taken care of later. auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_StackVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->ReplaceField(newfield); + static_cast(Array)->membervar = newfield; Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = Array->Resolve(ctx); Array = nullptr; @@ -7083,17 +7027,8 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0)); auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr); - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) - { - static_cast(Array)->membervar = f; - static_cast(Array)->AddressRequested = false; - } - else if (Array->ExprType == EFX_GlobalVariable) - { - static_cast(Array)->membervar = f; - static_cast(Array)->AddressRequested = false; - } - + static_cast(Array)->membervar = f; + static_cast(Array)->AddressRequested = false; Array->ValueType = TypeUInt32; bound = Array->Emit(build); } @@ -7849,9 +7784,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) a->ValueType = NewPointer(backingtype); // Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.) - if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember) + if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable) { - auto member = static_cast(a); + auto member = static_cast(a); auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset); member->membervar = newfield; Self = nullptr; @@ -7859,17 +7794,6 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) member->ValueType = TypeUInt32; return member; } - else if (Self->ExprType == EFX_StackVariable) - { - auto member = static_cast(Self); - auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset); - member->membervar = newfield; - Self = nullptr; - delete this; - member->ValueType = TypeUInt32; - return member; - } - } else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { @@ -7908,19 +7832,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) else { // Resizable arrays can only be defined in C code and they can only exist in pointer form to reduce their impact on the code generator. - if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember) + if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_GlobalVariable) { - auto member = static_cast(Self); - auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer. - member->membervar = newfield; - Self = nullptr; - delete this; - member->ValueType = TypeUInt32; - return member; - } - else if (Self->ExprType == EFX_GlobalVariable) - { - auto member = static_cast(Self); + auto member = static_cast(Self); auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer. member->membervar = newfield; Self = nullptr; diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index c3af91729..c64ec2094 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -1314,19 +1314,30 @@ public: }; +//========================================================================== +// +// FxMemberBase +// +//========================================================================== + +class FxMemberBase : public FxExpression +{ +public: + PField *membervar; + bool AddressRequested = false; + bool AddressWritable = true; + FxMemberBase(EFxType type, PField *f, const FScriptPosition &p); +}; + //========================================================================== // // FxGlobalVariaböe // //========================================================================== -class FxGlobalVariable : public FxExpression +class FxGlobalVariable : public FxMemberBase { public: - PField *membervar; - bool AddressRequested; - bool AddressWritable; - FxGlobalVariable(PField*, const FScriptPosition&); FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); @@ -1343,19 +1354,17 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; + //========================================================================== // // FxClassMember // //========================================================================== -class FxStructMember : public FxExpression +class FxStructMember : public FxMemberBase { public: FxExpression *classx; - PField *membervar; - bool AddressRequested; - bool AddressWritable; FxStructMember(FxExpression*, PField*, const FScriptPosition&); ~FxStructMember(); @@ -1403,13 +1412,9 @@ public: // //========================================================================== -class FxStackVariable : public FxExpression +class FxStackVariable : public FxMemberBase { public: - PField *membervar; - bool AddressRequested; - bool AddressWritable; - FxStackVariable(PType *type, int offset, const FScriptPosition&); ~FxStackVariable(); void ReplaceField(PField *newfield); From f77a528e13f977eefb9432844db06d82da1630f9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 00:12:55 +0100 Subject: [PATCH 17/50] - added type checks for DynArray.Copy and Move and fixed parameter processing. --- src/scripting/codegeneration/codegen.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f59320fa6..4d6376f3b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7781,18 +7781,27 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { // Copy and Move must turn their parameter into a pointer to the backing struct type. auto backingtype = static_cast(a->ValueType)->BackingType; + if (elementType != static_cast(a->ValueType)->ElementType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument"); + delete this; + return nullptr; + } + bool writable; + if (!a->RequestAddress(ctx, &writable)) + { + ScriptPosition.Message(MSG_ERROR, "Unable to dereference array variable"); + delete this; + return nullptr; + } a->ValueType = NewPointer(backingtype); // Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.) if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable) { - auto member = static_cast(a); + auto member = static_cast(Self); auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset); member->membervar = newfield; - Self = nullptr; - delete this; - member->ValueType = TypeUInt32; - return member; } } else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) From 2021baf47dd8dfbba4e98a9f3ecb32000f9cc4d1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 00:24:04 +0100 Subject: [PATCH 18/50] - fixed: The 'transparent' line flag did not work due to a leftover OPAQUE constant where floats were expected. --- src/p_udmf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index e6ab47c24..515905b27 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1097,7 +1097,7 @@ public: { ld->alpha = 0.75; } - if (strifetrans2 && ld->alpha == OPAQUE) + if (strifetrans2 && ld->alpha == 1.) { ld->alpha = 0.25; } From f9712460f301267962d53f210a24ec28bc4de211 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 00:31:01 +0100 Subject: [PATCH 19/50] - fixed: 3D floors could be set for untagged sectors. --- src/p_3dfloors.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index f367c4637..fa7b66d65 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -858,7 +858,8 @@ void P_Spawn3DFloors (void) { case ExtraFloor_LightOnly: if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0; - P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0); + if (line.args[0] != 0) + P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0); break; case Sector_Set3DFloor: @@ -877,7 +878,8 @@ void P_Spawn3DFloors (void) line.args[4]=0; } } - P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]); + if (line.args[0] != 0) + P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]); break; default: From dae6230f7630cadbeb8be9f9a19f93b2307245ec Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 00:39:46 +0100 Subject: [PATCH 20/50] - fixed: Since the FastProjectile does not perform a velocity underflow check it must use an approximate comparison when deciding whether to call the Effect method. --- wadsrc/static/zscript/shared/fastprojectile.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/shared/fastprojectile.txt b/wadsrc/static/zscript/shared/fastprojectile.txt index fd877bd83..657c4680e 100644 --- a/wadsrc/static/zscript/shared/fastprojectile.txt +++ b/wadsrc/static/zscript/shared/fastprojectile.txt @@ -156,7 +156,7 @@ class FastProjectile : Actor ExplodeMissile (NULL, NULL); return; } - if (frac != (0, 0, 0) && ripcount <= 0) + if (!(frac.xy ~== (0, 0)) && ripcount <= 0) { ripcount = count >> 3; From 4ca69f10c72456f04d9e225cd6e394a948ba8a63 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 10:55:59 +0100 Subject: [PATCH 21/50] - removed a few unused definitions. --- src/oplsynth/muslib.h | 18 ------------------ src/r_data/renderstyle.cpp | 2 +- src/r_data/renderstyle.h | 4 ---- src/r_draw.cpp | 4 ++-- 4 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index e4b4ac5cb..9091c8536 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -83,26 +83,9 @@ class FileReader; /* Global Definitions */ -#define MLVERSION 0x0175 -#define MLVERSIONSTR "1.75" -extern char MLversion[]; -extern char MLcopyright[]; - #define CHANNELS 16 // total channels 0..CHANNELS-1 #define PERCUSSION 15 // percussion channel -/* MUS file header structure */ -struct MUSheader { - char ID[4]; // identifier "MUS" 0x1A - WORD scoreLen; // score length - WORD scoreStart; // score start - WORD channels; // primary channels - WORD sec_channels; // secondary channels (??) - WORD instrCnt; // used instrument count - WORD dummy; -// WORD instruments[...]; // table of used instruments -}; - /* OPL2 instrument */ struct OPL2instrument { /*00*/ BYTE trem_vibr_1; /* OP 1: tremolo/vibrato/sustain/KSR/multi */ @@ -131,7 +114,6 @@ struct OP2instrEntry { }; #define FL_FIXED_PITCH 0x0001 // note has fixed pitch (see below) -#define FL_UNKNOWN 0x0002 // ??? (used in instrument #65 only) #define FL_DOUBLE_VOICE 0x0004 // use two voices instead of one diff --git a/src/r_data/renderstyle.cpp b/src/r_data/renderstyle.cpp index 6e656f715..5c9dcc429 100644 --- a/src/r_data/renderstyle.cpp +++ b/src/r_data/renderstyle.cpp @@ -103,7 +103,7 @@ double GetAlpha(int type, double alpha) switch (type) { case STYLEALPHA_Zero: return 0; - case STYLEALPHA_One: return OPAQUE; + case STYLEALPHA_One: return 1.; case STYLEALPHA_Src: return alpha; case STYLEALPHA_InvSrc: return 1. - alpha; default: return 0; diff --git a/src/r_data/renderstyle.h b/src/r_data/renderstyle.h index 501c14c5f..947f9afed 100644 --- a/src/r_data/renderstyle.h +++ b/src/r_data/renderstyle.h @@ -44,10 +44,6 @@ enum { OPAQUE = 65536, - TRANSLUC25 = (OPAQUE / 4), - TRANSLUC33 = (OPAQUE / 3), - TRANSLUC66 = ((OPAQUE * 2) / 3), - TRANSLUC75 = ((OPAQUE * 3) / 4), }; // Legacy render styles diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 10bc104c2..c4449f73b 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -383,7 +383,7 @@ namespace swrenderer if (style.BlendOp == STYLEOP_Shadow) { style = LegacyRenderStyles[STYLE_TranslucentStencil]; - alpha = TRANSLUC33; + alpha = OPAQUE / 3; color = 0; } @@ -393,7 +393,7 @@ namespace swrenderer } else if (style.Flags & STYLEF_Alpha1) { - alpha = FRACUNIT; + alpha = OPAQUE; } else { From 56024a1ebe5aa6f3de31e5366f22b3f629c932de Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 14:48:27 +0100 Subject: [PATCH 22/50] - implemented the backend for dynamic arrays. Still needs thorough testing but it should be complete. - use a memory arena to store flat pointers so that the messed up cleanup can be avoided by deallocating this in bulk. - added a new SO opcode to the VM to execute a write barrier. This is necessary for all objects that are not linked into one global table, i.e. everything except thinkers and class types. - always use the cheaper LOS opcode for reading pointers to classes and defaults because these cannot be destroyed during normal operation. - removed the pointless validation from String.Mid. If the values are read as unsigned the internal validation of FString::Mid will automatically ensure proper results. --- src/dobject.cpp | 39 +++ src/dobjtype.cpp | 420 ++++++++++++++++------- src/dobjtype.h | 15 +- src/scripting/codegeneration/codegen.cpp | 13 +- src/scripting/thingdef_data.cpp | 21 +- src/scripting/vm/vm.h | 2 + src/scripting/vm/vmexec.h | 11 + src/scripting/vm/vmops.h | 2 + 8 files changed, 376 insertions(+), 147 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 10b37f636..63c7bb688 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -397,6 +397,23 @@ size_t DObject::PropagateMark() GC::Mark((DObject **)((BYTE *)this + *offsets)); offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + GC::Mark(&p); + } + offsets++; + } + return info->Size; } return 0; @@ -427,6 +444,28 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld) } offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + if (p == old) + { + p = notOld; + changed++; + } + } + offsets++; + } + + return changed; } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 958cd4275..034510ff9 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -65,6 +65,7 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- +FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. FNamespaceManager Namespaces; FTypeTable TypeTable; @@ -99,7 +100,7 @@ PPointer *TypeVoidPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -// A harmless non-NULL FlatPointer for classes without pointers. +// A harmless non-nullptr FlatPointer for classes without pointers. static const size_t TheEnd = ~(size_t)0; // CODE -------------------------------------------------------------------- @@ -118,7 +119,7 @@ void DumpTypeTable() { int len = 0; Printf("%4zu:", i); - for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { Printf(" -> %s", ty->DescriptiveName()); len++; @@ -161,7 +162,7 @@ IMPLEMENT_CLASS(PClassType, false, false) //========================================================================== PClassType::PClassType() -: TypeTableType(NULL) +: TypeTableType(nullptr) { } @@ -211,7 +212,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PType::PType(unsigned int size, unsigned int align) -: Size(size), Align(align), HashNext(NULL) +: Size(size), Align(align), HashNext(nullptr) { mDescriptiveName = "Type"; loadOp = OP_NOP; @@ -286,6 +287,10 @@ void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) con { } +void PType::SetPointerArray(void *base, unsigned offset, TArray *stroffs) const +{ +} + //========================================================================== // // PType :: InitializeValue @@ -831,7 +836,7 @@ PBool::PBool() MemberOnly = false; // Override the default max set by PInt's constructor PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); - assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); maxsym->Value = 1; } @@ -1147,7 +1152,7 @@ bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) const { if (base != nullptr) new((BYTE *)base + offset) FString; - if (special != NULL) + if (special != nullptr) { special->Push(std::make_pair(this, offset)); } @@ -1415,7 +1420,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PPointer::PPointer() -: PBasicType(sizeof(void *), alignof(void *)), PointedType(NULL), IsConst(false) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) { mDescriptiveName = "NullPointer"; SetOps(); @@ -1442,8 +1447,9 @@ PPointer::PPointer(PType *pointsat, bool isconst) void PPointer::SetOps() { - storeOp = OP_SP; loadOp = (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP; + // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. + storeOp = (loadOp == OP_LO && !static_cast(PointedType)->IsDescendantOf(RUNTIME_CLASS(DThinker))) ? OP_SO : OP_SP; moveOp = OP_MOVEA; RegType = REGT_POINTER; } @@ -1476,7 +1482,7 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const //========================================================================== // -// PPointer :: SetDefaultValue +// PPointer :: SetPointer // //========================================================================== @@ -1547,7 +1553,7 @@ PPointer *NewPointer(PType *type, bool isconst) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PPointer(type, isconst); TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); @@ -1606,18 +1612,6 @@ IMPLEMENT_POINTERS_START(PClassPointer) IMPLEMENT_POINTER(ClassRestriction) IMPLEMENT_POINTERS_END -//========================================================================== -// -// PClassPointer - Default Constructor -// -//========================================================================== - -PClassPointer::PClassPointer() -: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL) -{ - mDescriptiveName = "ClassPointer"; -} - //========================================================================== // // PClassPointer - Parameterized Constructor @@ -1629,6 +1623,10 @@ PClassPointer::PClassPointer(PClass *restrict) { if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); else mDescriptiveName = "ClassPointer"; + // class pointers do not need write barriers because all classes are stored in the global type table and won't get collected. + // This means we can use the cheapoer non-barriered opcodes here. + loadOp = OP_LOS; + storeOp = OP_SP; } //========================================================================== @@ -1683,7 +1681,7 @@ PClassPointer *NewClassPointer(PClass *restrict) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PClassPointer(restrict); TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket); @@ -1739,7 +1737,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); - if (etype == NULL) + if (etype == nullptr) { etype = new PEnum(name, outer); TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); @@ -1762,7 +1760,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PArray::PArray() -: ElementType(NULL), ElementCount(0) +: ElementType(nullptr), ElementCount(0) { mDescriptiveName = "Array"; } @@ -1902,7 +1900,7 @@ PArray *NewArray(PType *type, unsigned int count) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PArray(type, count); TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); @@ -1976,7 +1974,7 @@ PResizableArray *NewResizableArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PResizableArray(type); TypeTable.AddType(atype, RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, bucket); @@ -1999,7 +1997,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PDynArray::PDynArray() -: ElementType(NULL) +: ElementType(nullptr) { mDescriptiveName = "DynArray"; Size = sizeof(FArray); @@ -2046,6 +2044,152 @@ void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PDynArray :: InitializeValue +// +//========================================================================== + +void PDynArray::InitializeValue(void *addr, const void *deff) const +{ + const FArray *def = (const FArray*)deff; + FArray *aray = (FArray*)addr; + + if (def == nullptr || def->Count == 0) + { + // Empty arrays do not need construction. + *aray = { nullptr, 0, 0 }; + } + else if (ElementType->GetRegType() != REGT_STRING) + { + // These are just integral values which can be done without any constructor hackery. + size_t blocksize = ElementType->Size * def->Count; + aray->Array = M_Malloc(blocksize); + memcpy(aray->Array, def->Array, blocksize); + aray->Most = aray->Count = def->Count; + } + else + { + // non-empty string arrays require explicit construction. + new(addr) TArray(*(TArray*)def); + } +} + +//========================================================================== +// +// PDynArray :: DestroyValue +// +//========================================================================== + +void PDynArray::DestroyValue(void *addr) const +{ + FArray *aray = (FArray*)addr; + + if (aray->Array != nullptr) + { + if (ElementType->GetRegType() != REGT_STRING) + { + M_Free(aray->Array); + } + else + { + // Damn those cursed strings again. :( + ((TArray*)addr)->~TArray(); + } + } + aray->Count = aray->Most = 0; + aray->Array = nullptr; +} + +//========================================================================== +// +// PDynArray :: SetDefaultValue +// +//========================================================================== + +void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array. + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PDynArray :: SetPointer +// +//========================================================================== + +void PDynArray::SetPointerArray(void *base, unsigned offset, TArray *special) const +{ + if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // Add to the list of pointer arrays for this class. + special->Push(offset); + } +} + +//========================================================================== +// +// PDynArray :: WriteValue +// +//========================================================================== + +void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FArray *aray = (FArray*)addr; + if (aray->Count > 0) + { + if (ar.BeginArray(key)) + { + const BYTE *addrb = (const BYTE *)aray->Array; + for (unsigned i = 0; i < aray->Count; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + } + } +} + +//========================================================================== +// +// PDynArray :: ReadValue +// +//========================================================================== + +bool PDynArray::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FArray *aray = (FArray*)addr; + DestroyValue(addr); // note that even after calling this we still got a validly constructed empty array. + + if (ar.BeginArray(key)) + { + bool readsomething = false; + unsigned count = ar.ArraySize(); + + size_t blocksize = ElementType->Size * count; + aray->Array = M_Malloc(blocksize); + memset(aray->Array, 0, blocksize); + aray->Most = aray->Count = count; + + BYTE *addrb = (BYTE *)aray->Array; + for (unsigned i = 0; iGetRegType() == REGT_STRING) new(addrb) FString; + readsomething |= ElementType->ReadValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + return readsomething; + } + return false; +} + //========================================================================== // // NewDynArray @@ -2059,7 +2203,7 @@ PDynArray *NewDynArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { FString backingname; @@ -2109,7 +2253,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PMap::PMap() -: KeyType(NULL), ValueType(NULL) +: KeyType(nullptr), ValueType(nullptr) { mDescriptiveName = "Map"; Size = sizeof(FMap); @@ -2169,7 +2313,7 @@ PMap *NewMap(PType *keytype, PType *valuetype) { size_t bucket; PType *maptype = TypeTable.FindType(RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, &bucket); - if (maptype == NULL) + if (maptype == nullptr) { maptype = new PMap(keytype, valuetype); TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket); @@ -2308,7 +2452,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const foundsomething = true; const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); - if (sym == NULL) + if (sym == nullptr) { DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", label, TypeName.GetChars()); @@ -2332,7 +2476,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const // PStruct :: AddField // // Appends a new field to the end of a struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2350,10 +2494,10 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // its fields. Align = MAX(Align, type->Align); - if (Symbols.AddSymbol(field) == NULL) + if (Symbols.AddSymbol(field) == nullptr) { // name is already in use delete field; - return NULL; + return nullptr; } Fields.Push(field); @@ -2365,7 +2509,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // PStruct :: AddField // // Appends a new native field to the struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2408,7 +2552,7 @@ PStruct *NewStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2447,7 +2591,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PNativeStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2466,7 +2610,7 @@ IMPLEMENT_CLASS(PField, false, false) //========================================================================== PField::PField() -: PSymbol(NAME_None), Offset(0), Type(NULL), Flags(0) +: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0) { } @@ -2599,7 +2743,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray { size_t bucket; PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); - if (proto == NULL) + if (proto == nullptr) { proto = new PPrototype(rettypes, argtypes); TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); @@ -2689,7 +2833,7 @@ IMPLEMENT_POINTERS_END static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *addr) { - if (type != NULL) + if (type != nullptr) { RecurseWriteFields(type->ParentClass, ar, addr); // Don't write this part if it has no non-transient variables @@ -2773,7 +2917,7 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { // Only read it if the type is related to this one. const PClass *parent; - for (parent = this; parent != NULL; parent = parent->ParentClass) + for (parent = this; parent != nullptr; parent = parent->ParentClass) { if (parent == type) { @@ -2835,7 +2979,7 @@ void PClass::StaticInit () FAutoSegIterator probe(CRegHead, CRegTail); - while (*++probe != NULL) + while (*++probe != nullptr) { ((ClassReg *)*probe)->RegisterClass (); } @@ -2859,16 +3003,12 @@ void PClass::StaticInit () // // PClass :: StaticShutdown STATIC // -// Frees FlatPointers belonging to all classes. Only really needed to avoid -// memory leak warnings at exit. +// Frees all static class data. // //========================================================================== void PClass::StaticShutdown () { - TArray uniqueFPs(64); - unsigned int i, j; - // delete all variables containing pointers to script functions. for (auto p : FunctionPtrList) { @@ -2876,7 +3016,8 @@ void PClass::StaticShutdown () } FunctionPtrList.Clear(); - // Make a full garbage collection here so that all destroyed but uncollected higher level objects that still exist can be properly taken down. + // 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. GC::FullGC(); // From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now. @@ -2886,33 +3027,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(); - - for (i = 0; i < PClass::AllClasses.Size(); ++i) - { - PClass *type = PClass::AllClasses[i]; - PClass::AllClasses[i] = NULL; - if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers) - { - // FlatPointers are shared by many classes, so we must check for - // duplicates and only delete those that are unique. - for (j = 0; j < uniqueFPs.Size(); ++j) - { - if (type->FlatPointers == uniqueFPs[j]) - { - break; - } - } - if (j == uniqueFPs.Size()) - { - uniqueFPs.Push(const_cast(type->FlatPointers)); - } - } - type->Destroy(); - } - for (i = 0; i < uniqueFPs.Size(); ++i) - { - delete[] uniqueFPs[i]; - } + FlatpointerArena.FreeAllBlocks(); bShutdown = true; AllClasses.Clear(); @@ -2946,7 +3061,7 @@ void PClass::StaticBootstrap() PClassClass *cls = new PClassClass; PClass::RegistrationInfo.SetupClass(cls); - // The PClassClass constructor initialized these to NULL, because the + // The PClassClass constructor initialized these to nullptr, because the // PClass metadata had not been created yet. Now it has, so we know what // they should be and can insert them into the type table successfully. clscls->TypeTableType = cls; @@ -2971,6 +3086,7 @@ PClass::PClass() ParentClass = nullptr; Pointers = nullptr; FlatPointers = nullptr; + ArrayPointers = nullptr; HashNext = nullptr; Defaults = nullptr; bRuntimeClass = false; @@ -2990,10 +3106,10 @@ PClass::PClass() PClass::~PClass() { - if (Defaults != NULL) + if (Defaults != nullptr) { M_Free(Defaults); - Defaults = NULL; + Defaults = nullptr; } } @@ -3020,7 +3136,7 @@ PClass *ClassReg::RegisterClass() }; // Skip classes that have already been registered - if (MyClass != NULL) + if (MyClass != nullptr) { return MyClass; } @@ -3059,7 +3175,7 @@ PClass *ClassReg::RegisterClass() void ClassReg::SetupClass(PClass *cls) { - assert(MyClass == NULL); + assert(MyClass == nullptr); MyClass = cls; cls->TypeName = FName(Name+1); cls->Size = SizeOf; @@ -3082,7 +3198,7 @@ void PClass::InsertIntoHash () PType *found; found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket); - if (found != NULL) + if (found != nullptr) { // This type has already been inserted I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } @@ -3102,14 +3218,14 @@ void PClass::InsertIntoHash () const PClass *PClass::FindParentClass(FName name) const { - for (const PClass *type = this; type != NULL; type = type->ParentClass) + for (const PClass *type = this; type != nullptr; type = type->ParentClass) { if (type->TypeName == name) { return type; } } - return NULL; + return nullptr; } //========================================================================== @@ -3124,9 +3240,9 @@ PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { - return NULL; + return nullptr; } - return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, NULL)); + return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, nullptr)); } //========================================================================== @@ -3140,10 +3256,10 @@ PClass *PClass::FindClass (FName zaname) DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); - assert (mem != NULL); + assert (mem != nullptr); // Set this object's defaults before constructing it. - if (Defaults != NULL) + if (Defaults != nullptr) memcpy (mem, Defaults, Size); else memset (mem, 0, Size); @@ -3170,7 +3286,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(addr, defaults); for (auto tao : SpecialInits) { @@ -3195,7 +3311,7 @@ void PClass::DestroySpecials(void *addr) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->DestroySpecials(addr); for (auto tao : SpecialInits) { @@ -3231,7 +3347,7 @@ void PClass::InitializeDefaults() { if (IsKindOf(RUNTIME_CLASS(PClassActor))) { - assert(Defaults == NULL); + assert(Defaults == nullptr); Defaults = (BYTE *)M_Malloc(Size); // run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them. @@ -3248,7 +3364,7 @@ void PClass::InitializeDefaults() // Copy the defaults from the parent but leave the DObject part alone because it contains important data. - if (ParentClass->Defaults != NULL) + if (ParentClass->Defaults != nullptr) { memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject)); if (Size > ParentClass->Size) @@ -3265,7 +3381,7 @@ void PClass::InitializeDefaults() if (bRuntimeClass) { // Copy parent values from the parent defaults. - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); for (const PField *field : Fields) @@ -3404,14 +3520,14 @@ PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { - return NULL; + return nullptr; } size_t bucket; PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket); - if (found != NULL) + if (found != nullptr) { return static_cast(found); } @@ -3484,14 +3600,14 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) void PClass::BuildFlatPointers () { - if (FlatPointers != NULL) + if (FlatPointers != nullptr) { // Already built: Do nothing. return; } - else if (ParentClass == NULL) + else if (ParentClass == nullptr) { // No parent (i.e. DObject: FlatPointers is the same as Pointers. - if (Pointers == NULL) - { // No pointers: Make FlatPointers a harmless non-NULL. + if (Pointers == nullptr) + { // No pointers: Make FlatPointers a harmless non-nullptr. FlatPointers = &TheEnd; } else @@ -3536,7 +3652,7 @@ void PClass::BuildFlatPointers () { } // Concatenate them into a new array - size_t *flat = new size_t[numPointers + numSuperPointers + ScriptPointers.Size() + 1]; + size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); @@ -3555,6 +3671,68 @@ void PClass::BuildFlatPointers () } } +//========================================================================== +// +// PClass :: BuildArrayPointers +// +// same as above, but creates a list to dynamic object arrays +// +//========================================================================== + +void PClass::BuildArrayPointers() +{ + if (ArrayPointers != nullptr) + { // Already built: Do nothing. + return; + } + else if (ParentClass == nullptr) + { // No parent (i.e. DObject: FlatPointers is the same as Pointers. + ArrayPointers = &TheEnd; + } + else + { + ParentClass->BuildArrayPointers(); + + TArray ScriptPointers; + + // Collect all arrays to pointers in scripted fields. + for (auto field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointerArray(Defaults, unsigned(field->Offset), &ScriptPointers); + } + } + + if (ScriptPointers.Size() == 0) + { // No new pointers: Just use the same ArrayPointers as the parent. + ArrayPointers = ParentClass->ArrayPointers; + } + else + { // New pointers: Create a new FlatPointers array and add them. + int numSuperPointers; + + // Count pointers defined by superclasses. + for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++) + { + } + + // Concatenate them into a new array + size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); + if (numSuperPointers > 0) + { + memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); + } + if (ScriptPointers.Size() > 0) + { + memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + } + flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0; + ArrayPointers = flat; + } + } +} + //========================================================================== // // PClass :: NativeClass @@ -3604,18 +3782,18 @@ void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname) PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum) { size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - if (bucketnum != NULL) + if (bucketnum != nullptr) { *bucketnum = bucket; } - for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext) + for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) { if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) { return type; } } - return NULL; + return nullptr; } //========================================================================== @@ -3630,13 +3808,13 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) { - for (PType **type_p = &TypeHash[bucket]; *type_p != NULL; type_p = &(*type_p)->HashNext) + 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 = NULL; + type->HashNext = nullptr; *type_p = newtype; break; } @@ -3654,7 +3832,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t #ifdef _DEBUG size_t bucketcheck; assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); - assert(FindType(metatype, parm1, parm2, &bucketcheck) == NULL && "Type must not be inserted more than once"); + assert(FindType(metatype, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); assert(bucketcheck == bucket && "Passed bucket was wrong"); #endif type->HashNext = TypeHash[bucket]; @@ -3677,7 +3855,7 @@ void FTypeTable::AddType(PType *type) metatype = type->GetClass()->TypeTableType; type->GetTypeIDs(parm1, parm2); bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - assert(FindType(metatype, parm1, parm2, NULL) == NULL && "Type must not be inserted more than once"); + assert(FindType(metatype, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; @@ -3732,7 +3910,7 @@ void FTypeTable::Mark() { for (int i = HASH_SIZE - 1; i >= 0; --i) { - if (TypeHash[i] != NULL) + if (TypeHash[i] != nullptr) { GC::Mark(TypeHash[i]); } @@ -3790,7 +3968,7 @@ PSymbol::~PSymbol() } PSymbolTable::PSymbolTable() -: ParentSymbolTable(NULL) +: ParentSymbolTable(nullptr) { } @@ -3833,24 +4011,24 @@ void PSymbolTable::SetParentTable (PSymbolTable *parent) PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const { PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL && searchparents && ParentSymbolTable != NULL) + if (value == nullptr && searchparents && ParentSymbolTable != nullptr) { return ParentSymbolTable->FindSymbol(symname, searchparents); } - return value != NULL ? *value : NULL; + return value != nullptr ? *value : nullptr; } PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) { PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL) + if (value == nullptr) { - if (ParentSymbolTable != NULL) + if (ParentSymbolTable != nullptr) { return ParentSymbolTable->FindSymbolInTable(symname, symtable); } - symtable = NULL; - return NULL; + symtable = nullptr; + return nullptr; } symtable = this; return *value; @@ -3859,9 +4037,9 @@ PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) { // Symbols that already exist are not inserted. - if (Symbols.CheckKey(sym->SymbolName) != NULL) + if (Symbols.CheckKey(sym->SymbolName) != nullptr) { - return NULL; + return nullptr; } Symbols.Insert(sym->SymbolName, sym); return sym; @@ -3878,16 +4056,16 @@ 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 != NULL) + if (symslot != nullptr) { PSymbol *oldsym = *symslot; *symslot = newsym; return oldsym; } - // Else, just insert normally and return NULL since there was no + // Else, just insert normally and return nullptr since there was no // symbol to replace. Symbols.Insert(newsym->SymbolName, newsym); - return NULL; + return nullptr; } IMPLEMENT_CLASS(PNamespace, false, true) @@ -3969,7 +4147,7 @@ void RemoveUnusedSymbols() // 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 != NULL; ty = ty->HashNext) + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) { diff --git a/src/dobjtype.h b/src/dobjtype.h index 60d410918..3e204da62 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -247,6 +247,7 @@ public: // object is destroyed. virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const; virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL) const; + virtual void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const; // Initialize the value, if needed (e.g. strings) virtual void InitializeValue(void *addr, const void *def) const; @@ -534,7 +535,7 @@ class PClassPointer : public PPointer DECLARE_CLASS(PClassPointer, PPointer); HAS_OBJECT_POINTERS; public: - PClassPointer(class PClass *restrict); + PClassPointer(class PClass *restrict = nullptr); class PClass *ClassRestriction; @@ -542,8 +543,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -protected: - PClassPointer(); }; // Struct/class fields ------------------------------------------------------ @@ -657,6 +656,14 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + 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; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const override; + protected: PDynArray(); }; @@ -801,6 +808,7 @@ public: PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default + const size_t *ArrayPointers; // dynamic arrays containing object pointers. BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time bool bExported; // This type has been declared in a script @@ -818,6 +826,7 @@ public: PField *AddField(FName name, PType *type, DWORD flags=0) override; void InitializeActorInfo(); void BuildFlatPointers(); + void BuildArrayPointers(); void DestroySpecials(void *addr) const; const PClass *NativeClass() const; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4d6376f3b..a3dc066e9 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -542,7 +542,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) { tag = ATAG_STATE; } - else if (value.Type->GetLoadOp() == OP_LO) + else if (value.Type->GetLoadOp() != OP_LP) { tag = ATAG_OBJECT; } @@ -6356,7 +6356,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) ob.Free(build); ExpEmit meta(build, REGT_POINTER); build->Emit(OP_META, meta.RegNum, ob.RegNum); - build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return meta; } @@ -8874,7 +8874,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build) op.Free(build); } ExpEmit to(build, REGT_POINTER); - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); return to; } @@ -8946,7 +8946,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) build->Emit(OP_LKP, to.RegNum, op.RegNum); op = to; } - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return to; } @@ -10683,8 +10683,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) case REGT_POINTER: { - bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))); - build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC)); + build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ValueType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC)); break; } case REGT_STRING: @@ -10824,7 +10823,7 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) { TArray cvalues; for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetPointer()); - StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC); + StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC); break; } } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8786a31bf..97f6ae10b 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1141,19 +1141,8 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) DEFINE_ACTION_FUNCTION(FStringStruct, Mid) { PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(ipos); - PARAM_INT(ilen); - // validate. we don't want to crash if someone passes negative values. - // with size_t it's handled naturally I think, as it's unsigned, but not in ZScript. - if (ipos < 0) ipos = 0; - if (ilen < 0) ilen = 0; - // convert to size_t to prevent overflows here - size_t slen = self->Len(); - size_t pos = (size_t)ipos; - size_t len = (size_t)ilen; - if (pos > slen) pos = slen - 1; - if (pos + len > slen) - len = slen - pos; + PARAM_UINT(pos); + PARAM_UINT(len); FString s = self->Mid(pos, len); ACTION_RETURN_STRING(s); } @@ -1161,7 +1150,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid) DEFINE_ACTION_FUNCTION(FStringStruct, Len) { PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_INT(self->Len()); + ACTION_RETURN_INT((int)self->Len()); } // CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. @@ -1169,7 +1158,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharAt) { PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_INT(pos); - int slen = self->Len(); + int slen = (int)self->Len(); if (pos < 0 || pos >= slen) ACTION_RETURN_STRING(""); ACTION_RETURN_STRING(FString((*self)[pos])); @@ -1179,7 +1168,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt) { PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_INT(pos); - int slen = self->Len(); + int slen = (int)self->Len(); if (pos < 0 || pos >= slen) ACTION_RETURN_INT(0); ACTION_RETURN_INT((*self)[pos]); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 1a5c10b4e..8b8e3c864 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -997,6 +997,7 @@ void NullParam(const char *varname); // For required parameters. #define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; +#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i; #define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i; #define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i); #define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; @@ -1040,6 +1041,7 @@ void NullParam(const char *varname); #define PARAM_PROLOGUE int paramnum = -1; #define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x) +#define PARAM_UINT(x) ++paramnum; PARAM_UINT_AT(paramnum,x) #define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x) #define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x) #define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 38dbbc411..b9f8e81ca 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -347,6 +347,17 @@ begin: GETADDR(PA,RC,X_WRITE_NIL); *(void **)ptr = reg.a[B]; NEXTOP; + OP(SO): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; + OP(SO_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; OP(SV2): ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 3fc3d7643..7128f1e43 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -70,6 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string xx(SS_R, ss, RPRSRI, NOP, 0, 0), xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer xx(SP_R, sp, RPRPRI, NOP, 0, 0), +xx(SO, sp, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types +xx(SO_R, sp, RPRPRI, NOP, 0, 0), xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2 xx(SV2_R, sv2, RPRVRI, NOP, 0, 0), xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3 From 776509e68aa696d4fba125c646c760f1ad8dc50d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 18:12:38 +0100 Subject: [PATCH 23/50] - let skip_super use the AActor assignment operator. The blanket memcpy it used was clobbering some data. - moved the Finalize method from PClassActor to AActor. Now that defaults get their vtbl pointer initialized this will actually work. --- src/actor.h | 1 + src/g_inventory/a_pickups.cpp | 4 ++-- src/g_inventory/a_pickups.h | 1 + src/g_inventory/a_weapons.cpp | 3 ++- src/g_inventory/a_weapons.h | 4 ++-- src/info.cpp | 8 ++++---- src/info.h | 1 - src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 15 +-------------- 10 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/actor.h b/src/actor.h index 05b1aa076..4016d447b 100644 --- a/src/actor.h +++ b/src/actor.h @@ -596,6 +596,7 @@ public: AActor &operator= (const AActor &other); ~AActor (); + virtual void Finalize(FStateDefinitions &statedef); virtual void OnDestroy() override; virtual void Serialize(FSerializer &arc) override; virtual void PostSerialize() override; diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index fc35d2da4..66f51e92e 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -73,10 +73,10 @@ size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass return changed; } -void PClassInventory::Finalize(FStateDefinitions &statedef) +void AInventory::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); - ((AActor*)Defaults)->flags |= MF_SPECIAL; + flags |= MF_SPECIAL; } IMPLEMENT_CLASS(AInventory, false, true) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 7ca317397..be6280c0a 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -72,6 +72,7 @@ class AInventory : public AActor HAS_OBJECT_POINTERS public: + virtual void Finalize(FStateDefinitions &statedef) override; virtual void Serialize(FSerializer &arc) override; virtual void MarkPrecacheSounds() const override; virtual void OnDestroy() override; diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 24661dfd1..7c2a0fb81 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -155,13 +155,14 @@ void PClassWeapon::DeriveData(PClass *newclass) // //=========================================================================== -void PClassWeapon::Finalize(FStateDefinitions &statedef) +void AWeapon::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); FState *ready = FindState(NAME_Ready); FState *select = FindState(NAME_Select); FState *deselect = FindState(NAME_Deselect); FState *fire = FindState(NAME_Fire); + auto TypeName = GetClass()->TypeName; // Consider any weapon without any valid state abstract and don't output a warning // This is for creating base classes for weapon groups that only set up some properties. diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 21eaf9b89..b2eeaf951 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -94,7 +94,6 @@ protected: virtual void DeriveData(PClass *newclass); public: PClassWeapon(); - void Finalize(FStateDefinitions &statedef); int SlotNumber; int SlotPriority; @@ -135,7 +134,8 @@ public: virtual void MarkPrecacheSounds() const; - virtual void Serialize(FSerializer &arc) override; + void Finalize(FStateDefinitions &statedef) override; + void Serialize(FSerializer &arc) override; void PostMorphWeapon(); diff --git a/src/info.cpp b/src/info.cpp index a424c890f..c86486b5e 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -429,20 +429,20 @@ void PClassActor::SetDropItems(DDropItem *drops) // //========================================================================== -void PClassActor::Finalize(FStateDefinitions &statedef) +void AActor::Finalize(FStateDefinitions &statedef) { - AActor *defaults = (AActor*)Defaults; + AActor *defaults = this; try { - statedef.FinishStates(this, defaults); + statedef.FinishStates(GetClass(), defaults); } catch (CRecoverableError &) { statedef.MakeStateDefines(NULL); throw; } - statedef.InstallStates(this, defaults); + statedef.InstallStates(GetClass(), defaults); statedef.MakeStateDefines(NULL); } diff --git a/src/info.h b/src/info.h index 4a6baa671..3a20994f5 100644 --- a/src/info.h +++ b/src/info.h @@ -259,7 +259,6 @@ public: size_t PropagateMark(); bool SetReplacement(FName replaceName); void SetDropItems(DDropItem *drops); - virtual void Finalize(FStateDefinitions &statedef); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 505585937..fc411186a 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1155,7 +1155,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns) } try { - info->Finalize(bag.statedef); + GetDefaultByType(info)->Finalize(bag.statedef); } catch (CRecoverableError &err) { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 682300147..4822a27b3 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -560,7 +560,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) return; } - memcpy ((void *)defaults, (void *)GetDefault(), sizeof(AActor)); + *defaults = *GetDefault(); ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 44428ab88..93f41746f 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2447,19 +2447,6 @@ void ZCCCompiler::CompileStates() continue; } - // Same here, hack in the DVMObject as they weren't in the list originally - // TODO: process them in a non hackish way obviously - if (c->Type()->bRuntimeClass == true && c->Type()->ParentClass->bRuntimeClass == false) - { - auto vmtype = static_cast(c->Type()->ParentClass); - if (vmtype->StateList == nullptr) - { - FStateDefinitions vmstates; - vmstates.MakeStateDefines(dyn_cast(vmtype->ParentClass)); - vmtype->Finalize(vmstates); - } - } - FString statename; // The state builder wants the label as one complete string, not separated into tokens. FStateDefinitions statedef; statedef.MakeStateDefines(dyn_cast(c->Type()->ParentClass)); @@ -2658,7 +2645,7 @@ void ZCCCompiler::CompileStates() } try { - static_cast(c->Type())->Finalize(statedef); + GetDefaultByType(c->Type())->Finalize(statedef); } catch (CRecoverableError &err) { From 7ed554158c98cebe56c1d3a29a1138147546962f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 19:02:27 +0100 Subject: [PATCH 24/50] - got rid of PClassWeapon. Still 5 subclasses of PClass left... --- src/d_net.cpp | 6 +- src/dobject.h | 1 - src/dobjtype.cpp | 8 +- src/fragglescript/t_func.cpp | 10 +- src/g_inventory/a_weapons.cpp | 199 +++++++++----------- src/g_inventory/a_weapons.h | 41 ++-- src/scripting/thingdef_properties.cpp | 6 +- wadsrc/static/zscript/inventory/weapons.txt | 2 + 8 files changed, 118 insertions(+), 155 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 93f6a621b..c38a7cefe 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2638,7 +2638,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } for(i = 0; i < count; ++i) { - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer); } } @@ -2647,7 +2647,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } break; @@ -2655,7 +2655,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOTDEFAULT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; diff --git a/src/dobject.h b/src/dobject.h index 6b9b87c75..1a7afaea0 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -94,7 +94,6 @@ enum CLASSREG_PClass, CLASSREG_PClassActor, CLASSREG_PClassInventory, - CLASSREG_PClassWeapon, CLASSREG_PClassPlayerPawn, CLASSREG_PClassType, CLASSREG_PClassClass, diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 034510ff9..d5653fc6d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3030,6 +3030,13 @@ void PClass::StaticShutdown () FlatpointerArena.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(); @@ -3129,7 +3136,6 @@ PClass *ClassReg::RegisterClass() &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, &PClassInventory::RegistrationInfo, - &PClassWeapon::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, &PClassType::RegistrationInfo, &PClassClass::RegistrationInfo, diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 20b53c8fd..0ee391e21 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2675,8 +2675,8 @@ void FParser::SF_PlayerWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2686,7 +2686,7 @@ void FParser::SF_PlayerWeapon() { AActor * wp = players[playernum].mo->FindInventory(ti); t_return.type = svt_int; - t_return.value.i = wp!=NULL;; + t_return.value.i = wp!=NULL; return; } else @@ -2756,8 +2756,8 @@ void FParser::SF_PlayerSelectedWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 7c2a0fb81..a916531be 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -113,42 +113,11 @@ FString WeaponSection; TArray KeyConfWeapons; FWeaponSlots *PlayingKeyConf; -TArray Weapons_ntoh; -TMap Weapons_hton; +TArray Weapons_ntoh; +TMap Weapons_hton; static int ntoh_cmp(const void *a, const void *b); -IMPLEMENT_CLASS(PClassWeapon, false, false) - -//=========================================================================== -// -// -// -//=========================================================================== - -PClassWeapon::PClassWeapon() -{ - SlotNumber = -1; - SlotPriority = INT_MAX; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassWeapon::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - Super::DeriveData(newclass); - PClassWeapon *newc = static_cast(newclass); - - newc->SlotNumber = SlotNumber; - newc->SlotPriority = SlotPriority; -} - - //=========================================================================== // // @@ -273,7 +242,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am bool gotSome = CheckAmmo (PrimaryFire, false) || CheckAmmo (AltFire, false); if (!gotSome && autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return gotSome; } @@ -282,10 +251,10 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { return true; } - count1 = (Ammo1 != NULL) ? Ammo1->Amount : 0; - count2 = (Ammo2 != NULL) ? Ammo2->Amount : 0; + count1 = (Ammo1 != nullptr) ? Ammo1->Amount : 0; + count2 = (Ammo2 != nullptr) ? Ammo2->Amount : 0; - if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == NULL)) + if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == nullptr)) { lAmmoUse1 = 0; } @@ -307,7 +276,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { enoughmask = 1 << altFire; } - if (altFire && FindState(NAME_AltFire) == NULL) + if (altFire && FindState(NAME_AltFire) == nullptr) { // If this weapon has no alternate fire, then there is never enough ammo for it enough &= 1; } @@ -318,7 +287,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am // out of ammo, pick a weapon to change to if (autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return false; } @@ -353,7 +322,7 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) } if (!altFire) { - if (Ammo1 != NULL) + if (Ammo1 != nullptr) { if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO)) { @@ -364,25 +333,25 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) Ammo1->Amount -= AmmoUse1; } } - if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != NULL) + if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } } else { - if (Ammo2 != NULL) + if (Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } - if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != NULL) + if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != nullptr) { Ammo1->Amount -= AmmoUse1; } } - if (Ammo1 != NULL && Ammo1->Amount < 0) + if (Ammo1 != nullptr && Ammo1->Amount < 0) Ammo1->Amount = 0; - if (Ammo2 != NULL && Ammo2->Amount < 0) + if (Ammo2 != nullptr && Ammo2->Amount < 0) Ammo2->Amount = 0; } return true; @@ -547,14 +516,14 @@ FState *AWeapon::GetStateForButtonName (FName button) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon(static_cast(PClass::FindClass(type))); + return AddWeapon(static_cast(PClass::FindClass(type))); } -bool FWeaponSlot::AddWeapon(PClassWeapon *type) +bool FWeaponSlot::AddWeapon(PClassActor *type) { unsigned int i; - if (type == NULL) + if (type == nullptr) { return false; } @@ -595,10 +564,10 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) Clear(); } tok = strtok(buff, " "); - while (tok != NULL) + while (tok != nullptr) { AddWeapon(tok); - tok = strtok(NULL, " "); + tok = strtok(nullptr, " "); } } @@ -611,7 +580,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) // //=========================================================================== -int FWeaponSlot::LocateWeapon(PClassWeapon *type) +int FWeaponSlot::LocateWeapon(PClassActor *type) { unsigned int i; @@ -642,22 +611,22 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { int i, j; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } // Does this slot even have any weapons? if (Weapons.Size() == 0) { return player->ReadyWeapon; } - if (player->ReadyWeapon != NULL) + if (player->ReadyWeapon != nullptr) { for (i = 0; (unsigned)i < Weapons.Size(); i++) { if (Weapons[i].Type == player->ReadyWeapon->GetClass() || (player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP && - player->ReadyWeapon->SisterWeapon != NULL && + player->ReadyWeapon->SisterWeapon != nullptr && player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type)) { for (j = (i == 0 ? Weapons.Size() - 1 : i - 1); @@ -666,7 +635,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[j].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -681,7 +650,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[i].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -737,7 +706,7 @@ void FWeaponSlot::Sort() for (i = 1; i < (int)Weapons.Size(); ++i) { int pos = Weapons[i].Position; - PClassWeapon *type = Weapons[i].Type; + PClassActor *type = Weapons[i].Type; for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j) { Weapons[j + 1] = Weapons[j]; @@ -786,7 +755,7 @@ void FWeaponSlots::Clear() // //=========================================================================== -ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) +ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type) { int currSlot, index; @@ -811,7 +780,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) // //=========================================================================== -bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const index) +bool FWeaponSlots::LocateWeapon (PClassActor *type, int *const slot, int *const index) { int i, j; @@ -820,8 +789,8 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const j = Slots[i].LocateWeapon(type); if (j >= 0) { - if (slot != NULL) *slot = i; - if (index != NULL) *index = j; + if (slot != nullptr) *slot = i; + if (index != nullptr) *index = j; return true; } } @@ -858,14 +827,14 @@ static bool FindMostRecentWeapon(player_t *player, int *slot, int *index) { return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index); } - else if (player->ReadyWeapon != NULL) + else if (player->ReadyWeapon != nullptr) { AWeapon *weap = player->ReadyWeapon; if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index)) { // If the current weapon wasn't found and is powered up, // look for its non-powered up version. - if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != NULL) + if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != nullptr) { return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index); } @@ -894,16 +863,16 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon(player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon(player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = NUM_WEAPON_SLOTS - 1; startindex = Slots[startslot].Size() - 1; @@ -922,9 +891,9 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -949,16 +918,16 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon (player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon (player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = 0; startindex = 0; @@ -977,9 +946,9 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -1011,23 +980,23 @@ void FWeaponSlots::AddExtraWeapons() // Append extra weapons to the slots. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClassActor::AllActorClasses[i]; + PClassActor *cls = PClassActor::AllActorClasses[i]; if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { continue; } - PClassWeapon *acls = static_cast(cls); - if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && - acls->Replacement == NULL && // Replaced weapons don't get slotted. - !(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) && - !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. + auto weapdef = ((AWeapon*)GetDefaultByType(cls)); + if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) && + cls->Replacement == nullptr && // Replaced weapons don't get slotted. + !(weapdef->WeaponFlags & WIF_POWERED_UP) && + !LocateWeapon(cls, nullptr, nullptr) // Don't duplicate it if it's already present. ) { - int slot = acls->SlotNumber; + int slot = weapdef->SlotNumber; if ((unsigned)slot < NUM_WEAPON_SLOTS) { - FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority }; + FWeaponSlot::WeaponInfo info = { cls, weapdef->SlotPriority }; Slots[slot].Weapons.Push(info); } } @@ -1064,8 +1033,8 @@ void FWeaponSlots::SetFromGameInfo() { for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); j++) { - PClassWeapon *cls = dyn_cast(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j])); - if (cls == NULL) + PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]); + if (cls == nullptr) { Printf("Unknown weapon class '%s' found in default weapon slot assignments\n", gameinfo.DefaultWeaponSlots[i][j].GetChars()); @@ -1261,7 +1230,7 @@ CCMD (setslot) if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) { Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n"); - if (players[consoleplayer].mo != NULL) + if (players[consoleplayer].mo != nullptr) { FString config(GameConfig->GetConfigPath(false)); Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE @@ -1280,7 +1249,7 @@ CCMD (setslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->Slots[slot].Clear(); for (int i = 2; i < argv.argc(); ++i) @@ -1300,7 +1269,7 @@ CCMD (setslot) Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { - Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); + Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); } } } @@ -1311,9 +1280,9 @@ CCMD (setslot) // //=========================================================================== -void FWeaponSlots::AddSlot(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlot(int slot, PClassActor *type, bool feedback) { - if (type != NULL && !Slots[slot].AddWeapon(type) && feedback) + if (type != nullptr && !Slots[slot].AddWeapon(type) && feedback) { Printf ("Could not add %s to slot %d\n", type->TypeName.GetChars(), slot); } @@ -1329,8 +1298,8 @@ CCMD (addslot) return; } - PClassWeapon *type= dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + PClassActor *type= dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf("%s is not a weapon\n", argv[2]); return; @@ -1340,7 +1309,7 @@ CCMD (addslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlot(int(slot), type, false); } @@ -1371,9 +1340,9 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== -void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) { - if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (type != nullptr && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { switch (AddDefaultWeapon(slot, type)) { @@ -1396,7 +1365,7 @@ void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) CCMD (addslotdefault) { - PClassWeapon *type; + PClassActor *type; unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) @@ -1405,8 +1374,8 @@ CCMD (addslotdefault) return; } - type = dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + type = dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf ("%s is not a weapon\n", argv[2]); return; @@ -1416,7 +1385,7 @@ CCMD (addslotdefault) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlotDefault(int(slot), type, false); } @@ -1444,7 +1413,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) FString cmd(KeyConfWeapons[i]); AddCommandString(cmd.LockBuffer()); } - PlayingKeyConf = NULL; + PlayingKeyConf = nullptr; } //=========================================================================== @@ -1461,20 +1430,20 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) void P_SetupWeapons_ntohton() { unsigned int i; - PClassWeapon *cls; + PClassActor *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); - cls = NULL; - Weapons_ntoh.Push(cls); // Index 0 is always NULL. + cls = nullptr; + Weapons_ntoh.Push(cls); // Index 0 is always nullptr. for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - Weapons_ntoh.Push(static_cast(cls)); + Weapons_ntoh.Push(static_cast(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); @@ -1500,8 +1469,8 @@ void P_SetupWeapons_ntohton() static int ntoh_cmp(const void *a, const void *b) { - PClassWeapon *c1 = *(PClassWeapon **)a; - PClassWeapon *c2 = *(PClassWeapon **)b; + PClassActor *c1 = *(PClassActor **)a; + PClassActor *c2 = *(PClassActor **)b; int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2; int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) @@ -1541,24 +1510,24 @@ void P_WriteDemoWeaponsChunk(BYTE **demo) void P_ReadDemoWeaponsChunk(BYTE **demo) { int count, i; - PClassWeapon *type; + PClassActor *type; const char *s; count = ReadWord(demo); Weapons_ntoh.Resize(count); Weapons_hton.Clear(count); - Weapons_ntoh[0] = type = NULL; + Weapons_ntoh[0] = type = nullptr; Weapons_hton[type] = 0; for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = dyn_cast(PClass::FindClass(s)); + type = dyn_cast(PClass::FindClass(s)); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; - if (type != NULL) + if (type != nullptr) { Weapons_hton[type] = i; } @@ -1571,12 +1540,12 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) // //=========================================================================== -void Net_WriteWeapon(PClassWeapon *type) +void Net_WriteWeapon(PClassActor *type) { int index, *index_p; index_p = Weapons_hton.CheckKey(type); - if (index_p == NULL) + if (index_p == nullptr) { index = 0; } @@ -1603,7 +1572,7 @@ void Net_WriteWeapon(PClassWeapon *type) // //=========================================================================== -PClassWeapon *Net_ReadWeapon(BYTE **stream) +PClassActor *Net_ReadWeapon(BYTE **stream) { int index; @@ -1614,7 +1583,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream) } if ((unsigned)index >= Weapons_ntoh.Size()) { - return NULL; + return nullptr; } return Weapons_ntoh[index]; } diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index b2eeaf951..50862bc47 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -1,7 +1,7 @@ #pragma once #include "a_pickups.h" -class PClassWeapon; +class PClassActor; class AWeapon; class FWeaponSlot @@ -12,13 +12,13 @@ public: FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } void Clear() { Weapons.Clear(); } bool AddWeapon (const char *type); - bool AddWeapon (PClassWeapon *type); + bool AddWeapon (PClassActor *type); void AddWeaponList (const char *list, bool clear); AWeapon *PickWeapon (player_t *player, bool checkammo = false); int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (PClassWeapon *type); + int LocateWeapon (PClassActor *type); - inline PClassWeapon *GetWeapon (int index) const + inline PClassActor *GetWeapon (int index) const { if ((unsigned)index < Weapons.Size()) { @@ -35,7 +35,7 @@ public: private: struct WeaponInfo { - PClassWeapon *Type; + PClassActor *Type; int Position; }; void SetInitialPositions(); @@ -61,8 +61,8 @@ struct FWeaponSlots AWeapon *PickPrevWeapon (player_t *player); void Clear (); - bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); + bool LocateWeapon (PClassActor *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassActor *type); void AddExtraWeapons(); void SetFromGameInfo(); void SetFromPlayer(PClassPlayerPawn *type); @@ -72,36 +72,23 @@ struct FWeaponSlots int RestoreSlots (FConfigFile *config, const char *section); void PrintSettings(); - void AddSlot(int slot, PClassWeapon *type, bool feedback); - void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); + void AddSlot(int slot, PClassActor *type, bool feedback); + void AddSlotDefault(int slot, PClassActor *type, bool feedback); }; void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(PClassWeapon *type); -PClassWeapon *Net_ReadWeapon(BYTE **stream); +void Net_WriteWeapon(PClassActor *type); +PClassActor *Net_ReadWeapon(BYTE **stream); void P_SetupWeapons_ntohton(); void P_WriteDemoWeaponsChunk(BYTE **demo); void P_ReadDemoWeaponsChunk(BYTE **demo); -// A weapon is just that. -class PClassWeapon : public PClassInventory -{ - DECLARE_CLASS(PClassWeapon, PClassInventory); -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassWeapon(); - - int SlotNumber; - int SlotPriority; -}; - class AWeapon : public AStateProvider { - DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) + DECLARE_CLASS(AWeapon, AStateProvider) HAS_OBJECT_POINTERS public: DWORD WeaponFlags; @@ -112,7 +99,7 @@ public: int Kickback; float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one + PClassActor *SisterWeaponType; // Another weapon to pick up with this one PClassActor *ProjectileType; // Projectile used by primary attack PClassActor *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first @@ -122,6 +109,8 @@ public: int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + int SlotNumber; + int SlotPriority; // In-inventory instance variables TObjPtr Ammo1, Ammo2; diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 4822a27b3..859ccb3f5 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2065,8 +2065,7 @@ DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon) DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) { PROP_INT_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotNumber = i; + defaults->SlotNumber = i; } //========================================================================== @@ -2075,8 +2074,7 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotPriority = int(i*65536); + defaults->SlotPriority = int(i*65536); } //========================================================================== diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index 5634c4c49..7bda52e52 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -43,6 +43,8 @@ class Weapon : StateProvider native Weapon.BobSpeed 1.0; Weapon.BobRangeX 1.0; Weapon.BobRangeY 1.0; + Weapon.SlotNumber -1; + Weapon.SlotPriority 32767; +WEAPONSPAWN DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; } From e3d07bddabfee6f6d13badbeb8baeb403c01a7f3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 20:25:52 +0100 Subject: [PATCH 25/50] - moved the TypeTableType pointer from PClassType to PType. Removing this variable is needed to remove PClassType and PClassClass as the next step to eliminate all of PClass's subclasses in order to clean up the type system. --- src/dobjtype.cpp | 97 ++++++++++++++---------------------------------- src/dobjtype.h | 4 +- 2 files changed, 29 insertions(+), 72 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index d5653fc6d..0e7a5e304 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -162,23 +162,9 @@ IMPLEMENT_CLASS(PClassType, false, false) //========================================================================== PClassType::PClassType() -: TypeTableType(nullptr) { } -//========================================================================== -// -// PClassType :: DeriveData -// -//========================================================================== - -void PClassType::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); - Super::DeriveData(newclass); - static_cast(newclass)->TypeTableType = TypeTableType; -} - /* PClassClass ************************************************************/ IMPLEMENT_CLASS(PClassClass, false, false) @@ -187,14 +173,10 @@ IMPLEMENT_CLASS(PClassClass, false, false) // // PClassClass Constructor // -// The only thing we want to do here is automatically set TypeTableType -// to PClass. -// //========================================================================== PClassClass::PClassClass() { - TypeTableType = RUNTIME_CLASS(PClass); } /* PType ******************************************************************/ @@ -383,40 +365,10 @@ const char *PType::DescriptiveName() const // // PType :: StaticInit STATIC // -// Set up TypeTableType values for every PType child and create basic types. -// //========================================================================== void PType::StaticInit() { - // Add types to the global symbol table. - - // Set up TypeTable hash keys. - RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); - RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); - RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); - RUNTIME_CLASS(PBool)->TypeTableType = RUNTIME_CLASS(PBool); - RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); - RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); - RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); - RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); - RUNTIME_CLASS(PSpriteID)->TypeTableType = RUNTIME_CLASS(PSpriteID); - RUNTIME_CLASS(PTextureID)->TypeTableType = RUNTIME_CLASS(PTextureID); - RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); - RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); - RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); - RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); - RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); - RUNTIME_CLASS(PResizableArray)->TypeTableType = RUNTIME_CLASS(PResizableArray); - RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); - RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); - RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); - RUNTIME_CLASS(PNativeStruct)->TypeTableType = RUNTIME_CLASS(PNativeStruct); - RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); - RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); - RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); - RUNTIME_CLASS(PStateLabel)->TypeTableType = RUNTIME_CLASS(PStateLabel); - // Create types and add them type the type table. TypeTable.AddType(TypeError = new PErrorType); TypeTable.AddType(TypeAuto = new PErrorType(2)); @@ -1503,13 +1455,18 @@ void PPointer::SetPointer(void *base, unsigned offset, TArray *special) void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - ar(key, *(PClass **)addr); - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - ar(key, *(DObject **)addr); + auto pt = static_cast(PointedType); + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ar(key, *(PClass **)addr); + } + else + { + ar(key, *(DObject **)addr); + } } else { @@ -1526,16 +1483,19 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - bool res = false; - ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); - return res; - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - bool res = false; - ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + auto pt = static_cast(PointedType); + bool res = true; + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); + } + else + { + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + } return res; } return false; @@ -3071,8 +3031,6 @@ void PClass::StaticBootstrap() // The PClassClass constructor initialized these to nullptr, because the // PClass metadata had not been created yet. Now it has, so we know what // they should be and can insert them into the type table successfully. - clscls->TypeTableType = cls; - cls->TypeTableType = cls; clscls->InsertIntoHash(); cls->InsertIntoHash(); @@ -3794,7 +3752,7 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si } for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) { - if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + if (type->TypeTableType == metatype && type->IsMatch(parm1, parm2)) { return type; } @@ -3837,10 +3795,10 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t { #ifdef _DEBUG size_t bucketcheck; - assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); assert(FindType(metatype, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); assert(bucketcheck == bucket && "Passed bucket was wrong"); #endif + type->TypeTableType = metatype; type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; GC::WriteBarrier(type); @@ -3854,11 +3812,12 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t void FTypeTable::AddType(PType *type) { - PClass *metatype; intptr_t parm1, parm2; size_t bucket; - metatype = type->GetClass()->TypeTableType; + // Type table stuff id only needed to let all classes hash to the same group. For all other types this is pointless. + type->TypeTableType = type->GetClass(); + PClass *metatype = type->TypeTableType; type->GetTypeIDs(parm1, parm2); bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; assert(FindType(metatype, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); diff --git a/src/dobjtype.h b/src/dobjtype.h index 3e204da62..02877a4ec 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -215,6 +215,7 @@ public: typedef PClassType MetaClass; MetaClass *GetClass() const; + PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment PType *HashNext; // next type in this type table @@ -875,9 +876,6 @@ class PClassType : public PClass protected: public: PClassType(); - virtual void DeriveData(PClass *newclass); - - PClass *TypeTableType; // The type to use for hashing into the type table }; inline PType::MetaClass *PType::GetClass() const From 3cddcc852445bc72dc2216950cb5a8d62abd0f13 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 20:45:56 +0100 Subject: [PATCH 26/50] - removed PClassType and PClassClass. All non-actors now use PClass exclusively as their type descriptor. Getting rid of these two classes already removes a lot of obtuse code from the type system, but there's still three more classes to go before a major cleanup can be undertaken. --- src/dobject.h | 2 -- src/dobjtype.cpp | 41 +---------------------------------------- src/dobjtype.h | 39 --------------------------------------- 3 files changed, 1 insertion(+), 81 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 1a7afaea0..ef7560909 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -95,8 +95,6 @@ enum CLASSREG_PClassActor, CLASSREG_PClassInventory, CLASSREG_PClassPlayerPawn, - CLASSREG_PClassType, - CLASSREG_PClassClass, }; struct ClassReg diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 0e7a5e304..54cc64675 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -151,34 +151,6 @@ void DumpTypeTable() Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); } -/* PClassType *************************************************************/ - -IMPLEMENT_CLASS(PClassType, false, false) - -//========================================================================== -// -// PClassType Constructor -// -//========================================================================== - -PClassType::PClassType() -{ -} - -/* PClassClass ************************************************************/ - -IMPLEMENT_CLASS(PClassClass, false, false) - -//========================================================================== -// -// PClassClass Constructor -// -//========================================================================== - -PClassClass::PClassClass() -{ -} - /* PType ******************************************************************/ IMPLEMENT_CLASS(PType, true, true) @@ -3014,28 +2986,19 @@ void PClass::StaticShutdown () // // PClass :: StaticBootstrap STATIC // -// PClass and PClassClass have intermingling dependencies on their -// definitions. To sort this out, we explicitly define them before -// proceeding with the RegisterClass loop in StaticInit(). -// //========================================================================== void PClass::StaticBootstrap() { - PClassClass *clscls = new PClassClass; - PClassClass::RegistrationInfo.SetupClass(clscls); - - PClassClass *cls = new PClassClass; + PClass *cls = new PClass; PClass::RegistrationInfo.SetupClass(cls); // The PClassClass constructor initialized these to nullptr, because the // PClass metadata had not been created yet. Now it has, so we know what // they should be and can insert them into the type table successfully. - clscls->InsertIntoHash(); cls->InsertIntoHash(); // Create parent objects before we go so that these definitions are complete. - clscls->ParentClass = PClassType::RegistrationInfo.ParentType->RegisterClass(); cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); } @@ -3095,8 +3058,6 @@ PClass *ClassReg::RegisterClass() &PClassActor::RegistrationInfo, &PClassInventory::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, - &PClassType::RegistrationInfo, - &PClassClass::RegistrationInfo, }; // Skip classes that have already been registered diff --git a/src/dobjtype.h b/src/dobjtype.h index 02877a4ec..3858585e9 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -199,22 +199,13 @@ public: // Prototype *+ *+ struct ZCC_ExprConstant; -class PClassType; class PType : public PTypeBase { - //DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType); - // We need to unravel the _WITH_META macro, since PClassType isn't defined yet, - // and we can't define it until we've defined PClass. But we can't define that - // without defining PType. DECLARE_ABSTRACT_CLASS(PType, PTypeBase) HAS_OBJECT_POINTERS; protected: - enum { MetaClassNum = CLASSREG_PClassType }; public: - typedef PClassType MetaClass; - MetaClass *GetClass() const; - PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment @@ -777,22 +768,17 @@ enum TentativeClass = UINT_MAX, }; -class PClassClass; class PClass : public PNativeStruct { DECLARE_CLASS(PClass, PNativeStruct); HAS_OBJECT_POINTERS; protected: // We unravel _WITH_META here just as we did for PType. - enum { MetaClassNum = CLASSREG_PClassClass }; TArray SpecialInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr, void *defaults) const; void SetSuper(); public: - typedef PClassClass MetaClass; - MetaClass *GetClass() const; - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; void WriteAllFields(FSerializer &ar, const void *addr) const; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -870,31 +856,6 @@ public: static bool bVMOperational; }; -class PClassType : public PClass -{ - DECLARE_CLASS(PClassType, PClass); -protected: -public: - PClassType(); -}; - -inline PType::MetaClass *PType::GetClass() const -{ - return static_cast(DObject::GetClass()); -} - -class PClassClass : public PClassType -{ - DECLARE_CLASS(PClassClass, PClassType); -public: - PClassClass(); -}; - -inline PClass::MetaClass *PClass::GetClass() const -{ - return static_cast(DObject::GetClass()); -} - // Type tables -------------------------------------------------------------- struct FTypeTable From 3cbd62479b827a69d59f15cee7ea1c614c9d533e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 11:13:41 +0100 Subject: [PATCH 27/50] - took VMFunction out of the DObject hierarchy. As it stood, just compiling the internal ZScript code created more than 9000 DObjects, none of which really need to be subjected to garbage collection, aside from allowing lazy deallocation. This puts an incredible drag on the garbage collector which often needs several minutes to finish processing before actual deletion can start. The VM functions with roughly 1800 of these objects were by far the easiest to refactor so they are now. They also use a memory arena now which significantly reduces their memory footprint. --- src/dobjgc.cpp | 20 ++++++++------------ src/dobjtype.cpp | 2 +- src/info.cpp | 26 -------------------------- src/info.h | 1 - src/memarena.cpp | 20 ++++++++++++++++++++ src/memarena.h | 1 + src/scripting/vm/vm.h | 33 ++++++++++++++++++++++++++------- src/scripting/vm/vmframe.cpp | 29 +++-------------------------- 8 files changed, 59 insertions(+), 73 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index df1760dd7..5b6a34bdc 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -361,17 +361,6 @@ static void MarkRoot() } Mark(SectorMarker); Mark(interpolator.Head); - // Mark action functions - if (!FinalGC) - { - FAutoSegIterator probe(ARegHead, ARegTail); - - while (*++probe != NULL) - { - AFuncDesc *afunc = (AFuncDesc *)*probe; - Mark(*(afunc->VMPointer)); - } - } // Mark types TypeTable.Mark(); for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) @@ -776,7 +765,7 @@ CCMD(gc) { if (argv.argc() == 1) { - Printf ("Usage: gc stop|now|full|pause [size]|stepmul [size]\n"); + Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n"); return; } if (stricmp(argv[1], "stop") == 0) @@ -791,6 +780,12 @@ CCMD(gc) { GC::FullGC(); } + else if (stricmp(argv[1], "count") == 0) + { + int cnt = 0; + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++) + Printf("%d active objects counted\n", cnt); + } else if (stricmp(argv[1], "pause") == 0) { if (argv.argc() == 2) @@ -814,3 +809,4 @@ CCMD(gc) } } } + diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 54cc64675..6dc4483a0 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2698,7 +2698,6 @@ size_t PFunction::PropagateMark() for (unsigned i = 0; i < Variants.Size(); ++i) { GC::Mark(Variants[i].Proto); - GC::Mark(Variants[i].Implementation); } return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); } @@ -2947,6 +2946,7 @@ void PClass::StaticShutdown () *p = nullptr; } FunctionPtrList.Clear(); + VMFunction::DeleteAll(); // Make a full garbage collection here so that all destroyed but uncollected higher level objects // that still exist are properly taken down before the low level data is deleted. diff --git a/src/info.cpp b/src/info.cpp index c86486b5e..18eecc2d1 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -351,32 +351,6 @@ void PClassActor::DeriveData(PClass *newclass) } -//========================================================================== -// -// PClassActor :: PropagateMark -// -//========================================================================== - -size_t PClassActor::PropagateMark() -{ - // Mark state functions - for (int i = 0; i < NumOwnedStates; ++i) - { - if (OwnedStates[i].ActionFunc != NULL) - { - GC::Mark(OwnedStates[i].ActionFunc); - } - } - // Mark damage function - if (Defaults != NULL) - { - GC::Mark(((AActor *)Defaults)->DamageFunc); - } - -// marked += ActorInfo->NumOwnedStates * sizeof(FState); - return Super::PropagateMark(); -} - //========================================================================== // // PClassActor :: SetReplacement diff --git a/src/info.h b/src/info.h index 3a20994f5..64be2d92f 100644 --- a/src/info.h +++ b/src/info.h @@ -256,7 +256,6 @@ public: void RegisterIDs(); void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); - size_t PropagateMark(); bool SetReplacement(FName replaceName); void SetDropItems(DDropItem *drops); diff --git a/src/memarena.cpp b/src/memarena.cpp index 8ea8b5806..af9f91547 100644 --- a/src/memarena.cpp +++ b/src/memarena.cpp @@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks() FreeBlockChain(FreeBlocks); } +//========================================================================== +// +// FMemArena :: DumpInfo +// +// Prints some info about this arena +// +//========================================================================== + +void FMemArena::DumpInfo() +{ + size_t allocated = 0; + size_t used = 0; + for (auto block = TopBlock; block != NULL; block = block->NextBlock) + { + allocated += BlockSize; + used += BlockSize - ((char*)block->Limit - (char*)block->Avail); + } + Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used); +} + //========================================================================== // // FMemArena :: FreeBlockChain diff --git a/src/memarena.h b/src/memarena.h index 3601469bf..14b735eda 100644 --- a/src/memarena.h +++ b/src/memarena.h @@ -46,6 +46,7 @@ public: void *Alloc(size_t size); void FreeAll(); void FreeAllBlocks(); + void DumpInfo(); protected: struct Block; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 8b8e3c864..6d758f1bc 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -6,6 +6,7 @@ #include "vectors.h" #include "cmdlib.h" #include "doomerrors.h" +#include "memarena.h" #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return #define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function @@ -693,10 +694,8 @@ do_double: if (inexact) } }; -class VMFunction : public DObject +class VMFunction { - DECLARE_ABSTRACT_CLASS(VMFunction, DObject); - HAS_OBJECT_POINTERS; public: bool Native; bool Final = false; // cannot be overridden @@ -709,7 +708,30 @@ public: class PPrototype *Proto; - VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {} + VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) + { + AllFunctions.Push(this); + } + virtual ~VMFunction() {} + + void *operator new(size_t size) + { + return Allocator.Alloc(size); + } + + void operator delete(void *block) {} + void operator delete[](void *block) {} + static void DeleteAll() + { + for (auto f : AllFunctions) + { + f->~VMFunction(); + } + AllFunctions.Clear(); + } + static FMemArena Allocator; + static TArray AllFunctions; +protected: }; // VM frame layout: @@ -838,11 +860,9 @@ struct FStatementInfo class VMScriptFunction : public VMFunction { - DECLARE_CLASS(VMScriptFunction, VMFunction); public: VMScriptFunction(FName name=NAME_None); ~VMScriptFunction(); - size_t PropagateMark(); void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } @@ -910,7 +930,6 @@ private: class VMNativeFunction : public VMFunction { - DECLARE_CLASS(VMNativeFunction, VMFunction); public: typedef int (*NativeCallType)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret); diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index c44fbb2ea..5fa82ad0c 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -42,14 +42,10 @@ cycle_t VMCycles[10]; int VMCalls[10]; IMPLEMENT_CLASS(VMException, false, false) -IMPLEMENT_CLASS(VMFunction, true, true) -IMPLEMENT_POINTERS_START(VMFunction) - IMPLEMENT_POINTER(Proto) -IMPLEMENT_POINTERS_END +FMemArena VMFunction::Allocator(32768); +TArray VMFunction::AllFunctions; -IMPLEMENT_CLASS(VMScriptFunction, false, false) -IMPLEMENT_CLASS(VMNativeFunction, false, false) VMScriptFunction::VMScriptFunction(FName name) { @@ -87,7 +83,6 @@ VMScriptFunction::~VMScriptFunction() KonstS[i].~FString(); } } - M_Free(Code); } } @@ -100,7 +95,7 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko assert(numkonsts >= 0 && numkonsts <= 65535); assert(numkonsta >= 0 && numkonsta <= 65535); assert(numlinenumbers >= 0 && numlinenumbers <= 65535); - void *mem = M_Malloc(numops * sizeof(VMOP) + + void *mem = Allocator.Alloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + @@ -166,24 +161,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko NumKonstA = numkonsta; } -size_t VMScriptFunction::PropagateMark() -{ - if (KonstA != NULL) - { - FVoidObj *konsta = KonstA; - VM_UBYTE *atag = KonstATags(); - for (int count = NumKonstA; count > 0; --count) - { - if (*atag++ == ATAG_OBJECT) - { - GC::Mark(konsta->o); - } - konsta++; - } - } - return NumKonstA * sizeof(void *) + Super::PropagateMark(); -} - void VMScriptFunction::InitExtra(void *addr) { char *caddr = (char*)addr; From f6d6f310a96d89279f2ec06910edda50b9389e06 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 11:56:12 +0100 Subject: [PATCH 28/50] - fixed comments. --- src/scripting/codegeneration/dynarrays.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/codegeneration/dynarrays.cpp index 05e18a3ca..0152c6520 100644 --- a/src/scripting/codegeneration/dynarrays.cpp +++ b/src/scripting/codegeneration/dynarrays.cpp @@ -1,10 +1,10 @@ /* ** dynarray.cpp ** -** Compiler backend / code generation for dynamic arrays +** internal data types for dynamic arrays ** **--------------------------------------------------------------------------- -** Copyright 2016 Christoph Oelckers +** Copyright 2016-2017 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without From 5a81a4ca16e27dc01991abd06dbc2425992a55e1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 12:24:08 +0100 Subject: [PATCH 29/50] - moved a few things around to have them into better fitting places. --- src/CMakeLists.txt | 16 ++++++++-------- src/d_dehacked.cpp | 2 +- src/d_main.cpp | 2 +- src/dobjgc.cpp | 2 +- src/dobjtype.cpp | 6 +----- src/dobjtype.h | 1 - .../{codegeneration => backend}/codegen.cpp | 0 .../{codegeneration => backend}/codegen.h | 0 .../{codegeneration => backend}/dynarrays.cpp | 0 src/scripting/{vm => backend}/vmbuilder.cpp | 2 +- src/scripting/{vm => backend}/vmbuilder.h | 0 src/scripting/{vm => backend}/vmdisasm.cpp | 0 src/scripting/decorate/olddecorations.cpp | 2 +- src/scripting/decorate/thingdef_exp.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/decorate/thingdef_states.cpp | 4 ++-- src/scripting/thingdef.cpp | 4 ++-- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 2 +- src/scripting/zscript/zcc_compile.h | 2 +- 20 files changed, 23 insertions(+), 28 deletions(-) rename src/scripting/{codegeneration => backend}/codegen.cpp (100%) rename src/scripting/{codegeneration => backend}/codegen.h (100%) rename src/scripting/{codegeneration => backend}/dynarrays.cpp (100%) rename src/scripting/{vm => backend}/vmbuilder.cpp (99%) rename src/scripting/{vm => backend}/vmbuilder.h (100%) rename src/scripting/{vm => backend}/vmdisasm.cpp (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 200164d7b..ce60111fa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -778,7 +778,7 @@ file( GLOB HEADER_FILES sound/*.h textures/*.h scripting/*.h - scripting/codegeneration/*.h + scripting/backend/*.h scripting/decorate/*.h scripting/zscript/*.h scripting/vm/*.h @@ -1197,14 +1197,14 @@ set (PCH_SOURCES scripting/thingdef.cpp scripting/thingdef_data.cpp scripting/thingdef_properties.cpp - scripting/codegeneration/codegen.cpp - scripting/codegeneration/dynarrays.cpp + scripting/backend/codegen.cpp + scripting/backend/dynarrays.cpp + scripting/backend/vmbuilder.cpp + scripting/backend/vmdisasm.cpp scripting/decorate/olddecorations.cpp scripting/decorate/thingdef_exp.cpp scripting/decorate/thingdef_parse.cpp scripting/decorate/thingdef_states.cpp - scripting/vm/vmbuilder.cpp - scripting/vm/vmdisasm.cpp scripting/vm/vmexec.cpp scripting/vm/vmframe.cpp scripting/zscript/ast.cpp @@ -1421,9 +1421,9 @@ source_group("Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE source_group("Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+") source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+") source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+") -source_group("Scripting\\Decorate" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+") -source_group("Scripting\\ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) -source_group("Scripting\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/codegeneration/.+") +source_group("Scripting\\Decorate frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+") +source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) +source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+") source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+") source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+") source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+") diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 7fecec550..7ad5e6344 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -73,7 +73,7 @@ #include "thingdef.h" #include "info.h" #include "v_text.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO diff --git a/src/d_main.cpp b/src/d_main.cpp index 573c19071..e91c2ccaa 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2717,7 +2717,7 @@ void D_DoomMain (void) GC::FullGC(); // clean up before taking down the object list. - // Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions. + // Delete the reference to the VM functions here which were deleted and will be recreated after the restart. FAutoSegIterator probe(ARegHead, ARegTail); while (*++probe != NULL) { diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 5b6a34bdc..ca57e6aca 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -783,7 +783,7 @@ CCMD(gc) else if (stricmp(argv[1], "count") == 0) { int cnt = 0; - for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++) + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++); Printf("%d active objects counted\n", cnt); } else if (stricmp(argv[1], "pause") == 0) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 6dc4483a0..c39e316a7 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3877,11 +3877,7 @@ IMPLEMENT_POINTERS_START(PSymbolType) IMPLEMENT_POINTER(Type) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(PSymbolVMFunction, false, true) - -IMPLEMENT_POINTERS_START(PSymbolVMFunction) - IMPLEMENT_POINTER(Function) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PSymbolVMFunction, false, false) //========================================================================== // diff --git a/src/dobjtype.h b/src/dobjtype.h index 3858585e9..6fd2f9b1d 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -84,7 +84,6 @@ struct FNamespaceManager; class PSymbolVMFunction : public PSymbol { DECLARE_CLASS(PSymbolVMFunction, PSymbol); - HAS_OBJECT_POINTERS; public: VMFunction *Function; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/backend/codegen.cpp similarity index 100% rename from src/scripting/codegeneration/codegen.cpp rename to src/scripting/backend/codegen.cpp diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/backend/codegen.h similarity index 100% rename from src/scripting/codegeneration/codegen.h rename to src/scripting/backend/codegen.h diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/backend/dynarrays.cpp similarity index 100% rename from src/scripting/codegeneration/dynarrays.cpp rename to src/scripting/backend/dynarrays.cpp diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp similarity index 99% rename from src/scripting/vm/vmbuilder.cpp rename to src/scripting/backend/vmbuilder.cpp index 19fe81c32..74f845248 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -32,7 +32,7 @@ */ #include "vmbuilder.h" -#include "codegeneration/codegen.h" +#include "codegen.h" #include "info.h" #include "m_argv.h" #include "thingdef.h" diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/backend/vmbuilder.h similarity index 100% rename from src/scripting/vm/vmbuilder.h rename to src/scripting/backend/vmbuilder.h diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/backend/vmdisasm.cpp similarity index 100% rename from src/scripting/vm/vmdisasm.cpp rename to src/scripting/backend/vmdisasm.cpp diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 5861138d6..575bbf0a4 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -47,7 +47,7 @@ #include "decallib.h" #include "i_system.h" #include "thingdef.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "r_data/r_translate.h" // TYPES ------------------------------------------------------------------- diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 2b0866dd8..6757a2382 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -49,7 +49,7 @@ #include "thingdef.h" #include "p_lnspec.h" #include "doomstat.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" FRandom pr_exrandom ("EX_Random"); diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index fc411186a..23ffc48e8 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -49,7 +49,7 @@ #include "v_palette.h" #include "doomerrors.h" #include "i_system.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "w_wad.h" #include "v_video.h" #include "version.h" diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 8e08fc038..63269eeeb 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -53,10 +53,10 @@ #include "s_sound.h" #include "i_system.h" #include "colormatcher.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "version.h" #include "templates.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" //========================================================================== //*** diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 6776e70e8..f2849eb39 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -60,9 +60,9 @@ #include "p_conversation.h" #include "v_text.h" #include "thingdef.h" -#include "codegeneration/codegen.h" +#include "backend/codegen.h" #include "a_sharedglobal.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "stats.h" // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 859ccb3f5..22d6610ce 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -66,7 +66,7 @@ #include "teaminfo.h" #include "v_video.h" #include "r_data/colormaps.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "a_keys.h" #include "g_levellocals.h" diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 93f41746f..4972e1344 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -48,7 +48,7 @@ #include "p_lnspec.h" #include "i_system.h" #include "gdtoa.h" -#include "vmbuilder.h" +#include "backend/vmbuilder.h" #include "version.h" static int GetIntConst(FxExpression *ex, FCompileContext &ctx) diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index a14443b7d..dc5fea565 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -2,7 +2,7 @@ #define ZCC_COMPILE_H #include -#include "codegeneration/codegen.h" +#include "backend/codegen.h" struct Baggage; struct FPropertyInfo; From 18c532c3076e856dccc9c8818c53cd0be139bc75 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 13:17:25 +0100 Subject: [PATCH 30/50] - moved the compiler symbols into their own file. - removed all pointer declarations to types from the symbols. All types must be placed into the type table which means that they can be considered static. --- src/CMakeLists.txt | 1 + src/dobject.h | 1 + src/dobjtype.cpp | 288 ------------------------- src/dobjtype.h | 276 ------------------------ src/scripting/symbols.cpp | 440 ++++++++++++++++++++++++++++++++++++++ src/scripting/symbols.h | 286 +++++++++++++++++++++++++ 6 files changed, 728 insertions(+), 564 deletions(-) create mode 100644 src/scripting/symbols.cpp create mode 100644 src/scripting/symbols.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ce60111fa..d0d31984d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1194,6 +1194,7 @@ set (PCH_SOURCES r_data/voxels.cpp r_data/renderstyle.cpp r_data/r_interpolate.cpp + scripting/symbols.cpp scripting/thingdef.cpp scripting/thingdef_data.cpp scripting/thingdef_properties.cpp diff --git a/src/dobject.h b/src/dobject.h index ef7560909..6ad8ded6f 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -603,6 +603,7 @@ static inline void GC::WriteBarrier(DObject *pointed) } } +#include "symbols.h" #include "dobjtype.h" inline bool DObject::IsKindOf (const PClass *base) const diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c39e316a7..eda59bcc1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -66,7 +66,6 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. -FNamespaceManager Namespaces; FTypeTable TypeTable; TArray PClass::AllClasses; @@ -2683,68 +2682,6 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray return static_cast(proto); } -/* PFunction **************************************************************/ - -IMPLEMENT_CLASS(PFunction, false, false) - -//========================================================================== -// -// PFunction :: PropagataMark -// -//========================================================================== - -size_t PFunction::PropagateMark() -{ - for (unsigned i = 0; i < Variants.Size(); ++i) - { - GC::Mark(Variants[i].Proto); - } - return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); -} - -//========================================================================== -// -// PFunction :: AddVariant -// -// Adds a new variant for this function. Does not check if a matching -// variant already exists. -// -//========================================================================== - -unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) -{ - Variant variant; - - // I do not think we really want to deal with overloading here... - assert(Variants.Size() == 0); - - variant.Flags = flags; - variant.UseFlags = useflags; - variant.Proto = proto; - variant.ArgFlags = std::move(argflags); - variant.ArgNames = std::move(argnames); - variant.Implementation = impl; - if (impl != nullptr) impl->Proto = proto; - - // SelfClass can differ from OwningClass, but this is variant-dependent. - // Unlike the owner there can be cases where different variants can have different SelfClasses. - // (Of course only if this ever gets enabled...) - if (flags & VARF_Method) - { - assert(proto->ArgumentTypes.Size() > 0); - auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); - assert(selftypeptr != nullptr); - variant.SelfClass = dyn_cast(selftypeptr->PointedType); - assert(variant.SelfClass != nullptr); - } - else - { - variant.SelfClass = nullptr; - } - - return Variants.Push(variant); -} - /* PClass *****************************************************************/ IMPLEMENT_CLASS(PClass, false, true) @@ -3863,228 +3800,3 @@ CCMD(typetable) DumpTypeTable(); } -// Symbol tables ------------------------------------------------------------ - -IMPLEMENT_CLASS(PTypeBase, true, false); -IMPLEMENT_CLASS(PSymbol, true, false); -IMPLEMENT_CLASS(PSymbolConst, false, false); -IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); -IMPLEMENT_CLASS(PSymbolConstString, false, false); -IMPLEMENT_CLASS(PSymbolTreeNode, false, false) -IMPLEMENT_CLASS(PSymbolType, false, true) - -IMPLEMENT_POINTERS_START(PSymbolType) - IMPLEMENT_POINTER(Type) -IMPLEMENT_POINTERS_END - -IMPLEMENT_CLASS(PSymbolVMFunction, false, false) - -//========================================================================== -// -// -// -//========================================================================== - -PSymbol::~PSymbol() -{ -} - -PSymbolTable::PSymbolTable() -: ParentSymbolTable(nullptr) -{ -} - -PSymbolTable::PSymbolTable(PSymbolTable *parent) -: ParentSymbolTable(parent) -{ -} - -PSymbolTable::~PSymbolTable () -{ - ReleaseSymbols(); -} - -size_t PSymbolTable::MarkSymbols() -{ - size_t count = 0; - MapType::Iterator it(Symbols); - MapType::Pair *pair; - - while (it.NextPair(pair)) - { - GC::Mark(pair->Value); - count++; - } - return count * sizeof(*pair); -} - -void PSymbolTable::ReleaseSymbols() -{ - // The GC will take care of deleting the symbols. We just need to - // clear our references to them. - Symbols.Clear(); -} - -void PSymbolTable::SetParentTable (PSymbolTable *parent) -{ - ParentSymbolTable = parent; -} - -PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const -{ - PSymbol * const *value = Symbols.CheckKey(symname); - if (value == nullptr && searchparents && ParentSymbolTable != nullptr) - { - return ParentSymbolTable->FindSymbol(symname, searchparents); - } - return value != nullptr ? *value : nullptr; -} - -PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) -{ - PSymbol * const *value = Symbols.CheckKey(symname); - if (value == nullptr) - { - if (ParentSymbolTable != nullptr) - { - return ParentSymbolTable->FindSymbolInTable(symname, symtable); - } - symtable = nullptr; - return nullptr; - } - symtable = this; - return *value; -} - -PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) -{ - // Symbols that already exist are not inserted. - if (Symbols.CheckKey(sym->SymbolName) != nullptr) - { - return nullptr; - } - Symbols.Insert(sym->SymbolName, sym); - return sym; -} - -void PSymbolTable::RemoveSymbol(PSymbol *sym) -{ - auto mysym = Symbols.CheckKey(sym->SymbolName); - if (mysym == nullptr || *mysym != sym) return; - Symbols.Remove(sym->SymbolName); -} - -PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) -{ - // If a symbol with a matching name exists, take its place and return it. - PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); - if (symslot != nullptr) - { - PSymbol *oldsym = *symslot; - *symslot = newsym; - return oldsym; - } - // Else, just insert normally and return nullptr since there was no - // symbol to replace. - Symbols.Insert(newsym->SymbolName, newsym); - return nullptr; -} - -IMPLEMENT_CLASS(PNamespace, false, true) - -IMPLEMENT_POINTERS_START(PNamespace) -IMPLEMENT_POINTER(Parent) -IMPLEMENT_POINTERS_END - -PNamespace::PNamespace(int filenum, PNamespace *parent) -{ - Parent = parent; - if (parent) Symbols.SetParentTable(&parent->Symbols); - FileNum = filenum; -} - -size_t PNamespace::PropagateMark() -{ - GC::Mark(Parent); - return Symbols.MarkSymbols() + 1; -} - -FNamespaceManager::FNamespaceManager() -{ - GlobalNamespace = nullptr; -} - -PNamespace *FNamespaceManager::NewNamespace(int filenum) -{ - PNamespace *parent = nullptr; - // The parent will be the last namespace with this or a lower filenum. - // This ensures that DECORATE won't see the symbols of later files. - for (int i = AllNamespaces.Size() - 1; i >= 0; i--) - { - if (AllNamespaces[i]->FileNum <= filenum) - { - parent = AllNamespaces[i]; - break; - } - } - auto newns = new PNamespace(filenum, parent); - AllNamespaces.Push(newns); - return newns; -} - -size_t FNamespaceManager::MarkSymbols() -{ - for (auto ns : AllNamespaces) - { - GC::Mark(ns); - } - return AllNamespaces.Size(); -} - -void FNamespaceManager::ReleaseSymbols() -{ - GlobalNamespace = nullptr; - AllNamespaces.Clear(); -} - -// removes all symbols from the symbol tables. -// After running the compiler these are not needed anymore. -// Only the namespaces themselves are kept because the type table references them. -int FNamespaceManager::RemoveSymbols() -{ - int count = 0; - for (auto ns : AllNamespaces) - { - count += ns->Symbols.Symbols.CountUsed(); - ns->Symbols.ReleaseSymbols(); - } - return count; -} - -void RemoveUnusedSymbols() -{ - // Global symbols are not needed anymore after running the compiler. - int count = Namespaces.RemoveSymbols(); - - // We do not need any non-field and non-function symbols in structs and classes anymore. - for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) - { - for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) - { - if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) - { - auto it = ty->Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction))) - { - ty->Symbols.RemoveSymbol(pair->Value); - count++; - } - } - } - } - } - DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count); -} diff --git a/src/dobjtype.h b/src/dobjtype.h index 6fd2f9b1d..c999f3f50 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -39,36 +39,6 @@ enum VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature }; -// Symbol information ------------------------------------------------------- - -class PTypeBase : public DObject -{ - DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) - -public: - virtual FString QualifiedName() const - { - return ""; - } -}; - -class PSymbol : public PTypeBase -{ - DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase); -public: - virtual ~PSymbol(); - - virtual FString QualifiedName() const - { - return SymbolName.GetChars(); - } - - FName SymbolName; - -protected: - PSymbol(FName name) { SymbolName = name; } -}; - // An action function ------------------------------------------------------- struct FState; @@ -79,100 +49,6 @@ struct VMReturn; class VMFunction; struct FNamespaceManager; -// A VM function ------------------------------------------------------------ - -class PSymbolVMFunction : public PSymbol -{ - DECLARE_CLASS(PSymbolVMFunction, PSymbol); -public: - VMFunction *Function; - - PSymbolVMFunction(FName name) : PSymbol(name) {} - PSymbolVMFunction() : PSymbol(NAME_None) {} -}; - -// A symbol for a type ------------------------------------------------------ - -class PSymbolType : public PSymbol -{ - DECLARE_CLASS(PSymbolType, PSymbol); - HAS_OBJECT_POINTERS; -public: - class PType *Type; - - PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} - PSymbolType() : PSymbol(NAME_None) {} -}; - -// A symbol table ----------------------------------------------------------- - -struct PSymbolTable -{ - PSymbolTable(); - PSymbolTable(PSymbolTable *parent); - ~PSymbolTable(); - - size_t MarkSymbols(); - - // Sets the table to use for searches if this one doesn't contain the - // requested symbol. - void SetParentTable (PSymbolTable *parent); - PSymbolTable *GetParentTable() const - { - return ParentSymbolTable; - } - - // Finds a symbol in the table, optionally searching parent tables - // as well. - PSymbol *FindSymbol (FName symname, bool searchparents) const; - - // Like FindSymbol with searchparents set true, but also returns the - // specific symbol table the symbol was found in. - PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); - - - // Places the symbol in the table and returns a pointer to it or NULL if - // a symbol with the same name is already in the table. This symbol is - // not copied and will be freed when the symbol table is destroyed. - PSymbol *AddSymbol (PSymbol *sym); - - // Similar to AddSymbol but always succeeds. Returns the symbol that used - // to be in the table with this name, if any. - PSymbol *ReplaceSymbol(PSymbol *sym); - - void RemoveSymbol(PSymbol *sym); - - // Frees all symbols from this table. - void ReleaseSymbols(); - - typedef TMap MapType; - - MapType::Iterator GetIterator() - { - return MapType::Iterator(Symbols); - } - -private: - - PSymbolTable *ParentSymbolTable; - MapType Symbols; - - friend class DObject; - friend struct FNamespaceManager; -}; - -// A symbol for a compiler tree node ---------------------------------------- - -class PSymbolTreeNode : public PSymbol -{ - DECLARE_CLASS(PSymbolTreeNode, PSymbol); -public: - struct ZCC_TreeNode *Node; - - PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {} - PSymbolTreeNode() : PSymbol(NAME_None) {} -}; - // Basic information shared by all types ------------------------------------ // Only one copy of a type is ever instantiated at one time. @@ -536,52 +412,6 @@ public: virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; }; -// Struct/class fields ------------------------------------------------------ - -// A PField describes a symbol that takes up physical space in the struct. -class PField : public PSymbol -{ - DECLARE_CLASS(PField, PSymbol); - HAS_OBJECT_POINTERS -public: - PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0); - - size_t Offset; - PType *Type; - DWORD Flags; - int BitValue; -protected: - PField(); -}; - -// Struct/class fields ------------------------------------------------------ - -// A PField describes a symbol that takes up physical space in the struct. -class PProperty : public PSymbol -{ - DECLARE_CLASS(PProperty, PSymbol); -public: - PProperty(FName name, TArray &variables); - - TArray Variables; - -protected: - PProperty(); -}; - -class PPropFlag : public PSymbol -{ - DECLARE_CLASS(PPropFlag, PSymbol); -public: - PPropFlag(FName name, PField *offset, int bitval); - - PField *Offset; - int bitval; - -protected: - PPropFlag(); -}; - // Compound types ----------------------------------------------------------- class PEnum : public PInt @@ -729,36 +559,6 @@ protected: PPrototype(); }; -// TBD: Should we really support overloading? -class PFunction : public PSymbol -{ - DECLARE_CLASS(PFunction, PSymbol); -public: - struct Variant - { - PPrototype *Proto; - VMFunction *Implementation; - TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes - TArray ArgNames; // we need the names to access them later when the function gets compiled. - uint32_t Flags; - int UseFlags; - PStruct *SelfClass; - }; - TArray Variants; - PStruct *OwningClass = nullptr; - - unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); - int GetImplicitArgs() - { - if (Variants[0].Flags & VARF_Action) return 3; - else if (Variants[0].Flags & VARF_Method) return 1; - return 0; - } - - size_t PropagateMark(); - - PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} -}; // Meta-info for every class derived from DObject --------------------------- @@ -914,82 +714,6 @@ extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; extern PPointer *TypeVoidPtr; -// A constant value --------------------------------------------------------- - -class PSymbolConst : public PSymbol -{ - DECLARE_CLASS(PSymbolConst, PSymbol); -public: - PType *ValueType; - - PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} - PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} -}; - -// A constant numeric value ------------------------------------------------- - -class PSymbolConstNumeric : public PSymbolConst -{ - DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); -public: - union - { - int Value; - double Float; - void *Pad; - }; - - PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} - PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} - PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} - PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} - PSymbolConstNumeric() {} -}; - -// A constant string value -------------------------------------------------- - -class PSymbolConstString : public PSymbolConst -{ - DECLARE_CLASS(PSymbolConstString, PSymbolConst); -public: - FString Str; - - PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {} - PSymbolConstString() {} -}; - -// Namespaces -------------------------------------------------- - -class PNamespace : public PTypeBase -{ - DECLARE_CLASS(PNamespace, PTypeBase) - HAS_OBJECT_POINTERS; - -public: - PSymbolTable Symbols; - PNamespace *Parent; - int FileNum; // This is for blocking DECORATE access to later files. - - PNamespace() {} - PNamespace(int filenum, PNamespace *parent); - size_t PropagateMark(); -}; - -struct FNamespaceManager -{ - PNamespace *GlobalNamespace; - TArray AllNamespaces; - - FNamespaceManager(); - PNamespace *NewNamespace(int filenum); - size_t MarkSymbols(); - void ReleaseSymbols(); - int RemoveSymbols(); -}; - -extern FNamespaceManager Namespaces; - - // Enumerations for serializing types in an archive ------------------------- inline bool &DObject::BoolVar(FName field) diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp new file mode 100644 index 000000000..ba0704433 --- /dev/null +++ b/src/scripting/symbols.cpp @@ -0,0 +1,440 @@ +/* +** symbols.cpp +** Implements the symbol types and symbol table +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2006-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "dobject.h" +#include "i_system.h" + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FNamespaceManager Namespaces; + +// Symbol tables ------------------------------------------------------------ + +IMPLEMENT_CLASS(PTypeBase, true, false); +IMPLEMENT_CLASS(PSymbol, true, false); +IMPLEMENT_CLASS(PSymbolConst, false, false); +IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); +IMPLEMENT_CLASS(PSymbolConstString, false, false); +IMPLEMENT_CLASS(PSymbolTreeNode, false, false) +IMPLEMENT_CLASS(PSymbolType, false, false) +IMPLEMENT_CLASS(PSymbolVMFunction, false, false) +IMPLEMENT_CLASS(PFunction, false, false) +IMPLEMENT_CLASS(PNamespace, false, true) + +IMPLEMENT_POINTERS_START(PNamespace) +IMPLEMENT_POINTER(Parent) +IMPLEMENT_POINTERS_END + + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol::~PSymbol() +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbolConstString::PSymbolConstString(FName name, const FString &str) + : PSymbolConst(name, TypeString), Str(str) +{ +} + +//========================================================================== +// +// PFunction :: AddVariant +// +// Adds a new variant for this function. Does not check if a matching +// variant already exists. +// +//========================================================================== + +unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) +{ + Variant variant; + + // I do not think we really want to deal with overloading here... + assert(Variants.Size() == 0); + + variant.Flags = flags; + variant.UseFlags = useflags; + variant.Proto = proto; + variant.ArgFlags = std::move(argflags); + variant.ArgNames = std::move(argnames); + variant.Implementation = impl; + if (impl != nullptr) impl->Proto = proto; + + // SelfClass can differ from OwningClass, but this is variant-dependent. + // Unlike the owner there can be cases where different variants can have different SelfClasses. + // (Of course only if this ever gets enabled...) + if (flags & VARF_Method) + { + assert(proto->ArgumentTypes.Size() > 0); + auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); + assert(selftypeptr != nullptr); + variant.SelfClass = dyn_cast(selftypeptr->PointedType); + assert(variant.SelfClass != nullptr); + } + else + { + variant.SelfClass = nullptr; + } + + return Variants.Push(variant); +} + +//========================================================================== +// +// +// +//========================================================================== + +int PFunction::GetImplicitArgs() +{ + if (Variants[0].Flags & VARF_Action) return 3; + else if (Variants[0].Flags & VARF_Method) return 1; + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbolTable::PSymbolTable() +: ParentSymbolTable(nullptr) +{ +} + +PSymbolTable::PSymbolTable(PSymbolTable *parent) +: ParentSymbolTable(parent) +{ +} + +PSymbolTable::~PSymbolTable () +{ + ReleaseSymbols(); +} + +//========================================================================== +// +// +// +//========================================================================== + +size_t PSymbolTable::MarkSymbols() +{ + size_t count = 0; + MapType::Iterator it(Symbols); + MapType::Pair *pair; + + while (it.NextPair(pair)) + { + GC::Mark(pair->Value); + count++; + } + return count * sizeof(*pair); +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::ReleaseSymbols() +{ + // The GC will take care of deleting the symbols. We just need to + // clear our references to them. + Symbols.Clear(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::SetParentTable (PSymbolTable *parent) +{ + ParentSymbolTable = parent; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == nullptr && searchparents && ParentSymbolTable != nullptr) + { + return ParentSymbolTable->FindSymbol(symname, searchparents); + } + return value != nullptr ? *value : nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == nullptr) + { + if (ParentSymbolTable != nullptr) + { + return ParentSymbolTable->FindSymbolInTable(symname, symtable); + } + symtable = nullptr; + return nullptr; + } + symtable = this; + return *value; +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) +{ + // Symbols that already exist are not inserted. + if (Symbols.CheckKey(sym->SymbolName) != nullptr) + { + return nullptr; + } + Symbols.Insert(sym->SymbolName, sym); + return sym; +} + +//========================================================================== +// +// +// +//========================================================================== + +void PSymbolTable::RemoveSymbol(PSymbol *sym) +{ + auto mysym = Symbols.CheckKey(sym->SymbolName); + if (mysym == nullptr || *mysym != sym) return; + Symbols.Remove(sym->SymbolName); +} + +//========================================================================== +// +// +// +//========================================================================== + +PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) +{ + // If a symbol with a matching name exists, take its place and return it. + PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); + if (symslot != nullptr) + { + PSymbol *oldsym = *symslot; + *symslot = newsym; + return oldsym; + } + // Else, just insert normally and return nullptr since there was no + // symbol to replace. + Symbols.Insert(newsym->SymbolName, newsym); + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +//========================================================================== +// +// +// +//========================================================================== + +PNamespace::PNamespace(int filenum, PNamespace *parent) +{ + Parent = parent; + if (parent) Symbols.SetParentTable(&parent->Symbols); + FileNum = filenum; +} + +//========================================================================== +// +// +// +//========================================================================== + +size_t PNamespace::PropagateMark() +{ + GC::Mark(Parent); + return Symbols.MarkSymbols() + 1; +} + +//========================================================================== +// +// +// +//========================================================================== + +FNamespaceManager::FNamespaceManager() +{ + GlobalNamespace = nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +PNamespace *FNamespaceManager::NewNamespace(int filenum) +{ + PNamespace *parent = nullptr; + // The parent will be the last namespace with this or a lower filenum. + // This ensures that DECORATE won't see the symbols of later files. + for (int i = AllNamespaces.Size() - 1; i >= 0; i--) + { + if (AllNamespaces[i]->FileNum <= filenum) + { + parent = AllNamespaces[i]; + break; + } + } + auto newns = new PNamespace(filenum, parent); + AllNamespaces.Push(newns); + return newns; +} + +//========================================================================== +// +// +// +//========================================================================== + +size_t FNamespaceManager::MarkSymbols() +{ + for (auto ns : AllNamespaces) + { + GC::Mark(ns); + } + return AllNamespaces.Size(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FNamespaceManager::ReleaseSymbols() +{ + GlobalNamespace = nullptr; + AllNamespaces.Clear(); +} + +//========================================================================== +// +// removes all symbols from the symbol tables. +// After running the compiler these are not needed anymore. +// Only the namespaces themselves are kept because the type table references them. +// +//========================================================================== + +int FNamespaceManager::RemoveSymbols() +{ + int count = 0; + for (auto ns : AllNamespaces) + { + count += ns->Symbols.Symbols.CountUsed(); + ns->Symbols.ReleaseSymbols(); + } + return count; +} + +//========================================================================== +// +// Clean out all compiler-only data from the symbol tables +// +//========================================================================== + +void RemoveUnusedSymbols() +{ + // Global symbols are not needed anymore after running the compiler. + int count = Namespaces.RemoveSymbols(); + + // We do not need any non-field and non-function symbols in structs and classes anymore. + // struct/class fields and functions are still needed so that the game can access the script data, + // but all the rest serves no purpose anymore and can be entirely removed. + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) + { + if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) + { + auto it = ty->Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction))) + { + ty->Symbols.RemoveSymbol(pair->Value); + count++; + } + } + } + } + } + DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count); +} diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h new file mode 100644 index 000000000..52d7ac60a --- /dev/null +++ b/src/scripting/symbols.h @@ -0,0 +1,286 @@ +// Note: This must not be included by anything but dobject.h! +#pragma once + +#ifndef __DOBJECT_H__ +#error You must #include "dobject.h" to get symbols.h +#endif + + +class VMFunction; +class PType; +class PPrototype; +struct ZCC_TreeNode; +class PStruct; + +// Symbol information ------------------------------------------------------- + +class PTypeBase : public DObject +{ + DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) + +public: + virtual FString QualifiedName() const + { + return ""; + } +}; + +class PSymbol : public PTypeBase +{ + DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase); +public: + virtual ~PSymbol(); + + virtual FString QualifiedName() const + { + return SymbolName.GetChars(); + } + + FName SymbolName; + +protected: + PSymbol(FName name) { SymbolName = name; } +}; + +// A VM function ------------------------------------------------------------ + +class PSymbolVMFunction : public PSymbol +{ + DECLARE_CLASS(PSymbolVMFunction, PSymbol); +public: + VMFunction *Function; + + PSymbolVMFunction(FName name) : PSymbol(name) {} + PSymbolVMFunction() : PSymbol(NAME_None) {} +}; + +// A symbol for a type ------------------------------------------------------ + +class PSymbolType : public PSymbol +{ + DECLARE_CLASS(PSymbolType, PSymbol); +public: + PType *Type; + + PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} + PSymbolType() : PSymbol(NAME_None) {} +}; + +// A symbol for a compiler tree node ---------------------------------------- + +class PSymbolTreeNode : public PSymbol +{ + DECLARE_CLASS(PSymbolTreeNode, PSymbol); +public: + struct ZCC_TreeNode *Node; + + PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {} + PSymbolTreeNode() : PSymbol(NAME_None) {} +}; + +// Struct/class fields ------------------------------------------------------ + +// A PField describes a symbol that takes up physical space in the struct. +class PField : public PSymbol +{ + DECLARE_CLASS(PField, PSymbol); + HAS_OBJECT_POINTERS +public: + PField(FName name, PType *type, uint32_t flags = 0, size_t offset = 0, int bitvalue = 0); + + size_t Offset; + PType *Type; + uint32_t Flags; + int BitValue; +protected: + PField(); +}; + +// Properties ------------------------------------------------------ + +// For setting properties in class defaults. +class PProperty : public PSymbol +{ + DECLARE_CLASS(PProperty, PSymbol); +public: + PProperty(FName name, TArray &variables); + + TArray Variables; + +protected: + PProperty(); +}; + +class PPropFlag : public PSymbol +{ + DECLARE_CLASS(PPropFlag, PSymbol); +public: + PPropFlag(FName name, PField *offset, int bitval); + + PField *Offset; + int bitval; + +protected: + PPropFlag(); +}; + +// A constant value --------------------------------------------------------- + +class PSymbolConst : public PSymbol +{ + DECLARE_CLASS(PSymbolConst, PSymbol); +public: + PType *ValueType; + + PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} + PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} +}; + +// A constant numeric value ------------------------------------------------- + +class PSymbolConstNumeric : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); +public: + union + { + int Value; + double Float; + void *Pad; + }; + + PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} + PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} + PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} + PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} + PSymbolConstNumeric() {} +}; + +// A constant string value -------------------------------------------------- + +class PSymbolConstString : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstString, PSymbolConst); +public: + FString Str; + + PSymbolConstString(FName name, const FString &str); + PSymbolConstString() {} +}; + + +// A function for the VM -------------------------------------------------- + +// TBD: Should we really support overloading? +class PFunction : public PSymbol +{ + DECLARE_CLASS(PFunction, PSymbol); +public: + struct Variant + { + PPrototype *Proto; + VMFunction *Implementation; + TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes + TArray ArgNames; // we need the names to access them later when the function gets compiled. + uint32_t Flags; + int UseFlags; + PStruct *SelfClass; + }; + TArray Variants; + PStruct *OwningClass = nullptr; + + unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); + int GetImplicitArgs(); + + PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} +}; + +// A symbol table ----------------------------------------------------------- + +struct PSymbolTable +{ + PSymbolTable(); + PSymbolTable(PSymbolTable *parent); + ~PSymbolTable(); + + size_t MarkSymbols(); + + // Sets the table to use for searches if this one doesn't contain the + // requested symbol. + void SetParentTable (PSymbolTable *parent); + PSymbolTable *GetParentTable() const + { + return ParentSymbolTable; + } + + // Finds a symbol in the table, optionally searching parent tables + // as well. + PSymbol *FindSymbol (FName symname, bool searchparents) const; + + // Like FindSymbol with searchparents set true, but also returns the + // specific symbol table the symbol was found in. + PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); + + + // Places the symbol in the table and returns a pointer to it or NULL if + // a symbol with the same name is already in the table. This symbol is + // not copied and will be freed when the symbol table is destroyed. + PSymbol *AddSymbol (PSymbol *sym); + + // Similar to AddSymbol but always succeeds. Returns the symbol that used + // to be in the table with this name, if any. + PSymbol *ReplaceSymbol(PSymbol *sym); + + void RemoveSymbol(PSymbol *sym); + + // Frees all symbols from this table. + void ReleaseSymbols(); + + typedef TMap MapType; + + MapType::Iterator GetIterator() + { + return MapType::Iterator(Symbols); + } + +private: + + PSymbolTable *ParentSymbolTable; + MapType Symbols; + + friend class DObject; + friend struct FNamespaceManager; +}; + +// Namespaces -------------------------------------------------- + +class PNamespace : public PTypeBase +{ + DECLARE_CLASS(PNamespace, PTypeBase) + HAS_OBJECT_POINTERS; + +public: + PSymbolTable Symbols; + PNamespace *Parent; + int FileNum; // This is for blocking DECORATE access to later files. + + PNamespace() {} + PNamespace(int filenum, PNamespace *parent); + size_t PropagateMark(); +}; + +struct FNamespaceManager +{ + PNamespace *GlobalNamespace; + TArray AllNamespaces; + + FNamespaceManager(); + PNamespace *NewNamespace(int filenum); + size_t MarkSymbols(); + void ReleaseSymbols(); + int RemoveSymbols(); +}; + +extern FNamespaceManager Namespaces; + + From f1b3d60b2f606b3fd2f96209de3c4d81211ca70b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 13:37:13 +0100 Subject: [PATCH 31/50] - PSymbol does not need to inherit from PTypeBase. This also means that there are no remaining references to any symbol object outside of the symbol tables. --- src/dobject.h | 1 + src/dobjtype.cpp | 14 -------------- src/dobjtype.h | 1 - src/scripting/symbols.cpp | 10 ---------- src/scripting/symbols.h | 15 ++------------- 5 files changed, 3 insertions(+), 38 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 6ad8ded6f..7c2fd4c22 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -205,6 +205,7 @@ enum EObjectFlags OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) + OF_Released = 1 << 12, // Object was released from the GC system and should not be processed by GC function }; template class TObjPtr; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index eda59bcc1..3c556da3b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -489,20 +489,6 @@ void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = TypeName; } -//========================================================================== -// -// PNamedType :: QualifiedName -// -//========================================================================== - -FString PNamedType::QualifiedName() const -{ - FString out; - if (Outer != nullptr) out = Outer->QualifiedName(); - out << "::" << TypeName; - return out; -} - /* PInt *******************************************************************/ IMPLEMENT_CLASS(PInt, false, false) diff --git a/src/dobjtype.h b/src/dobjtype.h index c999f3f50..cfae5e169 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -224,7 +224,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - virtual FString QualifiedName() const; }; // Basic types -------------------------------------------------------------- diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index ba0704433..68b9d522c 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -59,16 +59,6 @@ IMPLEMENT_POINTER(Parent) IMPLEMENT_POINTERS_END -//========================================================================== -// -// -// -//========================================================================== - -PSymbol::~PSymbol() -{ -} - //========================================================================== // // diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index 52d7ac60a..af5bfb80e 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -19,23 +19,12 @@ class PTypeBase : public DObject DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) public: - virtual FString QualifiedName() const - { - return ""; - } }; -class PSymbol : public PTypeBase +class PSymbol : public DObject { - DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase); + DECLARE_ABSTRACT_CLASS(PSymbol, DObject); public: - virtual ~PSymbol(); - - virtual FString QualifiedName() const - { - return SymbolName.GetChars(); - } - FName SymbolName; protected: From 31223ca180b0b3199fa0c6a04e47548ec356150d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 14:34:39 +0100 Subject: [PATCH 32/50] - remove all symbols that get linked into the symbol table from the garbage collector. Symbols are very easy to manage once they are in a symbol table and there's lots of them so this reduces the amount of work the GC needs to do quite considerably. After cleaning out compile-time-only symbols there will still be more than 2000 left, one for each function and one for each member variable of a class or struct. This means more than 2000 object that won't need to tracked constantly by the garbage collector. Note that loose fields which do occur during code generation will be GC'd just as before. --- src/dobject.cpp | 70 ++++++++++++++++++------------- src/dobject.h | 3 ++ src/dobjgc.cpp | 6 ++- src/dobjtype.cpp | 26 +----------- src/dobjtype.h | 4 -- src/scripting/backend/codegen.cpp | 13 ------ src/scripting/backend/codegen.h | 1 - src/scripting/symbols.cpp | 52 +++++++---------------- src/scripting/symbols.h | 5 +-- 9 files changed, 64 insertions(+), 116 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 63c7bb688..68f3aab8e 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -301,42 +301,17 @@ DObject::~DObject () PClass *type = GetClass(); if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) { - DObject **probe; - - if (!(ObjectFlags & OF_YesReallyDelete)) + if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released))) { Printf("Warning: '%s' is freed outside the GC process.\n", type != NULL ? type->TypeName.GetChars() : "==some object=="); } - // Find all pointers that reference this object and NULL them. - StaticPointerSubstitution(this, NULL); - - // Now unlink this object from the GC list. - for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) + if (!(ObjectFlags & OF_Released)) { - if (*probe == this) - { - *probe = ObjNext; - if (&ObjNext == GC::SweepPos) - { - GC::SweepPos = probe; - } - break; - } - } - - // If it's gray, also unlink it from the gray list. - if (this->IsGray()) - { - for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) - { - if (*probe == this) - { - *probe = GCNext; - break; - } - } + // Find all pointers that reference this object and NULL them. + StaticPointerSubstitution(this, NULL); + Release(); } } @@ -347,6 +322,41 @@ DObject::~DObject () } } +void DObject::Release() +{ + DObject **probe; + + // Unlink this object from the GC list. + for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) + { + if (*probe == this) + { + *probe = ObjNext; + if (&ObjNext == GC::SweepPos) + { + GC::SweepPos = probe; + } + break; + } + } + + // If it's gray, also unlink it from the gray list. + if (this->IsGray()) + { + for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) + { + if (*probe == this) + { + *probe = GCNext; + break; + } + } + } + ObjNext = nullptr; + GCNext = nullptr; + ObjectFlags |= OF_Released; +} + //========================================================================== // // diff --git a/src/dobject.h b/src/dobject.h index 7c2fd4c22..82051e3bd 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -468,6 +468,9 @@ public: Class = NULL; } + // Releases the object from the GC, letting the caller care of any maintenance. + void Release(); + // For catching Serialize functions in derived classes // that don't call their base class. void CheckIfSerialized () const; diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index ca57e6aca..e6ff9c734 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -277,7 +277,9 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) void Mark(DObject **obj) { DObject *lobj = *obj; - if (lobj != NULL) + + assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released)); + if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released)) { if (lobj->ObjectFlags & OF_EuthanizeMe) { @@ -551,6 +553,8 @@ void Barrier(DObject *pointing, DObject *pointed) assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointed->IsWhite() && !pointed->IsDead()); assert(State != GCS_Finalize && State != GCS_Pause); + assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong. + if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects. // The invariant only needs to be maintained in the propagate state. if (State == GCS_Propagate) { diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 3c556da3b..f0e7b2fc1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -185,18 +185,6 @@ PType::~PType() { } -//========================================================================== -// -// PType :: PropagateMark -// -//========================================================================== - -size_t PType::PropagateMark() -{ - size_t marked = Symbols.MarkSymbols(); - return marked + Super::PropagateMark(); -} - //========================================================================== // // PType :: WriteValue @@ -2413,7 +2401,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) if (Symbols.AddSymbol(field) == nullptr) { // name is already in use - delete field; + field->Destroy(); return nullptr; } Fields.Push(field); @@ -2444,18 +2432,6 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD f return field; } -//========================================================================== -// -// PStruct :: PropagateMark -// -//========================================================================== - -size_t PStruct::PropagateMark() -{ - GC::MarkArray(Fields); - return Fields.Size() * sizeof(void*) + Super::PropagateMark(); -} - //========================================================================== // // NewStruct diff --git a/src/dobjtype.h b/src/dobjtype.h index cfae5e169..6c07b047b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -171,8 +171,6 @@ public: const char *DescriptiveName() const; - size_t PropagateMark(); - static void StaticInit(); }; @@ -520,8 +518,6 @@ public: virtual PField *AddField(FName name, PType *type, DWORD flags=0); virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); - size_t PropagateMark(); - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index a3dc066e9..910dba19f 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6558,23 +6558,10 @@ FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition FxStackVariable::~FxStackVariable() { - // Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap. membervar->ObjectFlags |= OF_YesReallyDelete; delete membervar; } -//========================================================================== -// -// -//========================================================================== - -void FxStackVariable::ReplaceField(PField *newfield) -{ - membervar->ObjectFlags |= OF_YesReallyDelete; - delete membervar; - membervar = newfield; -} - //========================================================================== // // diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index c64ec2094..abbcbd54e 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -1417,7 +1417,6 @@ class FxStackVariable : public FxMemberBase public: FxStackVariable(PType *type, int offset, const FScriptPosition&); ~FxStackVariable(); - void ReplaceField(PField *newfield); FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index 68b9d522c..b6adb33e7 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -149,34 +149,19 @@ PSymbolTable::~PSymbolTable () //========================================================================== // -// -// -//========================================================================== - -size_t PSymbolTable::MarkSymbols() -{ - size_t count = 0; - MapType::Iterator it(Symbols); - MapType::Pair *pair; - - while (it.NextPair(pair)) - { - GC::Mark(pair->Value); - count++; - } - return count * sizeof(*pair); -} - -//========================================================================== -// -// +// this must explicitly delete all content because the symbols have +// been released from the GC. // //========================================================================== void PSymbolTable::ReleaseSymbols() { - // The GC will take care of deleting the symbols. We just need to - // clear our references to them. + auto it = GetIterator(); + MapType::Pair *pair; + while (it.NextPair(pair)) + { + delete pair->Value; + } Symbols.Clear(); } @@ -243,6 +228,7 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) return nullptr; } Symbols.Insert(sym->SymbolName, sym); + sym->Release(); // no more GC, please! return sym; } @@ -257,6 +243,7 @@ void PSymbolTable::RemoveSymbol(PSymbol *sym) auto mysym = Symbols.CheckKey(sym->SymbolName); if (mysym == nullptr || *mysym != sym) return; Symbols.Remove(sym->SymbolName); + delete sym; } //========================================================================== @@ -265,20 +252,20 @@ void PSymbolTable::RemoveSymbol(PSymbol *sym) // //========================================================================== -PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) +void PSymbolTable::ReplaceSymbol(PSymbol *newsym) { // If a symbol with a matching name exists, take its place and return it. PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); if (symslot != nullptr) { PSymbol *oldsym = *symslot; + delete oldsym; *symslot = newsym; - return oldsym; } // Else, just insert normally and return nullptr since there was no // symbol to replace. + newsym->Release(); // no more GC, please! Symbols.Insert(newsym->SymbolName, newsym); - return nullptr; } //========================================================================== @@ -306,18 +293,6 @@ PNamespace::PNamespace(int filenum, PNamespace *parent) // //========================================================================== -size_t PNamespace::PropagateMark() -{ - GC::Mark(Parent); - return Symbols.MarkSymbols() + 1; -} - -//========================================================================== -// -// -// -//========================================================================== - FNamespaceManager::FNamespaceManager() { GlobalNamespace = nullptr; @@ -370,6 +345,7 @@ size_t FNamespaceManager::MarkSymbols() void FNamespaceManager::ReleaseSymbols() { + RemoveSymbols(); GlobalNamespace = nullptr; AllNamespaces.Clear(); } diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index af5bfb80e..3c9d1f8f3 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -192,8 +192,6 @@ struct PSymbolTable PSymbolTable(PSymbolTable *parent); ~PSymbolTable(); - size_t MarkSymbols(); - // Sets the table to use for searches if this one doesn't contain the // requested symbol. void SetParentTable (PSymbolTable *parent); @@ -218,7 +216,7 @@ struct PSymbolTable // Similar to AddSymbol but always succeeds. Returns the symbol that used // to be in the table with this name, if any. - PSymbol *ReplaceSymbol(PSymbol *sym); + void ReplaceSymbol(PSymbol *sym); void RemoveSymbol(PSymbol *sym); @@ -255,7 +253,6 @@ public: PNamespace() {} PNamespace(int filenum, PNamespace *parent); - size_t PropagateMark(); }; struct FNamespaceManager From a6785afddbd8d9891e10cbbfbf8a1e2405094020 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 15:47:22 +0100 Subject: [PATCH 33/50] - optimized the FName versions of IsDescendantOf and IsKindOf. These can be done without first looking up the class type itself. --- src/am_map.cpp | 2 +- src/b_bot.cpp | 2 +- src/b_think.cpp | 2 +- src/c_cmds.cpp | 2 +- src/d_dehacked.cpp | 4 +-- src/dobject.h | 6 ++++ src/dobjtype.h | 13 +++++++ src/fragglescript/t_func.cpp | 12 +++---- src/g_inventory/a_keys.cpp | 2 +- src/g_inventory/a_weapons.cpp | 12 +++---- src/g_shared/a_morph.cpp | 2 +- src/g_shared/shared_hud.cpp | 6 ++-- src/g_statusbar/sbarinfo_commands.cpp | 38 ++++++++++----------- src/gl/dynlights/gl_dynlight.cpp | 2 +- src/info.cpp | 2 +- src/m_cheat.cpp | 4 +-- src/p_acs.cpp | 6 ++-- src/p_actionfunctions.cpp | 6 ++-- src/p_conversation.cpp | 4 +-- src/p_enemy.cpp | 4 +-- src/p_mobj.cpp | 4 +-- src/p_pspr.cpp | 6 ++-- src/p_user.cpp | 24 ++++++------- src/portal.cpp | 2 +- src/scripting/thingdef.cpp | 6 ++-- src/scripting/thingdef_properties.cpp | 12 +++---- src/zstring.h | 10 ++++++ wadsrc/static/zscript/inventory/weapons.txt | 28 +++++++-------- 28 files changed, 126 insertions(+), 97 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index be92fd37a..57eccc19d 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2857,7 +2857,7 @@ void AM_drawThings () // Find the key's own color. // Only works correctly if single-key locks have lower numbers than any-key locks. // That is the case for all default keys, however. - if (t->IsKindOf(PClass::FindActor(NAME_Key))) + if (t->IsKindOf(NAME_Key)) { if (G_SkillProperty(SKILLP_EasyKey)) { diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 54d154a3e..637494333 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -263,7 +263,7 @@ void InitBotStuff() for(unsigned i=0;iIsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls != NULL && cls->IsDescendantOf(NAME_Weapon)) { AWeapon *w = (AWeapon*)GetDefaultByType(cls); if (w != NULL) diff --git a/src/b_think.cpp b/src/b_think.cpp index 7ce276aa0..da3fb6124 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -328,7 +328,7 @@ void DBot::WhatToGet (AActor *item) //if(pos && !bglobal.thingvis[pos->id][item->id]) continue; // if (item->IsKindOf (RUNTIME_CLASS(AArtifact))) // return; // don't know how to use artifacts - if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { // FIXME AWeapon *heldWeapon; diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 7428fceea..e8f9509e5 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -1210,7 +1210,7 @@ static void PrintSecretString(const char *string, bool thislevel) { while ((actor = it.Next())) { - if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue; + if (!actor->IsKindOf("SecretTrigger")) continue; foundone = true; break; } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 7ad5e6344..c30fc64ae 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2916,7 +2916,7 @@ static bool LoadDehSupp () else { auto cls = PClass::FindActor(sc.String); - if (cls == NULL || !cls->IsDescendantOf(PClass::FindActor(NAME_Ammo))) + if (cls == NULL || !cls->IsDescendantOf(NAME_Ammo)) { sc.ScriptError("Unknown ammo type '%s'", sc.String); } @@ -2934,7 +2934,7 @@ static bool LoadDehSupp () { sc.MustGetString(); PClass *cls = PClass::FindClass(sc.String); - if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls == NULL || !cls->IsDescendantOf(NAME_Weapon)) { sc.ScriptError("Unknown weapon type '%s'", sc.String); } diff --git a/src/dobject.h b/src/dobject.h index 82051e3bd..f3c290443 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -458,6 +458,7 @@ public: virtual ~DObject (); inline bool IsKindOf (const PClass *base) const; + inline bool IsKindOf(FName base) const; inline bool IsA (const PClass *type) const; void SerializeUserVars(FSerializer &arc); @@ -615,6 +616,11 @@ inline bool DObject::IsKindOf (const PClass *base) const return base->IsAncestorOf (GetClass ()); } +inline bool DObject::IsKindOf(FName base) const +{ + return GetClass()->IsDescendantOf(base); +} + inline bool DObject::IsA (const PClass *type) const { return (type == GetClass()); diff --git a/src/dobjtype.h b/src/dobjtype.h index 6c07b047b..42280a12b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -622,11 +622,24 @@ public: } return false; } + inline bool IsDescendantOf(const PClass *ti) const { return ti->IsAncestorOf(this); } + inline bool IsDescendantOf(FName ti) const + { + auto me = this; + while (me) + { + if (me->TypeName == ti) + return true; + me = me->ParentClass; + } + return false; + } + // Find a type, given its name. const PClass *FindParentClass(FName name) const; PClass *FindParentClass(FName name) { return const_cast(const_cast(this)->FindParentClass(name)); } diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 0ee391e21..e8cde0222 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2629,7 +2629,7 @@ void FParser::SF_MaxPlayerAmmo() for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory) { - if (item->IsKindOf(PClass::FindClass(NAME_BackpackItem))) + if (item->IsKindOf(NAME_BackpackItem)) { if (t_argc>=4) amount = intvalue(t_argv[3]); else amount*=2; @@ -2676,7 +2676,7 @@ void FParser::SF_PlayerWeapon() return; } auto ti = PClass::FindActor(WeaponNames[weaponnum]); - if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!ti || !ti->IsDescendantOf(NAME_Weapon)) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2712,7 +2712,7 @@ void FParser::SF_PlayerWeapon() { if (!wp) { - AWeapon * pw=players[playernum].PendingWeapon; + auto pw=players[playernum].PendingWeapon; players[playernum].mo->GiveInventoryType(ti); players[playernum].PendingWeapon=pw; } @@ -2757,7 +2757,7 @@ void FParser::SF_PlayerSelectedWeapon() return; } auto ti = PClass::FindActor(WeaponNames[weaponnum]); - if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!ti || !ti->IsDescendantOf(NAME_Weapon)) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2862,7 +2862,7 @@ void FParser::SF_SetWeapon() { AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1]))); - if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item == NULL || !item->IsKindOf(NAME_Weapon)) { } else if (players[playernum].ReadyWeapon == item) @@ -2874,7 +2874,7 @@ void FParser::SF_SetWeapon() } else { - AWeapon *weap = static_cast (item); + auto weap = static_cast (item); if (weap->CheckAmmo (AWeapon::EitherFire, false)) { diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index 0ad6b72f1..75d98c2c7 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -187,7 +187,7 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc) keygroup->anykeylist.Push (k); //... but only keys get key numbers! - if (mi->IsDescendantOf(PClass::FindActor(NAME_Key))) + if (mi->IsDescendantOf(NAME_Key)) { if (!ignorekey && GetDefaultByType(mi)->special1 == 0) diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index a916531be..888259098 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -528,7 +528,7 @@ bool FWeaponSlot::AddWeapon(PClassActor *type) return false; } - if (!type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!type->IsDescendantOf(NAME_Weapon)) { Printf("Can't add non-weapon %s to weapon slots\n", type->TypeName.GetChars()); return false; @@ -635,7 +635,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[j].Type)); - if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(NAME_Weapon)) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -650,7 +650,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[i].Type)); - if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(NAME_Weapon)) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -982,7 +982,7 @@ void FWeaponSlots::AddExtraWeapons() { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (!cls->IsDescendantOf(NAME_Weapon)) { continue; } @@ -1342,7 +1342,7 @@ CCMD (weaponsection) //=========================================================================== void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) { - if (type != nullptr && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (type != nullptr && type->IsDescendantOf(NAME_Weapon)) { switch (AddDefaultWeapon(slot, type)) { @@ -1441,7 +1441,7 @@ void P_SetupWeapons_ntohton() { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls->IsDescendantOf(NAME_Weapon)) { Weapons_ntoh.Push(static_cast(cls)); } diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 0c95c77b8..cd72bca79 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -337,7 +337,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, if (correctweapon) { // Better "lose morphed weapon" semantics PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); - if (morphweapon != nullptr && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (morphweapon != nullptr && morphweapon->IsDescendantOf(NAME_Weapon)) { AWeapon *OriginalMorphWeapon = static_cast(mo->FindInventory (morphweapon)); if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon)) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 4ab0c8133..79c51350b 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -612,7 +612,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) // Now check for the remaining weapons that are in the inventory but not in the weapon slots for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory) { - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (inv->IsKindOf(NAME_Weapon)) { AddAmmoToList((AWeapon*)inv); } @@ -713,7 +713,7 @@ FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL } } // no spawn state - now try the ready state if it's weapon - else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) + else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(NAME_Weapon) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) { state = ReadyState; } @@ -767,7 +767,7 @@ static void DrawWeapons(player_t *CPlayer, int x, int y) // First draw all weapons in the inventory that are not assigned to a weapon slot for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory) { - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) && + if (inv->IsKindOf(NAME_Weapon) && !CPlayer->weapons.LocateWeapon(static_cast(inv)->GetClass(), NULL, NULL)) { DrawOneWeapon(CPlayer, x, y, static_cast(inv)); diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index c3950571f..6e6b55bec 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -148,7 +148,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { type = INVENTORYICON; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -418,7 +418,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->IsDescendantOf(PClass::FindActor(NAME_Key))) + if (cls->IsDescendantOf(NAME_Key)) { auto key = GetDefaultByType(cls); if (key->special1 == keynum) @@ -471,7 +471,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage { inventoryItem[0] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -498,7 +498,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage sc.MustGetToken(TK_Identifier); inventoryItem[1] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !item->IsDescendantOf(NAME_Inventory)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -556,7 +556,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) { - if(item->IsKindOf(PClass::FindActor(NAME_Key))) + if(item->IsKindOf(NAME_Key)) { int keynum = item->special1; if(keynum) @@ -1078,7 +1078,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if(inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); inventoryItem = PClass::FindActor(NAME_Ammo); @@ -1094,7 +1094,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); inventoryItem = PClass::FindActor(NAME_Ammo); @@ -1160,7 +1160,7 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(inventoryItem)) + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_PowerupGiver)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); inventoryItem = PClass::FindActor(NAME_PowerupGiver); @@ -1203,7 +1203,7 @@ class CommandDrawNumber : public CommandDrawString if(value == INVENTORY) { inventoryItem = PClass::FindActor(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if (inventoryItem == NULL || !inventoryItem->IsDescendantOf(NAME_Inventory)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); inventoryItem = RUNTIME_CLASS(AInventory); @@ -1476,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString num = 0; for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) { - if(item->IsKindOf(PClass::FindActor(NAME_Key))) + if(item->IsKindOf(NAME_Key)) num++; } break; @@ -2431,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand int rowWidth = 0; for(unsigned int i = 0;i < number+keyOffset;i++) { - while(!item->Icon.isValid() || !item->IsKindOf(PClass::FindActor(NAME_Key))) + while(!item->Icon.isValid() || !item->IsKindOf(NAME_Key)) { item = item->Inventory; if(item == NULL) @@ -2632,7 +2632,7 @@ class CommandDrawBar : public SBarInfoCommand sc.MustGetToken(TK_Identifier); type = AMMO; data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo + if (data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); data.inventoryItem = PClass::FindActor(NAME_Ammo); @@ -2660,7 +2660,7 @@ class CommandDrawBar : public SBarInfoCommand if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(data.inventoryItem)) + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_PowerupGiver)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); data.inventoryItem = PClass::FindActor(NAME_PowerupGiver); @@ -2672,7 +2672,7 @@ class CommandDrawBar : public SBarInfoCommand { type = INVENTORY; data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); data.inventoryItem = RUNTIME_CLASS(AInventory); @@ -2894,7 +2894,7 @@ class CommandDrawBar : public SBarInfoCommand if(sc.CheckToken(TK_Identifier) || (extendedSyntax && sc.CheckToken(TK_StringConst))) //comparing reference { data.inventoryItem = PClass::FindActor(sc.String); - if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) //must be a kind of inventory + if(data.inventoryItem == NULL || !data.inventoryItem->IsDescendantOf(NAME_Inventory)) //must be a kind of inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); data.inventoryItem = RUNTIME_CLASS(AInventory); @@ -2977,7 +2977,7 @@ class CommandIsSelected : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { weapon[i] = PClass::FindClass(sc.String); - if(weapon[i] == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon[i])) + if(weapon[i] == NULL || !weapon[i]->IsDescendantOf(NAME_Weapon)) { sc.ScriptMessage("'%s' is not a type of weapon.", sc.String); weapon[i] = RUNTIME_CLASS(AWeapon); @@ -3130,7 +3130,7 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl if(!sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); weapon = PClass::FindClass(sc.String); - if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon + if (weapon == NULL || !weapon->IsDescendantOf(NAME_Weapon)) //must be a weapon { sc.ScriptMessage("%s is not a kind of weapon.", sc.String); weapon = RUNTIME_CLASS(AWeapon); @@ -3317,7 +3317,7 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { ammo[i] = PClass::FindClass(sc.String); - if(ammo[i] == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(ammo[i])) //must be a kind of ammo + if(ammo[i] == NULL || !ammo[i]->IsDescendantOf(NAME_Ammo)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); ammo[i] = PClass::FindActor(NAME_Ammo); @@ -3400,7 +3400,7 @@ class CommandInInventory : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { item[i] = PClass::FindActor(sc.String); - if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i])) + if (item[i] == NULL || !item[i]->IsDescendantOf(NAME_Inventory)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); item[i] = RUNTIME_CLASS(AInventory); diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index 7a548eaa2..5ce79fd09 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -77,7 +77,7 @@ void gl_ParseVavoomSkybox(); inline PClassActor * GetRealType(PClassActor * ti) { PClassActor *rep = ti->GetReplacement(false); - if (rep != ti && rep != NULL && rep->IsDescendantOf(PClass::FindActor(NAME_DehackedPickup))) + if (rep != ti && rep != NULL && rep->IsDescendantOf(NAME_DehackedPickup)) { return rep; } diff --git a/src/info.cpp b/src/info.cpp index 18eecc2d1..48a22c2d4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -110,7 +110,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, const char *callinfo = ""; if (info != nullptr && info->mStateType == STATE_Psprite) { - if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon "; + if (stateowner->IsKindOf(NAME_Weapon) && stateowner != self) callinfo = "weapon "; else callinfo = "overlay "; } err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars()); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 23c2f1ded..bf687c09d 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -317,7 +317,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_RESSURECT: if (player->playerstate != PST_LIVE && player->mo != nullptr) { - if (player->mo->IsKindOf(PClass::FindActor("PlayerChunk"))) + if (player->mo->IsKindOf("PlayerChunk")) { Printf("Unable to resurrect. Player is no longer connected to its body.\n"); } @@ -421,7 +421,7 @@ void cht_DoCheat (player_t *player, int cheat) { lastinvp = invp; invp = &(*invp)->Inventory; - if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { AWeapon *weap = static_cast (item); if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) || diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bddcd7f95..8b0075475 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5716,7 +5716,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) if (argCount >= 2) { PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1])); - if (powerupclass == NULL || !powerupclass->IsDescendantOf(PClass::FindActor(NAME_Powerup))) + if (powerupclass == NULL || !powerupclass->IsDescendantOf(NAME_Powerup)) { Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1])); return 0; @@ -9042,7 +9042,7 @@ scriptwait: AInventory *item = activator->FindInventory (dyn_cast( PClass::FindClass (FBehavior::StaticLookupString (STACK(1))))); - if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (item == NULL || !item->IsKindOf(NAME_Weapon)) { STACK(1) = 0; } @@ -9110,7 +9110,7 @@ scriptwait: } else { - if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine"))) + if (activator != nullptr && activator->IsKindOf("ScriptedMarine")) { SetMarineSprite(activator, type); } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index c732ea18c..ea271967b 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -2387,7 +2387,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) { return false; } - if (item->IsKindOf(PClass::FindActor(NAME_Health))) + if (item->IsKindOf(NAME_Health)) { item->Amount *= amount; } @@ -3123,7 +3123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon) AWeapon *weaponitem = static_cast(self->FindInventory(cls)); - if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weaponitem != NULL && weaponitem->IsKindOf(NAME_Weapon)) { if (self->player->ReadyWeapon != weaponitem) { @@ -5668,7 +5668,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight. AInventory *gift = static_cast(Spawn(item)); - if (gift->IsKindOf(PClass::FindActor(NAME_Health))) + if (gift->IsKindOf(NAME_Health)) { gift->Amount *= amount; } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index a77a7358d..e9ad0ff0d 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1331,7 +1331,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply { if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory))) { - if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (reply->GiveType->IsDescendantOf(NAME_Weapon)) { if (player->mo->FindInventory(reply->GiveType) != NULL) { @@ -1357,7 +1357,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } } - if (reply->GiveType->IsDescendantOf(PClass::FindActor("SlideshowStarter"))) + if (reply->GiveType->IsDescendantOf("SlideshowStarter")) gameaction = ga_slideshow; } else diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index bd5a9cb17..2fb040a93 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3226,7 +3226,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) if (dropamount > 0) { - if (flagmask != 0 && inv->IsKindOf(PClass::FindActor(NAME_Ammo))) + if (flagmask != 0 && inv->IsKindOf(NAME_Ammo)) { inv->Amount = int(dropamount * dropammofactor); inv->ItemFlags |= IF_IGNORESKILL; @@ -3252,7 +3252,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) inv->FloatVar("AmmoFactor") = dropammofactor; inv->ItemFlags |= flagmask; } - else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon))) + else if (inv->IsKindOf(NAME_Weapon)) { // The same goes for ammo from a weapon. static_cast(inv)->AmmoGive1 = int(static_cast(inv)->AmmoGive1 * dropammofactor); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 758b4ac18..d39786311 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -789,7 +789,7 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) item->ClearCounters(); if (!givecheat || amount > 0) { - if (type->IsDescendantOf (PClass::FindActor(NAME_BasicArmorPickup)) || type->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus))) + if (type->IsDescendantOf (NAME_BasicArmorPickup) || type->IsDescendantOf(NAME_BasicArmorBonus)) { item->IntVar(NAME_SaveAmount) *= amount; } @@ -903,7 +903,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate // and infinite ammo is on if (notakeinfinite && ((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && - item->IsKindOf(PClass::FindActor(NAME_Ammo))) + item->IsKindOf(NAME_Ammo)) { // Nothing to do here, except maybe res = false;? Would it make sense? result = false; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index c443ca7da..bf6c79a82 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -166,7 +166,7 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id) if (Next && Next->ID == ID && ID != 0) Next->Destroy(); // Replace it. - if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + if (Caller->IsKindOf(NAME_Weapon) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn))) Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST); } @@ -353,7 +353,7 @@ void DPSprite::SetState(FState *newstate, bool pending) } else if (!(newstate->UseFlags & SUF_WEAPON)) { - if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (Caller->IsKindOf(NAME_Weapon)) { auto so = FState::StaticFindStateOwner(newstate); Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates)); @@ -1333,7 +1333,7 @@ void player_t::TickPSprites() // or if it's from an inventory item that the player no longer owns. if ((pspr->Caller == nullptr || (pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast(pspr->Caller)->Owner != pspr->Owner->mo) || - (pspr->Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) && pspr->Caller != pspr->Owner->ReadyWeapon))) + (pspr->Caller->IsKindOf(NAME_Weapon) && pspr->Caller != pspr->Owner->ReadyWeapon))) { pspr->Destroy(); } diff --git a/src/p_user.cpp b/src/p_user.cpp index c6b0a7d58..1b9cedf4a 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -963,7 +963,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) // Find the best weapon the player has. for (item = Inventory; item != NULL; item = item->Inventory) { - if (!item->IsKindOf (RUNTIME_CLASS(AWeapon))) + if (!item->IsKindOf(NAME_Weapon)) continue; weap = static_cast (item); @@ -1136,29 +1136,29 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) if ((dmflags & DF_COOP_LOSE_KEYS) && defitem == NULL && - item->IsKindOf(PClass::FindActor(NAME_Key))) + item->IsKindOf(NAME_Key)) { item->Destroy(); } else if ((dmflags & DF_COOP_LOSE_WEAPONS) && defitem == NULL && - item->IsKindOf(RUNTIME_CLASS(AWeapon))) + item->IsKindOf(NAME_Weapon)) { item->Destroy(); } else if ((dmflags & DF_COOP_LOSE_ARMOR) && - item->IsKindOf(PClass::FindActor(NAME_Armor))) + item->IsKindOf(NAME_Armor)) { if (defitem == NULL) { item->Destroy(); } - else if (item->IsKindOf(PClass::FindActor(NAME_BasicArmor))) + else if (item->IsKindOf(NAME_BasicArmor)) { item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent); item->Amount = defitem->Amount; } - else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor))) + else if (item->IsKindOf(NAME_HexenArmor)) { double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr); double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr); @@ -1167,12 +1167,12 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) } else if ((dmflags & DF_COOP_LOSE_POWERUPS) && defitem == NULL && - item->IsKindOf(PClass::FindActor(NAME_PowerupGiver))) + item->IsKindOf(NAME_PowerupGiver)) { item->Destroy(); } else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) && - item->IsKindOf(PClass::FindActor(NAME_Ammo))) + item->IsKindOf(NAME_Ammo)) { if (defitem == NULL) { @@ -1412,7 +1412,7 @@ void APlayerPawn::GiveDefaultInventory () item = static_cast(Spawn(ti)); item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here item->Amount = di->Amount; - if (item->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (item->IsKindOf(NAME_Weapon)) { // To allow better control any weapon is emptied of // ammo before being given to the player. @@ -1432,7 +1432,7 @@ void APlayerPawn::GiveDefaultInventory () item = NULL; } } - if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon)) && + if (item != NULL && item->IsKindOf(NAME_Weapon) && static_cast(item)->CheckAmmo(AWeapon::EitherFire, false)) { player->ReadyWeapon = player->PendingWeapon = static_cast (item); @@ -1536,7 +1536,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) weap->SpawnState != ::GetDefault()->SpawnState) { item = P_DropItem (this, weap->GetClass(), -1, 256); - if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (item != NULL && item->IsKindOf(NAME_Weapon)) { if (weap->AmmoGive1 && weap->Ammo1) { @@ -1709,7 +1709,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) player_t *player; // [GRB] Parameterized version - if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk"))) + if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk")) { spawntype = dyn_cast(PClass::FindClass("BloodySkull")); if (spawntype == NULL) diff --git a/src/portal.cpp b/src/portal.cpp index 43b7ef7b6..f354faa65 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -670,7 +670,7 @@ unsigned P_GetSkyboxPortal(AActor *actor) unsigned i = level.sectorPortals.Reserve(1); memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT; - level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf(PClass::FindActor("SkyCamCompat")) ? 0 : PORTSF_SKYFLATONLY; + level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY; level.sectorPortals[i].mSkybox = actor; level.sectorPortals[i].mDestination = actor->Sector; return i; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index f2849eb39..51fb0239c 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -246,7 +246,7 @@ static void CheckForUnsafeStates(PClassActor *obj) TMap checked; ENamedName *test; - if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (obj->IsDescendantOf(NAME_Weapon)) { if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables. test = weaponstates; @@ -336,11 +336,11 @@ static void CheckStates(PClassActor *obj) CheckStateLabels(obj, actorstates, SUF_ACTOR, "actor sprites"); - if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (obj->IsDescendantOf(NAME_Weapon)) { CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites"); } - else if (obj->IsDescendantOf(PClass::FindActor(NAME_CustomInventory))) + else if (obj->IsDescendantOf(NAME_CustomInventory)) { CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain"); } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 22d6610ce..8cffbc347 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2096,9 +2096,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) int alpha; PalEntry *pBlendColor; - bool isgiver = info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)); + bool isgiver = info->IsDescendantOf(NAME_PowerupGiver); - if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || isgiver) + if (info->IsDescendantOf(NAME_Powerup) || isgiver) { pBlendColor = &defaults->ColorVar(NAME_BlendColor); } @@ -2148,7 +2148,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) { PalEntry BlendColor; - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n"); return; @@ -2183,7 +2183,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) { - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.duration\" requires an actor of type \"Powerup\"\n"); return; @@ -2198,7 +2198,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory) { - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n"); return; @@ -2214,7 +2214,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory) { PROP_STRING_PARM(str, 0); - if (!info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) && !info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver))) + if (!info->IsDescendantOf(NAME_Powerup) && !info->IsDescendantOf(NAME_PowerupGiver)) { I_Error("\"powerup.mode\" requires an actor of type \"Powerup\"\n"); return; diff --git a/src/zstring.h b/src/zstring.h index c696f7fd6..c58fb111a 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -449,4 +449,14 @@ template<> struct THashTraits // Compares two keys, returning zero if they are the same. int Compare(const FString &left, const FString &right) { return left.Compare(right); } }; + +class FStringNoInit +{ + char mem[sizeof(FString)]; + operator FString&() + { + return *reinterpret_cast(&mem); + } +}; + #endif diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index 7bda52e52..c1fbf4384 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -252,7 +252,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: TryPickup + // Weapon :: TryPickup // // If you can't see the weapon when it's active, then you can't pick it up. // @@ -277,7 +277,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: TryPickup + // Weapon :: TryPickup // //=========================================================================== @@ -293,7 +293,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: Use + // Weapon :: Use // // Make the player switch to self weapon. // @@ -324,7 +324,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: Destroy + // Weapon :: Destroy // //=========================================================================== @@ -347,7 +347,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: HandlePickup + // Weapon :: HandlePickup // // Try to leach ammo from the weapon if you have it already. // @@ -372,7 +372,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: PickupForAmmo + // Weapon :: PickupForAmmo // // The player already has self weapon, so try to pick it up for ammo. // @@ -411,7 +411,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: CreateCopy + // Weapon :: CreateCopy // //=========================================================================== @@ -428,7 +428,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: CreateTossable + // Weapon :: CreateTossable // // A weapon that's tossed out should contain no ammo, so you can't cheat // by dropping it and then picking it back up. @@ -464,7 +464,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AttachToOwner + // Weapon :: AttachToOwner // //=========================================================================== @@ -491,7 +491,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddAmmo + // Weapon :: AddAmmo // // Give some ammo to the owner, even if it's just 0. // @@ -536,7 +536,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddExistingAmmo + // Weapon :: AddExistingAmmo // // Give the owner some more ammo he already has. // @@ -563,7 +563,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: AddWeapon + // Weapon :: AddWeapon // // Give the owner a weapon if they don't have it already. // @@ -588,7 +588,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: ShouldStay + // Weapon :: ShouldStay // //=========================================================================== @@ -606,7 +606,7 @@ class Weapon : StateProvider native //=========================================================================== // - // AWeapon :: EndPowerUp + // Weapon :: EndPowerUp // // The Tome of Power just expired. // From 2ca0e347850a94231f4dbfdd9c1603fbb1964aa0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 16:42:13 +0100 Subject: [PATCH 34/50] - turned many of PClassPlayerPawn's strings into names and moved all scalar properties into APlayerPawn. The goal is to get rid of PClassPlayerPawn and PClassInventory so that the old assumption that all actor class descriptors have the same size can be restored This is important to remove some code that seriously blocks optimization of the type table because that can only be done if types do not need to be replaced. --- src/d_player.h | 20 ++++++----- src/g_inventory/a_weapons.cpp | 5 +-- src/g_shared/a_morph.cpp | 6 ++-- src/g_statusbar/sbar_mugshot.cpp | 2 +- src/menu/playerdisplay.cpp | 6 ++-- src/p_user.cpp | 46 +++++++----------------- src/r_data/sprites.cpp | 27 +++++++------- src/scripting/thingdef_properties.cpp | 47 ++++++++++++------------- wadsrc/static/zscript/shared/player.txt | 21 ++++++----- 9 files changed, 82 insertions(+), 98 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e09db38a3..b79e56862 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -82,15 +82,6 @@ public: bool GetPainFlash(FName type, PalEntry *color) const; FString DisplayName; // Display name (used in menus, etc.) - FString SoundClass; // Sound class - FString Face; // Doom status bar face (when used) - FString Portrait; - FString Slot[10]; - FName InvulMode; - FName HealingRadiusType; - double HexenArmor[5]; - BYTE ColorRangeStart; // Skin color range - BYTE ColorRangeEnd; FPlayerColorSetMap ColorSets; PainFlashList PainFlashes; }; @@ -176,6 +167,17 @@ public: // [SP] ViewBob Multiplier double ViewBob; + // Former class properties that were moved into the object to get rid of the meta class. + FName SoundClass; // Sound class + FName Face; // Doom status bar face (when used) + FName Portrait; + FName Slot[10]; + FName InvulMode; + FName HealingRadiusType; + double HexenArmor[5]; + BYTE ColorRangeStart; // Skin color range + BYTE ColorRangeEnd; + }; // diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 888259098..afa55cc10 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1154,11 +1154,12 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type) { Clear(); + auto Slot = ((APlayerPawn*)GetDefaultByType(type))->Slot; for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) { - if (!type->Slot[i].IsEmpty()) + if (Slot[i] != NAME_None) { - Slots[i].AddWeaponList(type->Slot[i], false); + Slots[i].AddWeaponList(Slot[i], false); } } } diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index cd72bca79..246073010 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -290,8 +290,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // and for the original DOOM status bar. if (player == &players[consoleplayer]) { - FString face = pmo->GetClass()->Face; - if (face.IsNotEmpty() && strcmp(face, "None") != 0) + FName face = pmo->Face; + if (face != NAME_None) { // Assume root-level base skin to begin with size_t skinindex = 0; @@ -367,7 +367,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, if (hxarmor != nullptr) { double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr); - Slots[4] = mo->GetClass()->HexenArmor[0]; + Slots[4] = mo->HexenArmor[0]; } return true; } diff --git a/src/g_statusbar/sbar_mugshot.cpp b/src/g_statusbar/sbar_mugshot.cpp index d88ad40f2..d24298b94 100644 --- a/src/g_statusbar/sbar_mugshot.cpp +++ b/src/g_statusbar/sbar_mugshot.cpp @@ -489,7 +489,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu if (CurrentState != NULL) { int skin = player->userinfo.GetSkin(); - const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? player->MorphedPlayerClass->Face.GetChars() : skins[skin].face); + const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? ((APlayerPawn*)GetDefaultByType(player->MorphedPlayerClass))->Face.GetChars() : skins[skin].face); return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index 57c8ecf26..821c2ea70 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -557,11 +557,11 @@ void DListMenuItemPlayerDisplay::Drawer(bool selected) return; } - FString portrait = mPlayerClass->Type->Portrait; + FName portrait = ((APlayerPawn*)GetDefaultByType(mPlayerClass->Type))->Portrait; - if (portrait.IsNotEmpty() && !mNoportrait) + if (portrait != NAME_None && !mNoportrait) { - FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch); + FTextureID texid = TexMan.CheckForTexture(portrait.GetChars(), FTexture::TEX_MiscPatch); if (texid.isValid()) { FTexture *tex = TexMan(texid); diff --git a/src/p_user.cpp b/src/p_user.cpp index 1b9cedf4a..ab1920ae8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -542,12 +542,6 @@ IMPLEMENT_CLASS(PClassPlayerPawn, false, false) PClassPlayerPawn::PClassPlayerPawn() { - for (size_t i = 0; i < countof(HexenArmor); ++i) - { - HexenArmor[i] = 0; - } - ColorRangeStart = 0; - ColorRangeEnd = 0; } void PClassPlayerPawn::DeriveData(PClass *newclass) @@ -555,24 +549,9 @@ void PClassPlayerPawn::DeriveData(PClass *newclass) assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); Super::DeriveData(newclass); PClassPlayerPawn *newp = static_cast(newclass); - size_t i; newp->DisplayName = DisplayName; - newp->SoundClass = SoundClass; - newp->Face = Face; - newp->InvulMode = InvulMode; - newp->HealingRadiusType = HealingRadiusType; - newp->ColorRangeStart = ColorRangeStart; - newp->ColorRangeEnd = ColorRangeEnd; newp->ColorSets = ColorSets; - for (i = 0; i < countof(HexenArmor); ++i) - { - newp->HexenArmor[i] = HexenArmor[i]; - } - for (i = 0; i < countof(Slot); ++i) - { - newp->Slot[i] = Slot[i]; - } } static int intcmp(const void *a, const void *b) @@ -1230,7 +1209,7 @@ const char *APlayerPawn::GetSoundClass() const // [GRB] PClassPlayerPawn *pclass = GetClass(); - return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass.GetChars() : "player"; + return SoundClass != NAME_None? SoundClass.GetChars() : "player"; } //=========================================================================== @@ -1373,10 +1352,10 @@ void APlayerPawn::GiveDefaultInventory () double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr); - Slots[4] = myclass->HexenArmor[0]; + Slots[4] = HexenArmor[0]; for (int i = 0; i < 4; ++i) { - SlotsIncrement[i] = myclass->HexenArmor[i + 1]; + SlotsIncrement[i] = HexenArmor[i + 1]; } // BasicArmor must come right after that. It should not affect any @@ -3248,16 +3227,17 @@ DEFINE_FIELD(APlayerPawn, DamageFade) DEFINE_FIELD(APlayerPawn, ViewBob) DEFINE_FIELD(APlayerPawn, FullHeight) -DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType) +DEFINE_FIELD(APlayerPawn, HealingRadiusType) +DEFINE_FIELD(APlayerPawn, SoundClass) +DEFINE_FIELD(APlayerPawn, Face) +DEFINE_FIELD(APlayerPawn, Portrait) +DEFINE_FIELD(APlayerPawn, Slot) +DEFINE_FIELD(APlayerPawn, InvulMode) +DEFINE_FIELD(APlayerPawn, HexenArmor) +DEFINE_FIELD(APlayerPawn, ColorRangeStart) +DEFINE_FIELD(APlayerPawn, ColorRangeEnd) + DEFINE_FIELD(PClassPlayerPawn, DisplayName) -DEFINE_FIELD(PClassPlayerPawn, SoundClass) -DEFINE_FIELD(PClassPlayerPawn, Face) -DEFINE_FIELD(PClassPlayerPawn, Portrait) -DEFINE_FIELD(PClassPlayerPawn, Slot) -DEFINE_FIELD(PClassPlayerPawn, InvulMode) -DEFINE_FIELD(PClassPlayerPawn, HexenArmor) -DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart) -DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd) DEFINE_FIELD(PClassPlayerPawn, ColorSets) DEFINE_FIELD(PClassPlayerPawn, PainFlashes) diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 7fb59ef94..be44e9d82 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -725,18 +725,22 @@ void R_InitSkins (void) if (!remove) { - skins[i].range0start = transtype->ColorRangeStart; - skins[i].range0end = transtype->ColorRangeEnd; + auto transdef = ((APlayerPawn*)GetDefaultByType(transtype)); + auto basedef = ((APlayerPawn*)GetDefaultByType(basetype)); + + skins[i].range0start = transdef->ColorRangeStart; + skins[i].range0end = transdef->ColorRangeEnd; remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) { PClassPlayerPawn *type = PlayerClasses[j].Type; + auto type_def = ((APlayerPawn*)GetDefaultByType(type)); if (type->IsDescendantOf (basetype) && GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite && - type->ColorRangeStart == basetype->ColorRangeStart && - type->ColorRangeEnd == basetype->ColorRangeEnd) + type_def->ColorRangeStart == basedef->ColorRangeStart && + type_def->ColorRangeEnd == basedef->ColorRangeEnd) { PlayerClasses[j].Skins.Push ((int)i); remove = false; @@ -935,10 +939,10 @@ void R_InitSprites () memset (skins, 0, sizeof(*skins) * numskins); for (i = 0; i < numskins; i++) { // Assume Doom skin by default - PClassPlayerPawn *type = PlayerClasses[0].Type; + auto type = ((APlayerPawn*)GetDefaultByType(PlayerClasses[0].Type)); skins[i].range0start = type->ColorRangeStart; skins[i].range0end = type->ColorRangeEnd; - skins[i].Scale = GetDefaultByType (type)->Scale; + skins[i].Scale = type->Scale; } R_InitSpriteDefs (); @@ -950,11 +954,10 @@ void R_InitSprites () // [GRB] Each player class has its own base skin for (i = 0; i < PlayerClasses.Size (); i++) { - PClassPlayerPawn *basetype = PlayerClasses[i].Type; - FString classface = basetype->Face; + auto basetype = ((APlayerPawn*)GetDefaultByType(PlayerClasses[i].Type)); strcpy (skins[i].name, "Base"); - if (classface.IsEmpty() || strcmp(classface, "None") == 0) + if (basetype->Face == NAME_None) { skins[i].face[0] = 'S'; skins[i].face[1] = 'T'; @@ -963,12 +966,12 @@ void R_InitSprites () } else { - strcpy(skins[i].face, classface); + strcpy(skins[i].face, basetype->Face); } skins[i].range0start = basetype->ColorRangeStart; skins[i].range0end = basetype->ColorRangeEnd; - skins[i].Scale = GetDefaultByType (basetype)->Scale; - skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite; + skins[i].Scale = basetype->Scale; + skins[i].sprite = basetype->SpawnState->sprite; skins[i].namespc = ns_global; PlayerClasses[i].Skins.Push (i); diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 8cffbc347..ef9a905a3 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2274,8 +2274,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn) FString tmp = str; tmp.ReplaceChars (' ', '_'); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->SoundClass = tmp; + defaults->SoundClass = tmp.IsNotEmpty()? FName(tmp) : NAME_None; } //========================================================================== @@ -2286,21 +2285,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) PROP_STRING_PARM(str, 0); FString tmp = str; - tmp.ToUpper(); - bool valid = (tmp.Len() == 3 && - (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && - (((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) && - (((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9'))) - ); - if (!valid) + if (tmp.Len() == 0) defaults->Face = NAME_None; + else { - bag.ScriptPosition.Message(MSG_OPTERROR, - "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", - tmp.GetChars(), info->TypeName.GetChars ()); + tmp.ToUpper(); + bool valid = (tmp.Len() == 3 && + (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && + (((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) && + (((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9'))) + ); + if (!valid) + { + bag.ScriptPosition.Message(MSG_OPTERROR, + "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", + tmp.GetChars(), info->TypeName.GetChars()); + } + defaults->Face = tmp; } - - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->Face = tmp; } //========================================================================== @@ -2314,9 +2315,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) if (start > end) swapvalues (start, end); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorRangeStart = start; - static_cast(info)->ColorRangeEnd = end; + defaults->ColorRangeStart = start; + defaults->ColorRangeEnd = end; } //========================================================================== @@ -2693,8 +2693,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->InvulMode = str; + defaults->InvulMode = str; } //========================================================================== @@ -2704,7 +2703,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->HealingRadiusType = str; + defaults->HealingRadiusType = str; } //========================================================================== @@ -2716,7 +2715,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) for (int i = 0; i < 5; i++) { PROP_DOUBLE_PARM(val, i); - static_cast(info)->HexenArmor[i] = val; + defaults->HexenArmor[i] = val; } } @@ -2727,7 +2726,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn) { assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); PROP_STRING_PARM(val, 0); - static_cast(info)->Portrait = val; + defaults->Portrait = val; } //========================================================================== @@ -2751,7 +2750,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss PROP_STRING_PARM(str, i); weapons << ' ' << str; } - static_cast(info)->Slot[slot] = &weapons[1]; + defaults->Slot[slot] = weapons.IsEmpty()? NAME_None : FName(weapons); } } diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 0a7798ace..dc1d1ba1d 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -9,17 +9,16 @@ class PlayerPawn : Actor native native Inventory InvFirst; // first inventory item displayed on inventory bar native Inventory InvSel; // selected inventory item native meta String DisplayName; // Display name (used in menus, etc.) - native meta String SoundClass; // Sound class - native meta String Face; // Doom status bar face (when used) - native meta String Portrait; - native meta String Slot[10]; - native meta Name InvulMode; - native meta Name HealingRadiusType; - native meta double HexenArmor[5]; - native meta uint8 ColorRangeStart; // Skin color range - native meta uint8 ColorRangeEnd; - //FPlayerColorSetMap ColorSets; - //PainFlashList PainFlashes; + + native /*meta*/ Name SoundClass; // Sound class + native /*meta*/ Name Face; // Doom status bar face (when used) + native /*meta*/ Name Portrait; + native /*meta*/ Name Slot[10]; + native /*meta*/ Name InvulMode; + native /*meta*/ Name HealingRadiusType; + native /*meta*/ double HexenArmor[5]; + native /*meta*/ uint8 ColorRangeStart; // Skin color range + native /*meta*/ uint8 ColorRangeEnd; // [GRB] Player class properties native double JumpZ; From eebe09fb59760d48ed71bba09272ef9a837697dd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 16:57:48 +0100 Subject: [PATCH 35/50] - moved the scalar class properties of PClassInventory into AInventory. What's left is the non-scalars, they will need different treatment to get them out of the way. --- src/g_inventory/a_pickups.cpp | 9 ++--- src/g_inventory/a_pickups.h | 4 +- src/g_shared/shared_hud.cpp | 34 ++++++---------- src/scripting/thingdef_properties.cpp | 40 ++++++++++++------- wadsrc/static/zscript/inventory/inventory.txt | 2 +- 5 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 66f51e92e..796036c2d 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -29,8 +29,6 @@ IMPLEMENT_CLASS(PClassInventory, false, false) PClassInventory::PClassInventory() { - GiveQuest = 0; - AltHUDIcon.SetNull(); } void PClassInventory::DeriveData(PClass *newclass) @@ -40,8 +38,6 @@ void PClassInventory::DeriveData(PClass *newclass) PClassInventory *newc = static_cast(newclass); newc->PickupMsg = PickupMsg; - newc->GiveQuest = GiveQuest; - newc->AltHUDIcon = AltHUDIcon; newc->ForbiddenToPlayerClass = ForbiddenToPlayerClass; newc->RestrictedToPlayerClass = RestrictedToPlayerClass; } @@ -98,8 +94,8 @@ DEFINE_FIELD(AInventory, DropTime) DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) +DEFINE_FIELD(AInventory, GiveQuest) DEFINE_FIELD(PClassInventory, PickupMsg) -DEFINE_FIELD(PClassInventory, GiveQuest) //=========================================================================== // @@ -163,7 +159,8 @@ void AInventory::Serialize(FSerializer &arc) ("icon", Icon, def->Icon) ("pickupsound", PickupSound, def->PickupSound) ("spawnpointclass", SpawnPointClass, def->SpawnPointClass) - ("droptime", DropTime, def->DropTime); + ("droptime", DropTime, def->DropTime) + ("givequest", GiveQuest, def->GiveQuest); } //=========================================================================== diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index be6280c0a..f467ae984 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -60,8 +60,6 @@ public: void Finalize(FStateDefinitions &statedef); FString PickupMsg; - int GiveQuest; // Optionally give one of the quest items. - FTextureID AltHUDIcon; TArray RestrictedToPlayerClass; TArray ForbiddenToPlayerClass; }; @@ -104,6 +102,8 @@ public: FTextureID Icon; // Icon to show on status bar or HUD int DropTime; // Countdown after dropping PClassActor *SpawnPointClass; // For respawning like Heretic's mace + int GiveQuest; // Optionally give one of the quest items. + FTextureID AltHUDIcon; DWORD ItemFlags; PClassActor *PickupFlash; // actor to spawn as pickup flash diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 79c51350b..d39c16d88 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -122,16 +122,6 @@ static int statspace; DVector2 AM_GetPosition(); int active_con_scaletext(); -FTextureID GetHUDIcon(PClassInventory *cls) -{ - return cls->AltHUDIcon; -} - -void SetHUDIcon(PClassInventory *cls, FTextureID tex) -{ - cls->AltHUDIcon = tex; -} - //--------------------------------------------------------------------------- // // Draws an image into a box with its bottom center at the bottom @@ -437,7 +427,7 @@ static void SetKeyTypes() static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv) { FTextureID icon = FNullTextureID(); - FTextureID AltIcon = GetHUDIcon(inv->GetClass()); + FTextureID AltIcon = inv->AltHUDIcon; if (!AltIcon.Exists()) return; @@ -516,27 +506,27 @@ static int DrawKeys(player_t * CPlayer, int x, int y) // Drawing Ammo // //--------------------------------------------------------------------------- -static TArray orderedammos; +static TArray orderedammos; static void AddAmmoToList(AWeapon * weapdef) { - for(int i=0; i<2;i++) + for (int i = 0; i < 2; i++) { - PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; + auto ti = i == 0 ? weapdef->AmmoType1 : weapdef->AmmoType2; if (ti) { - auto ammodef=(AInventory*)GetDefaultByType(ti); + auto ammodef = (AInventory*)GetDefaultByType(ti); if (ammodef && !(ammodef->ItemFlags&IF_INVBAR)) { unsigned int j; - for(j=0;j=0;i--) { - PClassInventory * type = orderedammos[i]; + auto type = orderedammos[i]; auto ammoitem = CPlayer->mo->FindInventory(type); auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]); - FTextureID AltIcon = GetHUDIcon(type); + FTextureID AltIcon = inv->AltHUDIcon; FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon; if (!icon.isValid()) continue; @@ -682,7 +672,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) //--------------------------------------------------------------------------- FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL) // This function is also used by SBARINFO { - FTextureID picnum, AltIcon = GetHUDIcon(item->GetClass()); + FTextureID picnum, AltIcon = item->AltHUDIcon; FState * state=NULL, *ReadyState; picnum.SetNull(); @@ -816,7 +806,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y) { if (rover->Amount>0) { - FTextureID AltIcon = GetHUDIcon(rover->GetClass()); + FTextureID AltIcon = rover->AltHUDIcon; if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) ) { @@ -1285,7 +1275,7 @@ void HUD_InitHud() } else tex.SetInvalid(); - if (ti) SetHUDIcon(static_cast(ti), tex); + if (ti) ((AInventory*)GetDefaultByType(ti))->AltHUDIcon = tex; } } } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index ef9a905a3..d1273da18 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1734,31 +1734,47 @@ DEFINE_CLASS_PROPERTY(amount, I, Inventory) //========================================================================== // //========================================================================== -DEFINE_CLASS_PROPERTY(icon, S, Inventory) +static void SetIcon(FTextureID &icon, Baggage &bag, const char *i) { - PROP_STRING_PARM(i, 0); - if (i == NULL || i[0] == '\0') { - defaults->Icon.SetNull(); + icon.SetNull(); } else { - defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); - if (!defaults->Icon.isValid()) + icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); + if (!icon.isValid()) { // Don't print warnings if the item is for another game or if this is a shareware IWAD. // Strife's teaser doesn't contain all the icon graphics of the full game. - if ((info->GameFilter == GAME_Any || info->GameFilter & gameinfo.gametype) && + if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) && !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, - "Icon '%s' for '%s' not found\n", i, info->TypeName.GetChars()); + "Icon '%s' for '%s' not found\n", i, bag.Info->TypeName.GetChars()); } } } } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(icon, S, Inventory) +{ + PROP_STRING_PARM(i, 0); + SetIcon(defaults->Icon, bag, i); +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(althudicon, S, Inventory) +{ + PROP_STRING_PARM(i, 0); + SetIcon(defaults->AltHUDIcon, bag, i); +} + //========================================================================== // //========================================================================== @@ -1845,8 +1861,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory) { PROP_INT_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); - static_cast(info)->GiveQuest = i; + defaults->GiveQuest = i; } //========================================================================== @@ -2651,7 +2666,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) PROP_STRING_PARM(type, 3); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); static_cast(info)->PainFlashes.Insert(type, color); } } @@ -2702,7 +2716,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); defaults->HealingRadiusType = str; } @@ -2711,7 +2724,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); for (int i = 0; i < 5; i++) { PROP_DOUBLE_PARM(val, i); @@ -2724,7 +2736,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); PROP_STRING_PARM(val, 0); defaults->Portrait = val; } @@ -2736,7 +2747,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss { PROP_INT_PARM(slot, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); if (slot < 0 || slot > 9) { I_Error("Slot must be between 0 and 9."); diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index da915f170..28b20cdd5 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -24,7 +24,7 @@ class Inventory : Actor native native bool bCreateCopyMoved; native bool bInitEffectFailed; native meta String PickupMsg; - native meta int GiveQuest; + native /*meta*/ int GiveQuest; Default { From c77f6636f82cb3bd15050f454ea8845fd7dc4e4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 18:11:23 +0100 Subject: [PATCH 36/50] - moved the three remaining variables from PClassInventory to PClassActor so that PClassInventory can be removed. --- src/actor.h | 4 +- src/d_dehacked.cpp | 2 +- src/d_player.h | 6 +-- src/dobject.h | 1 - src/dobjtype.cpp | 1 - src/doomtype.h | 3 -- src/fragglescript/t_func.cpp | 14 +++---- src/g_inventory/a_pickups.cpp | 48 +---------------------- src/g_inventory/a_pickups.h | 16 +------- src/g_inventory/a_weapons.h | 2 +- src/info.cpp | 28 +++++++++++++ src/info.h | 5 +++ src/p_acs.cpp | 4 +- src/p_conversation.cpp | 8 +++- src/p_conversation.h | 2 +- src/p_mobj.cpp | 12 ++++-- src/p_usdf.cpp | 16 ++++---- src/p_user.cpp | 10 ++--- src/scripting/decorate/olddecorations.cpp | 2 +- src/scripting/thingdef_properties.cpp | 14 +++---- 20 files changed, 89 insertions(+), 109 deletions(-) diff --git a/src/actor.h b/src/actor.h index 4016d447b..0b33ed3e3 100644 --- a/src/actor.h +++ b/src/actor.h @@ -699,7 +699,7 @@ public: // Give an item to the actor and pick it up. // Returns true if the item pickup succeeded. - bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false); + bool GiveInventory (PClassActor *type, int amount, bool givecheat = false); // Removes the item from the inventory list. virtual void RemoveInventory (AInventory *item); @@ -736,7 +736,7 @@ public: AInventory *FirstInv (); // Tries to give the actor some ammo. - bool GiveAmmo (PClassInventory *type, int amount); + bool GiveAmmo (PClassActor *type, int amount); // Destroys all the inventory the actor is holding. void DestroyAllInventory (); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index c30fc64ae..8062faf5a 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1658,7 +1658,7 @@ static int PatchWeapon (int weapNum) { val = 5; } - info->AmmoType1 = (PClassInventory*)AmmoNames[val]; + info->AmmoType1 = AmmoNames[val]; if (info->AmmoType1 != NULL) { info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2; diff --git a/src/d_player.h b/src/d_player.h index b79e56862..f6009edec 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -110,9 +110,9 @@ public: void TweakSpeeds (double &forwardmove, double &sidemove); void MorphPlayerThink (); void ActivateMorphWeapon (); - AWeapon *PickNewWeapon (PClassInventory *ammotype); - AWeapon *BestWeapon (PClassInventory *ammotype); - void CheckWeaponSwitch(PClassInventory *ammotype); + AWeapon *PickNewWeapon (PClassActor *ammotype); + AWeapon *BestWeapon (PClassActor *ammotype); + void CheckWeaponSwitch(PClassActor *ammotype); void GiveDeathmatchInventory (); void FilterCoopRespawnInventory (APlayerPawn *oldplayer); diff --git a/src/dobject.h b/src/dobject.h index f3c290443..7b93a30c6 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -93,7 +93,6 @@ enum { CLASSREG_PClass, CLASSREG_PClassActor, - CLASSREG_PClassInventory, CLASSREG_PClassPlayerPawn, }; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f0e7b2fc1..486c72249 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2955,7 +2955,6 @@ PClass *ClassReg::RegisterClass() { &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, - &PClassInventory::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, }; diff --git a/src/doomtype.h b/src/doomtype.h index 248aee33b..11e4f96e2 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -155,12 +155,9 @@ struct PalEntry #endif }; -class PClassInventory; - class FTextureID { friend class FTextureManager; - friend FTextureID GetHUDIcon(PClassInventory *cls); friend void R_InitSpriteDefs(); public: diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index e8cde0222..68d940704 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -340,7 +340,7 @@ inline int T_FindFirstSectorFromTag(int tagnum) // Doom index is only supported for the 4 original ammo types // //========================================================================== -static PClassInventory * T_GetAmmo(const svalue_t &t) +static PClassActor * T_GetAmmo(const svalue_t &t) { const char * p; @@ -361,8 +361,8 @@ static PClassInventory * T_GetAmmo(const svalue_t &t) } p=DefAmmo[ammonum]; } - PClassInventory * am=dyn_cast(PClass::FindActor(p)); - if (am == NULL) + auto am = PClass::FindActor(p); + if (am == NULL || !am->IsKindOf(PClass::FindClass(NAME_Ammo))) { script_error("unknown ammo type : %s", p); return NULL; @@ -2434,8 +2434,8 @@ static void FS_GiveInventory (AActor *actor, const char * type, int amount) { type = "BasicArmorPickup"; } - PClassInventory * info = dyn_cast(PClass::FindActor (type)); - if (info == NULL) + auto info = PClass::FindActor (type); + if (info == NULL || !info->IsKindOf(RUNTIME_CLASS(AInventory))) { Printf ("Unknown inventory item: %s\n", type); return; @@ -2564,7 +2564,7 @@ void FParser::SF_PlayerKeys(void) void FParser::SF_PlayerAmmo(void) { int playernum, amount; - PClassInventory * ammotype; + PClassActor * ammotype; if (CheckArgs(2)) { @@ -2600,7 +2600,7 @@ void FParser::SF_PlayerAmmo(void) void FParser::SF_MaxPlayerAmmo() { int playernum, amount; - PClassInventory * ammotype; + PClassActor * ammotype; if (CheckArgs(2)) { diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 796036c2d..53e7d84ed 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -25,50 +25,6 @@ EXTERN_CVAR(Bool, sv_unlimited_pickup) -IMPLEMENT_CLASS(PClassInventory, false, false) - -PClassInventory::PClassInventory() -{ -} - -void PClassInventory::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory))); - Super::DeriveData(newclass); - PClassInventory *newc = static_cast(newclass); - - newc->PickupMsg = PickupMsg; - newc->ForbiddenToPlayerClass = ForbiddenToPlayerClass; - newc->RestrictedToPlayerClass = RestrictedToPlayerClass; -} - -size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass) -{ - size_t changed = Super::PointerSubstitution(oldclass, newclass); - AInventory *def = (AInventory*)Defaults; - if (def != NULL) - { - if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); - for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) - { - if (ForbiddenToPlayerClass[i] == oldclass) - { - ForbiddenToPlayerClass[i] = static_cast(newclass); - changed++; - } - } - for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) - { - if (RestrictedToPlayerClass[i] == oldclass) - { - RestrictedToPlayerClass[i] = static_cast(newclass); - changed++; - } - } - } - return changed; -} - void AInventory::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); @@ -95,7 +51,7 @@ DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) DEFINE_FIELD(AInventory, GiveQuest) -DEFINE_FIELD(PClassInventory, PickupMsg) +DEFINE_FIELD(PClassActor, PickupMsg) //=========================================================================== // @@ -545,7 +501,7 @@ DEFINE_ACTION_FUNCTION(AInventory, CanPickup) if (!toucher) ACTION_RETURN_BOOL(false); - PClassInventory *ai = self->GetClass(); + auto ai = self->GetClass(); // Is the item restricted to certain player classes? if (ai->RestrictedToPlayerClass.Size() != 0) { diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index f467ae984..3a67a3b6d 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -50,23 +50,9 @@ enum }; -class PClassInventory : public PClassActor -{ - DECLARE_CLASS(PClassInventory, PClassActor) -public: - PClassInventory(); - virtual void DeriveData(PClass *newclass); - virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass); - void Finalize(FStateDefinitions &statedef); - - FString PickupMsg; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; -}; - class AInventory : public AActor { - DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) + DECLARE_CLASS(AInventory, AActor) HAS_OBJECT_POINTERS public: diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 50862bc47..4ea56b355 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -92,7 +92,7 @@ class AWeapon : public AStateProvider HAS_OBJECT_POINTERS public: DWORD WeaponFlags; - PClassInventory *AmmoType1, *AmmoType2; // Types of ammo used by this weapon + PClassActor *AmmoType1, *AmmoType2; // Types of ammo used by this weapon int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon int AmmoUse1, AmmoUse2; // How much ammo to use with each shot diff --git a/src/info.cpp b/src/info.cpp index 48a22c2d4..90e2b7db9 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -349,6 +349,11 @@ void PClassActor::DeriveData(PClass *newclass) *newa->PainChances = *PainChances; } + // Inventory stuff + newa->PickupMsg = PickupMsg; + newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; + newa->RestrictedToPlayerClass = RestrictedToPlayerClass; + } //========================================================================== @@ -637,6 +642,29 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) changed++; } } + + for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) + { + if (ForbiddenToPlayerClass[i] == oldclass) + { + ForbiddenToPlayerClass[i] = static_cast(newclass); + changed++; + } + } + for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) + { + if (RestrictedToPlayerClass[i] == oldclass) + { + RestrictedToPlayerClass[i] = static_cast(newclass); + changed++; + } + } + AInventory *def = dyn_cast((AActor*)Defaults); + if (def != NULL) + { + if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); + } + return changed; } diff --git a/src/info.h b/src/info.h index 64be2d92f..28e75a121 100644 --- a/src/info.h +++ b/src/info.h @@ -317,6 +317,11 @@ public: FName MissileName; double MissileHeight; + // These are only valid for inventory items. + FString PickupMsg; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; + // For those times when being able to scan every kind of actor is convenient static TArray AllActorClasses; }; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 8b0075475..1423c48c4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1193,12 +1193,12 @@ static void GiveInventory (AActor *activator, const char *type, int amount) for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i]) - players[i].mo->GiveInventory(static_cast(info), amount); + players[i].mo->GiveInventory(info, amount); } } else { - activator->GiveInventory(static_cast(info), amount); + activator->GiveInventory(info, amount); } } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index e9ad0ff0d..54be79e3c 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -369,7 +369,9 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { - node->ItemCheck[j].Item = dyn_cast(GetStrifeType(speech.ItemCheck[j])); + auto inv = GetStrifeType(speech.ItemCheck[j]); + if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr; + node->ItemCheck[j].Item = inv; node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = speech.Link; @@ -513,7 +515,9 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->ItemCheck.Resize(3); for (k = 0; k < 3; ++k) { - reply->ItemCheck[k].Item = dyn_cast(GetStrifeType(rsp->Item[k])); + auto inv = GetStrifeType(rsp->Item[k]); + if (!inv->IsDescendantOf(RUNTIME_CLASS(AInventory))) inv = nullptr; + reply->ItemCheck[k].Item = inv; reply->ItemCheck[k].Amount = rsp->Count[k]; } reply->ItemCheckRequire.Clear(); diff --git a/src/p_conversation.h b/src/p_conversation.h index bd674aa10..8771d95ae 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -12,7 +12,7 @@ struct FBrokenLines; struct FStrifeDialogueItemCheck { - PClassInventory *Item; + PClassActor *Item; int Amount; }; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d39786311..846a25ca5 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -767,10 +767,12 @@ DEFINE_ACTION_FUNCTION(AActor, AddInventory) // //============================================================================ -bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) +bool AActor::GiveInventory(PClassActor *type, int amount, bool givecheat) { bool result = true; + if (type != nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false; + AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL; bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true; @@ -789,7 +791,7 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) item->ClearCounters(); if (!givecheat || amount > 0) { - if (type->IsDescendantOf (NAME_BasicArmorPickup) || type->IsDescendantOf(NAME_BasicArmorBonus)) + if (type->IsDescendantOf (PClass::FindActor(NAME_BasicArmorPickup)) || type->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus))) { item->IntVar(NAME_SaveAmount) *= amount; } @@ -1146,10 +1148,12 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) // //============================================================================ -bool AActor::GiveAmmo (PClassInventory *type, int amount) +bool AActor::GiveAmmo (PClassActor *type, int amount) { if (type != NULL) { + if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false; + AInventory *item = static_cast(Spawn (type)); if (item) { @@ -1542,7 +1546,7 @@ bool AActor::IsVisibleToPlayer() const bool visible = false; for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i) { - PClassPlayerPawn *cls = GetClass()->VisibleToPlayerClass[i]; + auto cls = GetClass()->VisibleToPlayerClass[i]; if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls)) { visible = true; diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index d40c542a1..f4ebe5ebd 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -57,21 +57,23 @@ class USDFParser : public UDMFParserBase PClassActor *CheckActorType(const char *key) { + PClassActor *type = nullptr; if (namespace_bits == St) { - return GetStrifeType(CheckInt(key)); + type = GetStrifeType(CheckInt(key)); } else if (namespace_bits == Zd) { PClassActor *cls = PClass::FindActor(CheckString(key)); - if (cls == NULL) + if (cls == nullptr) { sc.ScriptMessage("Unknown actor class '%s'", key); - return NULL; + return nullptr; } - return cls; + type = cls; } - return NULL; + if (type && type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return type; + return nullptr; } //=========================================================================== @@ -92,7 +94,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = dyn_cast(CheckActorType(key)); + check.Item = CheckActorType(key); break; case NAME_Amount: @@ -266,7 +268,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = dyn_cast(CheckActorType(key)); + check.Item = CheckActorType(key); break; case NAME_Count: diff --git a/src/p_user.cpp b/src/p_user.cpp index ab1920ae8..98221de1f 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -931,7 +931,7 @@ bool APlayerPawn::UseInventory (AInventory *item) // //=========================================================================== -AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype) { AWeapon *bestMatch = NULL; int bestOrder = INT_MAX; @@ -993,7 +993,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) // //=========================================================================== -AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) +AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype) { AWeapon *best = BestWeapon (ammotype); @@ -1021,7 +1021,7 @@ AWeapon *APlayerPawn::PickNewWeapon(PClassInventory *ammotype) // //=========================================================================== -void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) +void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype) { if (!player->userinfo.GetNeverSwitch() && player->PendingWeapon == WP_NOCHANGE && @@ -1040,7 +1040,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) { PARAM_SELF_PROLOGUE(APlayerPawn); - PARAM_OBJECT(ammotype, PClassInventory); + PARAM_OBJECT(ammotype, PClassActor); self->CheckWeaponSwitch(ammotype); return 0; } @@ -1346,7 +1346,7 @@ void APlayerPawn::GiveDefaultInventory () // HexenArmor must always be the first item in the inventory because // it provides player class based protection that should not affect // any other protection item. - PClassPlayerPawn *myclass = GetClass(); + auto myclass = GetClass(); GiveInventoryType(PClass::FindActor(NAME_HexenArmor)); auto harmor = FindInventory(NAME_HexenArmor); diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 575bbf0a4..50e8f9c6a 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -541,7 +541,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - static_cast(bag.Info)->PickupMsg = sc.String; + bag.Info->PickupMsg = sc.String; } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index d1273da18..7f363b623 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -97,7 +97,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool } static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); + return static_cast(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); } static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) { @@ -1699,12 +1699,12 @@ DEFINE_PROPERTY(distancecheck, S, Actor) //========================================================================== DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) { - static_cast(info)->RestrictedToPlayerClass.Clear(); + static_cast(info)->RestrictedToPlayerClass.Clear(); for(int i = 0;i < PROP_PARM_COUNT;++i) { PROP_STRING_PARM(n, i); if (*n != 0) - static_cast(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1713,12 +1713,12 @@ DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) //========================================================================== DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory) { - static_cast(info)->ForbiddenToPlayerClass.Clear(); + static_cast(info)->ForbiddenToPlayerClass.Clear(); for(int i = 0;i < PROP_PARM_COUNT;++i) { PROP_STRING_PARM(n, i); if (*n != 0) - static_cast(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); + static_cast(info)->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1817,8 +1817,8 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); - static_cast(info)->PickupMsg = str; + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->PickupMsg = str; } //========================================================================== From dd102caf13d2e558a680be604d12d12b5b651da7 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 8 Feb 2017 08:30:00 -0600 Subject: [PATCH 37/50] - Fixed: SetCamera didn't have the 'action' identifier, nor did it use the actual 'cam' actor provided, rendering it nonfunctional. --- src/p_actionfunctions.cpp | 10 +++++----- wadsrc/static/zscript/actor.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index ea271967b..518d2fb63 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -6923,18 +6923,18 @@ DEFINE_ACTION_FUNCTION(AActor, SetCamera) if (self->player == nullptr || self->player->mo != self) return 0; - if (camera == nullptr) + if (cam == nullptr) { - camera = self; + cam = self; revert = false; } AActor *oldcamera = self->player->camera; - self->player->camera = camera; + self->player->camera = cam; if (revert) self->player->cheats |= CF_REVERTPLEASE; - if (oldcamera != camera) + if (oldcamera != cam) { - R_ClearPastViewer(camera); + R_ClearPastViewer(cam); } return 0; } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9b6f42b88..ceda20bd8 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -498,7 +498,7 @@ class Actor : Thinker native native bool UsePuzzleItem(int PuzzleItemType); native float AccuracyFactor(); native bool MorphMonster (Class spawntype, int duration, int style, Class enter_flash, Class exit_flash); - native void SetCamera(Actor cam, bool revert = false); + action native void SetCamera(Actor cam, bool revert = false); // DECORATE compatible functions native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); From 68e9918ed5b3b110bca97567a9000c5d59c38523 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 19:10:11 +0100 Subject: [PATCH 38/50] - moved player color sets and pain flashes into global variables. There's simply never enough of them and they are used far too infrequently to justify the hassle of tagging along two TMaps per class. For what they provide, single global lists that handle all player classes at once are fully sufficient. --- src/d_main.cpp | 2 + src/d_netinfo.cpp | 4 +- src/d_player.h | 17 ++++--- src/doomtype.h | 2 + src/g_pch.h | 1 + src/menu/playerdisplay.cpp | 2 +- src/menu/playermenu.cpp | 6 +-- src/p_user.cpp | 73 ++++++++++++++++++++------- src/scripting/thingdef_properties.cpp | 14 ++--- src/v_blend.cpp | 2 +- 10 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index e91c2ccaa..e0cbcbefa 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2707,6 +2707,8 @@ void D_DoomMain (void) // delete all data that cannot be left until reinitialization V_ClearFonts(); // must clear global font pointers + ColorSets.Clear(); + PainFlashes.Clear(); R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. gameinfo.~gameinfo_t(); new (&gameinfo) gameinfo_t; // Reset gameinfo diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index d3ce8c943..62beb5460 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -156,7 +156,7 @@ int D_PlayerClassToInt (const char *classname) { for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) { - PClassPlayerPawn *type = PlayerClasses[i].Type; + auto type = PlayerClasses[i].Type; if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0) { @@ -180,7 +180,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet if (players[player].mo != NULL) { - colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet()); + colorset = GetColorSet(players[player].mo->GetClass(), info->GetColorSet()); } if (colorset != NULL) { diff --git a/src/d_player.h b/src/d_player.h index f6009edec..8a5415bc6 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -66,8 +66,11 @@ struct FPlayerColorSet ExtraRange Extra[6]; }; -typedef TMap FPlayerColorSetMap; -typedef TMap PainFlashList; +typedef TArray> PainFlashList; +typedef TArray> ColorSetList; + +extern PainFlashList PainFlashes; +extern ColorSetList ColorSets; class PClassPlayerPawn : public PClassActor { @@ -76,14 +79,8 @@ protected: public: PClassPlayerPawn(); virtual void DeriveData(PClass *newclass); - void EnumColorSets(TArray *out); - FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } - void SetPainFlash(FName type, PalEntry color); - bool GetPainFlash(FName type, PalEntry *color) const; FString DisplayName; // Display name (used in menus, etc.) - FPlayerColorSetMap ColorSets; - PainFlashList PainFlashes; }; FString GetPrintableDisplayName(PClassPlayerPawn *cls); @@ -541,12 +538,16 @@ public: // Make sure that a state is properly set after calling this unless // you are 100% sure the context already implies the layer exists. DPSprite *GetPSprite(PSPLayers layer); + + bool GetPainFlash(FName type, PalEntry *color) const; }; // Bookkeeping on players - state. extern player_t players[MAXPLAYERS]; void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale); +void EnumColorSets(PClassActor *pc, TArray *out); +FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum); inline void AActor::SetFriendPlayer(player_t *player) { diff --git a/src/doomtype.h b/src/doomtype.h index 11e4f96e2..c88ec842d 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -41,6 +41,8 @@ #endif #include +#include +#include #include "tarray.h" #include "name.h" #include "zstring.h" diff --git a/src/g_pch.h b/src/g_pch.h index 2c3676f5a..e5653796b 100644 --- a/src/g_pch.h +++ b/src/g_pch.h @@ -20,3 +20,4 @@ #include #include #include +#include diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index 821c2ea70..ba99aba36 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -435,7 +435,7 @@ void DListMenuItemPlayerDisplay::UpdateTranslation() if (mPlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, mPlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(mPlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 7116608b3..4126bc80b 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -680,7 +680,7 @@ void DPlayerMenu::UpdateTranslation() if (PlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, PlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(PlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -749,11 +749,11 @@ void DPlayerMenu::UpdateColorsets() if (li != NULL) { int sel = 0; - PlayerClass->Type->EnumColorSets(&PlayerColorSets); + EnumColorSets(PlayerClass->Type, &PlayerColorSets); li->SetString(0, "Custom"); for(unsigned i=0;iType->GetColorSet(PlayerColorSets[i]); + FPlayerColorSet *colorset = GetColorSet(PlayerClass->Type, PlayerColorSets[i]); li->SetString(i+1, colorset->Name); } int mycolorset = players[consoleplayer].userinfo.GetColorSet(); diff --git a/src/p_user.cpp b/src/p_user.cpp index 98221de1f..161d15121 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -84,6 +84,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO P_PredictionLerpReset(); } +ColorSetList ColorSets; +PainFlashList PainFlashes; + struct PredictPos { int gametic; @@ -551,23 +554,38 @@ void PClassPlayerPawn::DeriveData(PClass *newclass) PClassPlayerPawn *newp = static_cast(newclass); newp->DisplayName = DisplayName; - newp->ColorSets = ColorSets; } +//=========================================================================== +// +// EnumColorsets +// +// Only used by the menu so it doesn't really matter that it's a bit +// inefficient. +// +//=========================================================================== + static int intcmp(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } -void PClassPlayerPawn::EnumColorSets(TArray *out) +void EnumColorSets(PClassActor *cls, TArray *out) { - out->Clear(); - FPlayerColorSetMap::Iterator it(ColorSets); - FPlayerColorSetMap::Pair *pair; + TArray deleteds; - while (it.NextPair(pair)) + out->Clear(); + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - out->Push(pair->Key); + if (std::get<0>(ColorSets[i])->IsAncestorOf(cls)) + { + int v = std::get<1>(ColorSets[i]); + if (out->Find(v) == out->Size() && deleteds.Find(v) == deleteds.Size()) + { + if (std::get<2>(ColorSets[i]).Name == NAME_None) deleteds.Push(v); + else out->Push(v); + } + } } qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); } @@ -577,20 +595,41 @@ void PClassPlayerPawn::EnumColorSets(TArray *out) // //========================================================================== -bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const +FPlayerColorSet *GetColorSet(PClassActor *cls, int setnum) { - const PClassPlayerPawn *info = this; - - while (info != NULL) + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - const PalEntry *flash = info->PainFlashes.CheckKey(type); - if (flash != NULL) + if (std::get<1>(ColorSets[i]) == setnum && + std::get<0>(ColorSets[i])->IsAncestorOf(cls)) { - *color = *flash; + auto c = &std::get<2>(ColorSets[i]); + return c->Name != NAME_None ? c : nullptr; + } + } + return nullptr; +} + +//========================================================================== +// +// +//========================================================================== + +bool player_t::GetPainFlash(FName type, PalEntry *color) const +{ + PClass *info = mo->GetClass(); + + // go backwards through the list and return the first item with a + // matching damage type for an ancestor of our class. + // This will always return the best fit because any parent class + // must be processed before its children. + for (int i = PainFlashes.Size() - 1; i >= 0; i--) + { + if (std::get<1>(PainFlashes[i]) == type && + std::get<0>(PainFlashes[i])->IsAncestorOf(info)) + { + *color = std::get<2>(PainFlashes[i]); return true; } - // Try parent class - info = dyn_cast(info->ParentClass); } return false; } @@ -3238,8 +3277,6 @@ DEFINE_FIELD(APlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd) DEFINE_FIELD(PClassPlayerPawn, DisplayName) -DEFINE_FIELD(PClassPlayerPawn, ColorSets) -DEFINE_FIELD(PClassPlayerPawn, PainFlashes) DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 7f363b623..33d97dccf 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -69,6 +69,7 @@ #include "backend/vmbuilder.h" #include "a_keys.h" #include "g_levellocals.h" +#include "d_player.h" //========================================================================== // @@ -2386,8 +2387,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2413,8 +2413,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) } else if (color.Lump >= 0) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2431,8 +2430,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Remove(setnum); + FPlayerColorSet color; + memset(&color, 0, sizeof(color)); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2666,7 +2666,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) PROP_STRING_PARM(type, 3); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - static_cast(info)->PainFlashes.Insert(type, color); + PainFlashes.Push(std::make_tuple(info, type, color)); } } diff --git a/src/v_blend.cpp b/src/v_blend.cpp index ffc16cd5c..41e6fe7ff 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -123,7 +123,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int } PalEntry painFlash = CPlayer->mo->DamageFade; - CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); + CPlayer->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); if (painFlash.a != 0) { From 17a2666bd443b44eb65c4f1eac237ce34ea8601a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 19:42:24 +0100 Subject: [PATCH 39/50] - moved DisplayName, the last remaining PlayerPawn meta property, to PClassActor so that PClassPlayerPawn could be removed. Now all actors have the same metaclass and therefore it will always be the same size which will finally allow some needed changes to the type system which couldn't be done because it was occasionally necessary to replace tentatively created classes due to size mismatches. --- src/d_net.cpp | 2 +- src/d_player.h | 22 +++++------------ src/dobject.h | 1 - src/dobjtype.cpp | 1 - src/g_game.cpp | 2 +- src/g_inventory/a_pickups.h | 1 - src/g_inventory/a_weapons.cpp | 4 +-- src/g_inventory/a_weapons.h | 4 +-- src/g_shared/a_morph.cpp | 2 +- src/g_shared/a_morph.h | 2 +- src/info.cpp | 7 +++--- src/info.h | 10 +++++--- src/m_cheat.cpp | 6 ++--- src/m_cheat.h | 4 +-- src/menu/playermenu.cpp | 2 +- src/p_acs.cpp | 2 +- src/p_user.cpp | 35 ++++++--------------------- src/r_data/sprites.cpp | 20 +++++++-------- src/scripting/thingdef_properties.cpp | 3 +-- src/serializer.h | 5 ---- 20 files changed, 49 insertions(+), 86 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index c38a7cefe..97f6be9bb 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2539,7 +2539,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_MORPHEX: { s = ReadString (stream); - const char *msg = cht_Morph (players + player, dyn_cast(PClass::FindClass (s)), false); + const char *msg = cht_Morph (players + player, PClass::FindActor (s), false); if (player == consoleplayer) { Printf ("%s\n", *msg != '\0' ? msg : "Morph failed."); diff --git a/src/d_player.h b/src/d_player.h index 8a5415bc6..65f401f2d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -72,21 +72,11 @@ typedef TArray> ColorSetList; extern PainFlashList PainFlashes; extern ColorSetList ColorSets; -class PClassPlayerPawn : public PClassActor -{ - DECLARE_CLASS(PClassPlayerPawn, PClassActor); -protected: -public: - PClassPlayerPawn(); - virtual void DeriveData(PClass *newclass); - - FString DisplayName; // Display name (used in menus, etc.) -}; -FString GetPrintableDisplayName(PClassPlayerPawn *cls); +FString GetPrintableDisplayName(PClassActor *cls); class APlayerPawn : public AActor { - DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) + DECLARE_CLASS(APlayerPawn, AActor) HAS_OBJECT_POINTERS public: @@ -271,7 +261,7 @@ public: bool CheckSkin (int skin); - PClassPlayerPawn *Type; + PClassActor *Type; DWORD Flags; TArray Skins; }; @@ -343,7 +333,7 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_PlayerClass)); } - PClassPlayerPawn *GetPlayerClassType() const + PClassActor *GetPlayerClassType() const { return PlayerClasses[GetPlayerClassNum()].Type; } @@ -401,7 +391,7 @@ public: userinfo_t userinfo; // [RH] who is this? - PClassPlayerPawn *cls; // class of associated PlayerPawn + PClassActor *cls; // class of associated PlayerPawn float DesiredFOV; // desired field of vision float FOV; // current field of vision @@ -459,7 +449,7 @@ public: short fixedcolormap; // can be set to REDCOLORMAP, etc. short fixedlightlevel; int morphTics; // player is a chicken/pig if > 0 - PClassPlayerPawn *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed + PClassActor *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) TObjPtr PremorphWeapon; // ready weapon before morphing diff --git a/src/dobject.h b/src/dobject.h index 7b93a30c6..6797d2436 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -93,7 +93,6 @@ enum { CLASSREG_PClass, CLASSREG_PClassActor, - CLASSREG_PClassPlayerPawn, }; struct ClassReg diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 486c72249..76e6a3786 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2955,7 +2955,6 @@ PClass *ClassReg::RegisterClass() { &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, - &PClassPlayerPawn::RegistrationInfo, }; // Skip classes that have already been registered diff --git a/src/g_game.cpp b/src/g_game.cpp index e5c327472..9417f40b9 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1361,7 +1361,7 @@ void G_PlayerReborn (int player) BYTE currclass; userinfo_t userinfo; // [RH] Save userinfo APlayerPawn *actor; - PClassPlayerPawn *cls; + PClassActor *cls; FString log; DBot *Bot; //Added by MC: diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 3a67a3b6d..817fcf176 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -9,7 +9,6 @@ class player_t; class FConfigFile; -class PClassPlayerPawn; struct visstyle_t; /************************************************************************/ diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index afa55cc10..839de49a8 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1058,7 +1058,7 @@ void FWeaponSlots::SetFromGameInfo() // //=========================================================================== -void FWeaponSlots::StandardSetup(PClassPlayerPawn *type) +void FWeaponSlots::StandardSetup(PClassActor *type) { SetFromPlayer(type); AddExtraWeapons(); @@ -1151,7 +1151,7 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) // //=========================================================================== -void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type) +void FWeaponSlots::SetFromPlayer(PClassActor *type) { Clear(); auto Slot = ((APlayerPawn*)GetDefaultByType(type))->Slot; diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 4ea56b355..606c96e98 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -65,8 +65,8 @@ struct FWeaponSlots ESlotDef AddDefaultWeapon (int slot, PClassActor *type); void AddExtraWeapons(); void SetFromGameInfo(); - void SetFromPlayer(PClassPlayerPawn *type); - void StandardSetup(PClassPlayerPawn *type); + void SetFromPlayer(PClassActor *type); + void StandardSetup(PClassActor *type); void LocalSetup(PClassActor *type); void SendDifferences(int playernum, const FWeaponSlots &other); int RestoreSlots (FConfigFile *config, const char *section); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 246073010..359e8a174 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -33,7 +33,7 @@ void InitAllPowerupEffects(AInventory *item); // //--------------------------------------------------------------------------- -bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) +bool P_MorphPlayer (player_t *activator, player_t *p, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) { AInventory *item; APlayerPawn *morphed; diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index e770e418e..1c0047c69 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -35,7 +35,7 @@ class AActor; class player_t; class AMorphedMonster; -bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0, +bool P_MorphPlayer (player_t *activator, player_t *player, PClassActor *morphclass, int duration = 0, int style = 0, PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL); bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false); bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0, diff --git a/src/info.cpp b/src/info.cpp index 90e2b7db9..28509a0db 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -354,6 +354,7 @@ void PClassActor::DeriveData(PClass *newclass) newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; newa->RestrictedToPlayerClass = RestrictedToPlayerClass; + newa->DisplayName = DisplayName; } //========================================================================== @@ -638,7 +639,7 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (VisibleToPlayerClass[i] == oldclass) { - VisibleToPlayerClass[i] = static_cast(newclass); + VisibleToPlayerClass[i] = static_cast(newclass); changed++; } } @@ -647,7 +648,7 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (ForbiddenToPlayerClass[i] == oldclass) { - ForbiddenToPlayerClass[i] = static_cast(newclass); + ForbiddenToPlayerClass[i] = static_cast(newclass); changed++; } } @@ -655,7 +656,7 @@ size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { if (RestrictedToPlayerClass[i] == oldclass) { - RestrictedToPlayerClass[i] = static_cast(newclass); + RestrictedToPlayerClass[i] = static_cast(newclass); changed++; } } diff --git a/src/info.h b/src/info.h index 28e75a121..564342d76 100644 --- a/src/info.h +++ b/src/info.h @@ -235,7 +235,6 @@ private: }; class DDropItem; -class PClassPlayerPawn; class PClassActor : public PClass { @@ -287,7 +286,7 @@ public: DmgFactors *DamageFactors; PainChanceList *PainChances; - TArray VisibleToPlayerClass; + TArray VisibleToPlayerClass; FString Obituary; // Player was killed by this actor FString HitObituary; // Player was killed by this actor in melee @@ -319,8 +318,11 @@ public: // These are only valid for inventory items. FString PickupMsg; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; + + // This is from PClassPlayerPawn + FString DisplayName; // For those times when being able to scan every kind of actor is convenient static TArray AllActorClasses; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index bf687c09d..15dd90a07 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -170,7 +170,7 @@ void cht_DoCheat (player_t *player, int cheat) break; case CHT_MORPH: - msg = cht_Morph (player, static_cast(PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer)), true); + msg = cht_Morph (player, PClass::FindActor (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer), true); break; case CHT_NOTARGET: @@ -548,13 +548,13 @@ void cht_DoCheat (player_t *player, int cheat) Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg); } -const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo) +const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo) { if (player->mo == NULL) { return ""; } - PClassPlayerPawn *oldclass = player->mo->GetClass(); + auto oldclass = player->mo->GetClass(); // Set the standard morph style for the current game int style = MORPH_UNDOBYTOMEOFPOWER; diff --git a/src/m_cheat.h b/src/m_cheat.h index 11f89c4d7..baab5a451 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -29,12 +29,12 @@ // [RH] Functions that actually perform the cheating class player_t; -class PClassPlayerPawn; +class PClassActor; void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); void cht_Suicide (player_t *player); -const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo); +const char *cht_Morph (player_t *player, PClassActor *morphclass, bool quickundo); #endif diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 4126bc80b..add8e5680 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -899,7 +899,7 @@ void DPlayerMenu::ClassChanged (DMenuItemBase *li) players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1); PickPlayerClass(); - cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->DisplayName.GetChars()); + cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(PlayerClass->Type).GetChars()); UpdateSkins(); UpdateColorsets(); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 1423c48c4..197a0616d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -9491,7 +9491,7 @@ scriptwait: { int tag = STACK(7); FName playerclass_name = FBehavior::StaticLookupString(STACK(6)); - PClassPlayerPawn *playerclass = dyn_cast(PClass::FindClass (playerclass_name)); + auto playerclass = PClass::FindActor (playerclass_name); FName monsterclass_name = FBehavior::StaticLookupString(STACK(5)); PClassActor *monsterclass = PClass::FindActor(monsterclass_name); int duration = STACK(4); diff --git a/src/p_user.cpp b/src/p_user.cpp index 161d15121..78882b52b 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -148,7 +148,7 @@ bool FPlayerClass::CheckSkin (int skin) // //=========================================================================== -FString GetPrintableDisplayName(PClassPlayerPawn *cls) +FString GetPrintableDisplayName(PClassActor *cls) { // Fixme; This needs a decent way to access the string table without creating a mess. // [RH] ???? @@ -167,7 +167,7 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name) Printf("Invalid player class '%s'\n", name); return false; } - else if (static_cast(ti)->DisplayName.IsEmpty()) + else if (ti->DisplayName.IsEmpty()) { Printf ("Missing displayname for player class '%s'\n", name); return false; @@ -186,7 +186,7 @@ void SetupPlayerClasses () if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i])) { newclass.Flags = 0; - newclass.Type = static_cast(cls); + newclass.Type = cls; if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU)) { newclass.Flags |= PCF_NOMENU; @@ -214,7 +214,7 @@ CCMD (addplayerclass) { FPlayerClass newclass; - newclass.Type = static_cast(ti); + newclass.Type = ti; newclass.Flags = 0; int arg = 2; @@ -535,27 +535,6 @@ int player_t::GetSpawnClass() return static_cast(GetDefaultByType(type))->SpawnMask; } -//=========================================================================== -// -// PClassPlayerPawn -// -//=========================================================================== - -IMPLEMENT_CLASS(PClassPlayerPawn, false, false) - -PClassPlayerPawn::PClassPlayerPawn() -{ -} - -void PClassPlayerPawn::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - Super::DeriveData(newclass); - PClassPlayerPawn *newp = static_cast(newclass); - - newp->DisplayName = DisplayName; -} - //=========================================================================== // // EnumColorsets @@ -1247,7 +1226,7 @@ const char *APlayerPawn::GetSoundClass() const } // [GRB] - PClassPlayerPawn *pclass = GetClass(); + auto pclass = GetClass(); return SoundClass != NAME_None? SoundClass.GetChars() : "player"; } @@ -1729,7 +1708,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) // [GRB] Parameterized version if (spawntype == NULL || !spawntype->IsDescendantOf("PlayerChunk")) { - spawntype = dyn_cast(PClass::FindClass("BloodySkull")); + spawntype = PClass::FindActor("BloodySkull"); if (spawntype == NULL) return 0; } @@ -3276,7 +3255,7 @@ DEFINE_FIELD(APlayerPawn, HexenArmor) DEFINE_FIELD(APlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd) -DEFINE_FIELD(PClassPlayerPawn, DisplayName) +DEFINE_FIELD(PClassActor, DisplayName) DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index be44e9d82..c3f73760d 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -517,7 +517,7 @@ void R_InitSkins (void) int lastlump; int aliasid; bool remove; - PClassPlayerPawn *basetype, *transtype; + PClassActor *basetype, *transtype; key[sizeof(key)-1] = 0; i = PlayerClasses.Size () - 1; @@ -602,11 +602,11 @@ void R_InitSkins (void) else if (0 == stricmp (key, "game")) { if (gameinfo.gametype == GAME_Heretic) - basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); + basetype = PClass::FindActor(NAME_HereticPlayer); else if (gameinfo.gametype == GAME_Strife) - basetype = dyn_cast(PClass::FindActor(NAME_StrifePlayer)); + basetype = PClass::FindActor(NAME_StrifePlayer); else - basetype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = PClass::FindActor(NAME_DoomPlayer); transtype = basetype; @@ -614,7 +614,7 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - transtype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); + transtype = PClass::FindActor(NAME_HereticPlayer); skins[i].othergame = true; } else if (gameinfo.gametype != GAME_Heretic) @@ -633,7 +633,7 @@ void R_InitSkins (void) { if (gameinfo.gametype == GAME_Heretic) { - transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + transtype = PClass::FindActor(NAME_DoomPlayer); skins[i].othergame = true; } else if (!(gameinfo.gametype & GAME_DoomChex)) @@ -709,12 +709,12 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - basetype = transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = transtype = PClass::FindActor(NAME_DoomPlayer); } else if (gameinfo.gametype == GAME_Heretic) { - basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); - transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); + basetype = PClass::FindActor(NAME_HereticPlayer); + transtype = PClass::FindActor(NAME_DoomPlayer); skins[i].othergame = true; } else @@ -734,7 +734,7 @@ void R_InitSkins (void) remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) { - PClassPlayerPawn *type = PlayerClasses[j].Type; + auto type = PlayerClasses[j].Type; auto type_def = ((APlayerPawn*)GetDefaultByType(type)); if (type->IsDescendantOf (basetype) && diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 33d97dccf..33f455e3d 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2277,8 +2277,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->DisplayName = str; + info->DisplayName = str; } //========================================================================== diff --git a/src/serializer.h b/src/serializer.h index e4dc8f226..4f0d90cec 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -246,11 +246,6 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimat template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def); -template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, PClassPlayerPawn *&clst, PClassPlayerPawn **def) -{ - return Serialize(arc, key, (PClassActor *&)clst, (PClassActor **)def); -} - FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode); template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) { From 9499c22dfe191294bdb65ef87b117941ee2a8970 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 19:52:33 +0100 Subject: [PATCH 40/50] - restored ZDoom 2.8.1's version of FindClassTentative which just modified the existing class instead of replacing it and having to run a costly and volatile PointerSubstitution call to replace all pointers to the old one. --- src/dobjtype.cpp | 56 ++++++++++---------------------------- src/scripting/thingdef.cpp | 5 ++-- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 76e6a3786..72bf033b0 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2029,7 +2029,7 @@ void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const { - if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ElementType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { // Add to the list of pointer arrays for this class. special->Push(offset); @@ -3238,48 +3238,31 @@ void PClass::DeriveData(PClass *newclass) PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { - assert (size >= Size); + assert(size >= Size); PClass *type; bool notnew; - size_t bucket; - PClass *existclass = static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket)); + const PClass *existclass = FindClass(name); // This is a placeholder so fill it in - if (existclass != nullptr) + if (existclass != NULL && existclass->Size == (unsigned)-1) { - if (existclass->Size == TentativeClass) + type = const_cast(existclass); + if (!IsDescendantOf(type->ParentClass)) { - if (!IsDescendantOf(existclass->ParentClass)) - { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), existclass->ParentClass->TypeName.GetChars()); - } - - if (size == TentativeClass) - { - // see if we can reuse the existing class. This is only possible if the inheritance is identical. Otherwise it needs to be replaced. - if (this == existclass->ParentClass) - { - existclass->ObjectFlags &= OF_Transient; - return existclass; - } - } - notnew = true; - } - else - { - // a different class with the same name already exists. Let the calling code deal with this. - return nullptr; + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } + DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); + notnew = true; } else { + type = static_cast(GetClass()->CreateNew()); notnew = false; } - // Create a new type object of the same type as us. (We may be a derived class of PClass.) - type = static_cast(GetClass()->CreateNew()); - + type->TypeName = name; + type->bRuntimeClass = true; Derive(type, name); type->Size = size; if (size != TentativeClass) @@ -3288,22 +3271,13 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->Virtuals = Virtuals; DeriveData(type); } + else + type->ObjectFlags &= OF_Transient; + if (!notnew) { type->InsertIntoHash(); } - else - { - TypeTable.ReplaceType(type, existclass, bucket); - StaticPointerSubstitution(existclass, type, true); // replace the old one, also in the actor defaults. - // Delete the old class from the class lists, both the full one and the actor list. - auto index = PClassActor::AllActorClasses.Find(static_cast(existclass)); - if (index < PClassActor::AllActorClasses.Size()) PClassActor::AllActorClasses.Delete(index); - index = PClass::AllClasses.Find(existclass); - if (index < PClass::AllClasses.Size()) PClass::AllClasses.Delete(index); - // Now we can destroy the old class as nothing should reference it anymore - existclass->Destroy(); - } return type; } diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 51fb0239c..a43c741ce 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -396,8 +396,9 @@ void LoadActors() { Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::WarnCounter++; - DObject::StaticPointerSubstitution(ti, nullptr); - PClassActor::AllActorClasses.Delete(i); + // the class must be rendered harmless so that it won't cause problems. + ti->ParentClass = RUNTIME_CLASS(AActor); + ti->Size = sizeof(AActor); } else { From 8277299135163d3a8eab2b2f937a6c58f93bdac5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 20:37:22 +0100 Subject: [PATCH 41/50] - Turned DropItem into a plain struct again like it was before the scripting branch got merged. Making this an object had little to no advantage, except being able to remove the deleter code. Now, with some of the class data already being allocated in a memory arena so that freeing it is easier, this can also be used for the drop item lists which makes it unnecessary to subject them to the GC. This also merges the memory arenas for VM functions and flat pointers because both get deleted at the same time so they can share the same one. --- src/actor.h | 9 +++------ src/d_dehacked.cpp | 2 +- src/dobjtype.cpp | 9 ++++----- src/g_shared/a_action.cpp | 2 +- src/info.cpp | 9 ++------- src/info.h | 7 +++---- src/p_mobj.cpp | 16 +++++----------- src/p_user.cpp | 4 ++-- src/scripting/thingdef.h | 4 ++-- src/scripting/thingdef_properties.cpp | 6 ++---- src/scripting/vm/vm.h | 5 +++-- src/scripting/vm/vmframe.cpp | 3 +-- wadsrc/static/zscript/base.txt | 2 +- 13 files changed, 30 insertions(+), 48 deletions(-) diff --git a/src/actor.h b/src/actor.h index 0b33ed3e3..13511b617 100644 --- a/src/actor.h +++ b/src/actor.h @@ -572,12 +572,9 @@ struct FLinkContext msecnode_t *render_list = nullptr; }; -class DDropItem : public DObject +struct FDropItem { - DECLARE_CLASS(DDropItem, DObject) - HAS_OBJECT_POINTERS -public: - DDropItem *Next; + FDropItem *Next; FName Name; int Probability; int Amount; @@ -610,7 +607,7 @@ public: return (AActor *)(this->GetClass()->Defaults); } - DDropItem *GetDropItems() const; + FDropItem *GetDropItems() const; // Return true if the monster should use a missile attack, false for melee bool SuggestMissileAttack (double dist); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 8062faf5a..36c32bf5b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1983,7 +1983,7 @@ static int PatchMisc (int dummy) player->health = deh.StartHealth; // Hm... I'm not sure that this is the right way to change this info... - DDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; + FDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; while (di != NULL) { if (di->Name == NAME_Clip) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 72bf033b0..68d30dc31 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -64,8 +64,7 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. +FMemArena ClassDataAllocator(32768); // use this for all static class data that can be released in bulk when the type system is shut down. FTypeTable TypeTable; TArray PClass::AllClasses; @@ -2858,7 +2857,7 @@ void PClass::StaticShutdown () // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. TypeTable.Clear(); Namespaces.ReleaseSymbols(); - FlatpointerArena.FreeAllBlocks(); + ClassDataAllocator.FreeAllBlocks(); bShutdown = true; for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i) @@ -3448,7 +3447,7 @@ void PClass::BuildFlatPointers () { } // Concatenate them into a new array - size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); + size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); @@ -3514,7 +3513,7 @@ void PClass::BuildArrayPointers() } // Concatenate them into a new array - size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); + size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index aed8457f8..2d1a95cdd 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -42,7 +42,7 @@ void A_Unblock(AActor *self, bool drop) // If the actor has attached metadata for items to drop, drop those. if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] { - DDropItem *di = self->GetDropItems(); + auto di = self->GetDropItems(); if (di != NULL) { diff --git a/src/info.cpp b/src/info.cpp index 28509a0db..58c7241ad 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -176,11 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex) ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); } -IMPLEMENT_CLASS(PClassActor, false, true) - -IMPLEMENT_POINTERS_START(PClassActor) - IMPLEMENT_POINTER(DropItems) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClassActor, false, false) //========================================================================== // @@ -394,10 +390,9 @@ bool PClassActor::SetReplacement(FName replaceName) // //========================================================================== -void PClassActor::SetDropItems(DDropItem *drops) +void PClassActor::SetDropItems(FDropItem *drops) { DropItems = drops; - GC::WriteBarrier(this, DropItems); } diff --git a/src/info.h b/src/info.h index 564342d76..05785f90b 100644 --- a/src/info.h +++ b/src/info.h @@ -234,12 +234,11 @@ private: static DamageTypeDefinition *Get(FName type); }; -class DDropItem; +struct FDropItem; class PClassActor : public PClass { DECLARE_CLASS(PClassActor, PClass); - HAS_OBJECT_POINTERS; protected: public: static void StaticInit (); @@ -256,7 +255,7 @@ public: void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); bool SetReplacement(FName replaceName); - void SetDropItems(DDropItem *drops); + void SetDropItems(FDropItem *drops); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); @@ -303,7 +302,7 @@ public: FName BloodType2; // Bloopsplatter replacement type FName BloodType3; // AxeBlood replacement type - DDropItem *DropItems; + FDropItem *DropItems; FString SourceLumpName; FIntCVar *distancecheck; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 846a25ca5..2650224be 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7492,7 +7492,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) } -DDropItem *AActor::GetDropItems() const +FDropItem *AActor::GetDropItems() const { return GetClass()->DropItems; } @@ -8100,16 +8100,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors) // //---------------------------------------------------------------------------- -IMPLEMENT_CLASS(DDropItem, false, true) - -IMPLEMENT_POINTERS_START(DDropItem) -IMPLEMENT_POINTER(Next) -IMPLEMENT_POINTERS_END - -DEFINE_FIELD(DDropItem, Next) -DEFINE_FIELD(DDropItem, Name) -DEFINE_FIELD(DDropItem, Probability) -DEFINE_FIELD(DDropItem, Amount) +DEFINE_FIELD(FDropItem, Next) +DEFINE_FIELD(FDropItem, Name) +DEFINE_FIELD(FDropItem, Probability) +DEFINE_FIELD(FDropItem, Amount) void PrintMiscActorInfo(AActor *query) { diff --git a/src/p_user.cpp b/src/p_user.cpp index 78882b52b..b0d1d127f 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1384,7 +1384,7 @@ void APlayerPawn::GiveDefaultInventory () AddInventory (barmor); // Now add the items from the DECORATE definition - DDropItem *di = GetDropItems(); + auto di = GetDropItems(); while (di) { @@ -1514,7 +1514,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) AInventory *item; // kgDROP - start - modified copy from a_action.cpp - DDropItem *di = weap->GetDropItems(); + auto di = weap->GetDropItems(); if (di != NULL) { diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 37c247cbe..e98aeed88 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -110,7 +110,7 @@ FScriptPosition & GetStateSource(FState *state); // Extra info maintained while defining an actor. // //========================================================================== -class DDropItem; +class FDropItem; struct Baggage { @@ -126,7 +126,7 @@ struct Baggage int Lumpnum; FStateDefinitions statedef; - DDropItem *DropItemList; + FDropItem *DropItemList; FScriptPosition ScriptPosition; }; diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 33f455e3d..50b81310c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -921,7 +921,7 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) bag.DropItemList = NULL; } - DDropItem *di = new DDropItem; + FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem)); di->Name = type; di->Probability = 255; @@ -939,7 +939,6 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== @@ -2685,7 +2684,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) bag.DropItemList = NULL; } - DDropItem *di = new DDropItem; + FDropItem *di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem)); di->Name = str; di->Probability = 255; @@ -2697,7 +2696,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) } di->Next = bag.DropItemList; bag.DropItemList = di; - GC::WriteBarrier(di); } //========================================================================== diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 6d758f1bc..36619ef5b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -8,6 +8,8 @@ #include "doomerrors.h" #include "memarena.h" +extern FMemArena ClassDataAllocator; + #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return #define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function @@ -716,7 +718,7 @@ public: void *operator new(size_t size) { - return Allocator.Alloc(size); + return ClassDataAllocator.Alloc(size); } void operator delete(void *block) {} @@ -729,7 +731,6 @@ public: } AllFunctions.Clear(); } - static FMemArena Allocator; static TArray AllFunctions; protected: }; diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 5fa82ad0c..d5eaed5bd 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -43,7 +43,6 @@ int VMCalls[10]; IMPLEMENT_CLASS(VMException, false, false) -FMemArena VMFunction::Allocator(32768); TArray VMFunction::AllFunctions; @@ -95,7 +94,7 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko assert(numkonsts >= 0 && numkonsts <= 65535); assert(numkonsta >= 0 && numkonsta <= 65535); assert(numlinenumbers >= 0 && numlinenumbers <= 65535); - void *mem = Allocator.Alloc(numops * sizeof(VMOP) + + void *mem = ClassDataAllocator.Alloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 83d714684..1ff8a5e92 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -256,7 +256,7 @@ class BlockThingsIterator : Object native native bool Next(); } -class DropItem : Object native +struct DropItem native { native readonly DropItem Next; native readonly name Name; From 36a07b8e6ead5c52f614da44ad82b36485d2518c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 22:43:20 +0100 Subject: [PATCH 42/50] - remove all type table entries from garbage collection. Like the symbols and the VM functions this is data that is static from startup until shutdown and has no need to be subjected to garbage collection. All things combined this reduces the amount of GC-sensitive objects at startup from 9600 to 600. --- src/dobjgc.cpp | 19 +++-- src/dobjtype.cpp | 125 +++++------------------------- src/dobjtype.h | 12 --- src/g_inventory/a_weapons.cpp | 3 - src/scripting/backend/codegen.cpp | 2 +- src/scripting/thingdef.h | 2 +- 6 files changed, 34 insertions(+), 129 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index e6ff9c734..8e9333934 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -254,6 +254,14 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) curr->Destroy(); } + /* + if (curr->IsKindOf(RUNTIME_CLASS(PSymbol))) + Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast(curr)->SymbolName.GetChars()); + else if (curr->IsKindOf(RUNTIME_CLASS(PType))) + Printf("Collecting %s, name = %s\n", curr->GetClass()->TypeName.GetChars(), static_cast(curr)->DescriptiveName()); + else + Printf("Collecting %s\n", curr->GetClass()->TypeName.GetChars()); + */ curr->ObjectFlags |= OF_Cleanup; delete curr; finalized++; @@ -363,12 +371,6 @@ static void MarkRoot() } Mark(SectorMarker); Mark(interpolator.Head); - // Mark types - TypeTable.Mark(); - for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) - { - Mark(PClass::AllClasses[i]); - } // Mark global symbols Namespaces.MarkSymbols(); // Mark bot stuff. @@ -449,8 +451,8 @@ static size_t SingleStep() { // Nothing more to sweep? State = GCS_Finalize; } - assert(old >= AllocBytes); - Estimate -= old - AllocBytes; + //assert(old >= AllocBytes); + Estimate -= MAX(0, old - AllocBytes); return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST; } @@ -550,6 +552,7 @@ void FullGC() void Barrier(DObject *pointing, DObject *pointed) { + assert(pointed->GetClass() < (void*)0x1000000000000000); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointed->IsWhite() && !pointed->IsDead()); assert(State != GCS_Finalize && State != GCS_Pause); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 68d30dc31..34709cddc 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -151,11 +151,7 @@ void DumpTypeTable() /* PType ******************************************************************/ -IMPLEMENT_CLASS(PType, true, true) - -IMPLEMENT_POINTERS_START(PType) - IMPLEMENT_POINTER(HashNext) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PType, true, false) //========================================================================== // @@ -444,11 +440,7 @@ IMPLEMENT_CLASS(PCompoundType, true, false) /* PNamedType *************************************************************/ -IMPLEMENT_CLASS(PNamedType, true, true) - -IMPLEMENT_POINTERS_START(PNamedType) - IMPLEMENT_POINTER(Outer) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PNamedType, true, false) //========================================================================== // @@ -1303,11 +1295,7 @@ PStateLabel::PStateLabel() /* PPointer ***************************************************************/ -IMPLEMENT_CLASS(PPointer, false, true) - -IMPLEMENT_POINTERS_START(PPointer) - IMPLEMENT_POINTER(PointedType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PPointer, false, false) //========================================================================== // @@ -1510,11 +1498,7 @@ bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) cons /* PClassPointer **********************************************************/ -IMPLEMENT_CLASS(PClassPointer,false, true) - -IMPLEMENT_POINTERS_START(PClassPointer) - IMPLEMENT_POINTER(ClassRestriction) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClassPointer,false, false) //========================================================================== // @@ -1595,11 +1579,7 @@ PClassPointer *NewClassPointer(PClass *restrict) /* PEnum ******************************************************************/ -IMPLEMENT_CLASS(PEnum, false, true) - -IMPLEMENT_POINTERS_START(PEnum) - IMPLEMENT_POINTER(Outer) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PEnum, false, false) //========================================================================== // @@ -1651,11 +1631,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) /* PArray *****************************************************************/ -IMPLEMENT_CLASS(PArray, false, true) - -IMPLEMENT_POINTERS_START(PArray) - IMPLEMENT_POINTER(ElementType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PArray, false, false) //========================================================================== // @@ -1888,11 +1864,7 @@ PResizableArray *NewResizableArray(PType *type) /* PDynArray **************************************************************/ -IMPLEMENT_CLASS(PDynArray, false, true) - -IMPLEMENT_POINTERS_START(PDynArray) - IMPLEMENT_POINTER(ElementType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PDynArray, false, false) //========================================================================== // @@ -2143,12 +2115,7 @@ PDynArray *NewDynArray(PType *type) /* PMap *******************************************************************/ -IMPLEMENT_CLASS(PMap, false, true) - -IMPLEMENT_POINTERS_START(PMap) - IMPLEMENT_POINTER(KeyType) - IMPLEMENT_POINTER(ValueType) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PMap, false, false) //========================================================================== // @@ -2645,11 +2612,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray /* PClass *****************************************************************/ -IMPLEMENT_CLASS(PClass, false, true) - -IMPLEMENT_POINTERS_START(PClass) - IMPLEMENT_POINTER(ParentClass) -IMPLEMENT_POINTERS_END +IMPLEMENT_CLASS(PClass, false, false) //========================================================================== // @@ -2855,18 +2818,10 @@ void PClass::StaticShutdown () bVMOperational = false; // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. + bShutdown = true; TypeTable.Clear(); Namespaces.ReleaseSymbols(); ClassDataAllocator.FreeAllBlocks(); - bShutdown = true; - - for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i) - { - PClass *type = PClass::AllClasses[i]; - PClass::AllClasses[i] = NULL; - type->Destroy(); - } - AllClasses.Clear(); PClassActor::AllActorClasses.Clear(); @@ -3591,31 +3546,6 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si return nullptr; } -//========================================================================== -// -// FTypeTable :: ReplaceType -// -// Replaces an existing type in the table with a new version of the same -// type. For use when redefining actors in DECORATE. Does nothing if the -// old version is not in the table. -// -//========================================================================== - -void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) -{ - for (PType **type_p = &TypeHash[bucket]; *type_p != nullptr; type_p = &(*type_p)->HashNext) - { - PType *type = *type_p; - if (type == oldtype) - { - newtype->HashNext = type->HashNext; - type->HashNext = nullptr; - *type_p = newtype; - break; - } - } -} - //========================================================================== // // FTypeTable :: AddType - Fully Parameterized Version @@ -3632,7 +3562,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t type->TypeTableType = metatype; type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; - GC::WriteBarrier(type); + type->Release(); } //========================================================================== @@ -3655,7 +3585,7 @@ void FTypeTable::AddType(PType *type) type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; - GC::WriteBarrier(type); + type->Release(); } //========================================================================== @@ -3694,36 +3624,23 @@ size_t FTypeTable::Hash(const PClass *p1, intptr_t p2, intptr_t p3) } } -//========================================================================== -// -// FTypeTable :: Mark -// -// Mark all types in this table for the garbage collector. -// -//========================================================================== - -void FTypeTable::Mark() -{ - for (int i = HASH_SIZE - 1; i >= 0; --i) - { - if (TypeHash[i] != nullptr) - { - GC::Mark(TypeHash[i]); - } - } -} - //========================================================================== // // FTypeTable :: Clear // -// Removes everything from the table. We let the garbage collector worry -// about deleting them. -// //========================================================================== void FTypeTable::Clear() { + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr;) + { + auto next = ty->HashNext; + delete ty; + ty = next; + } + } memset(TypeHash, 0, sizeof(TypeHash)); } diff --git a/src/dobjtype.h b/src/dobjtype.h index 42280a12b..cc0a17da8 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -77,7 +77,6 @@ struct ZCC_ExprConstant; class PType : public PTypeBase { DECLARE_ABSTRACT_CLASS(PType, PTypeBase) - HAS_OBJECT_POINTERS; protected: public: @@ -208,7 +207,6 @@ class PCompoundType : public PType class PNamedType : public PCompoundType { DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); - HAS_OBJECT_POINTERS; public: PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name @@ -364,7 +362,6 @@ public: class PPointer : public PBasicType { DECLARE_CLASS(PPointer, PBasicType); - HAS_OBJECT_POINTERS; public: PPointer(); PPointer(PType *pointsat, bool isconst = false); @@ -397,7 +394,6 @@ public: class PClassPointer : public PPointer { DECLARE_CLASS(PClassPointer, PPointer); - HAS_OBJECT_POINTERS; public: PClassPointer(class PClass *restrict = nullptr); @@ -414,7 +410,6 @@ public: class PEnum : public PInt { DECLARE_CLASS(PEnum, PInt); - HAS_OBJECT_POINTERS; public: PEnum(FName name, PTypeBase *outer); @@ -427,7 +422,6 @@ protected: class PArray : public PCompoundType { DECLARE_CLASS(PArray, PCompoundType); - HAS_OBJECT_POINTERS; public: PArray(PType *etype, unsigned int ecount); @@ -451,7 +445,6 @@ protected: class PResizableArray : public PArray { DECLARE_CLASS(PResizableArray, PArray); - HAS_OBJECT_POINTERS; public: PResizableArray(PType *etype); @@ -465,7 +458,6 @@ protected: class PDynArray : public PCompoundType { DECLARE_CLASS(PDynArray, PCompoundType); - HAS_OBJECT_POINTERS; public: PDynArray(PType *etype, PStruct *backing); @@ -489,7 +481,6 @@ protected: class PMap : public PCompoundType { DECLARE_CLASS(PMap, PCompoundType); - HAS_OBJECT_POINTERS; public: PMap(PType *keytype, PType *valtype); @@ -565,7 +556,6 @@ enum class PClass : public PNativeStruct { DECLARE_CLASS(PClass, PNativeStruct); - HAS_OBJECT_POINTERS; protected: // We unravel _WITH_META here just as we did for PType. TArray SpecialInits; @@ -672,10 +662,8 @@ struct FTypeTable PType *TypeHash[HASH_SIZE]; PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); - void ReplaceType(PType *newtype, PType *oldtype, size_t bucket); void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket); void AddType(PType *type); - void Mark(); void Clear(); static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 839de49a8..af180a4ea 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -64,9 +64,6 @@ IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(Ammo1) IMPLEMENT_POINTER(Ammo2) IMPLEMENT_POINTER(SisterWeapon) - IMPLEMENT_POINTER(AmmoType1) - IMPLEMENT_POINTER(AmmoType2) - IMPLEMENT_POINTER(SisterWeaponType) IMPLEMENT_POINTERS_END DEFINE_FIELD(AWeapon, WeaponFlags) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 910dba19f..c05ab6d64 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6717,7 +6717,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) { auto parentfield = static_cast(classx)->membervar; // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + auto newfield = new PField(NAME_None, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); newfield->BitValue = membervar->BitValue; static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index e98aeed88..5558ffe3f 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -110,7 +110,7 @@ FScriptPosition & GetStateSource(FState *state); // Extra info maintained while defining an actor. // //========================================================================== -class FDropItem; +struct FDropItem; struct Baggage { From 4e685f2b78668a1563ef3808e930f35a7c02116c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 23:29:52 +0100 Subject: [PATCH 43/50] - fixed: for unpositioned sounds the play position was never initialized and depended on random memory contents. --- src/p_user.cpp | 1 - src/s_sound.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index b0d1d127f..0860796ef 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -657,7 +657,6 @@ IMPLEMENT_CLASS(APlayerPawn, false, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) IMPLEMENT_POINTER(InvSel) - IMPLEMENT_POINTER(FlechetteType) IMPLEMENT_POINTERS_END void APlayerPawn::Serialize(FSerializer &arc) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 856156322..bae1fbaf6 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -711,6 +711,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, { case SOURCE_None: default: + pos->Zero(); break; case SOURCE_Actor: From ccecfeb45ceaacf9e19b8099a35c70f73c11311c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 9 Feb 2017 01:34:07 +0100 Subject: [PATCH 44/50] - to avoid problems with the final garbage collection, the players' PendingWeapon needs to be cleared manually. This is because it can point to a non-standard value which the garbage collector cannot deal with during engine shutdown. --- src/dobjtype.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 34709cddc..25e27b846 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2817,6 +2817,13 @@ void PClass::StaticShutdown () // This flags DObject::Destroy not to call any scripted OnDestroy methods anymore. bVMOperational = false; + // PendingWeapon must be cleared manually because it is not subjected to the GC if it contains WP_NOCHANGE, which is just RUNTIME_CLASS(AWWeapon). + // But that will get cleared here, confusing the GC if the value is left in. + for (auto &p : players) + { + p.PendingWeapon = nullptr; + } + // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. bShutdown = true; TypeTable.Clear(); From 4dd7e02721d60f0184e7cb57bb5901caaa9f9948 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 9 Feb 2017 10:15:05 +0200 Subject: [PATCH 45/50] AActor::GiveInventory() is now functional See https://mantis.zdoom.org/view.php?id=213 --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2650224be..53491f235 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -771,7 +771,7 @@ bool AActor::GiveInventory(PClassActor *type, int amount, bool givecheat) { bool result = true; - if (type != nullptr || !type->IsDescendantOf(RUNTIME_CLASS(AInventory))) return false; + 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; From 4f0747c59e7ec1ecfd24fa33965c05f386125874 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 9 Feb 2017 11:11:54 +0100 Subject: [PATCH 46/50] - fixed: Class pointers were accepted for objects of the base type 'Object'. --- src/scripting/backend/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index c05ab6d64..71ecfc58c 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -7863,7 +7863,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return x->Resolve(ctx); } - if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) From 845f5e083366f109d558659e2fa080d48801c3a0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 9 Feb 2017 11:22:36 +0100 Subject: [PATCH 47/50] - fixed: A_Teleport and A_Warp had incorrect declarations for their state parameter. --- src/p_actionfunctions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 518d2fb63..69ca13f16 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -5012,7 +5012,7 @@ enum T_Flags DEFINE_ACTION_FUNCTION(AActor, A_Teleport) { PARAM_ACTION_PROLOGUE(AActor); - PARAM_STATE_DEF (teleport_state) + PARAM_STATE_ACTION_DEF (teleport_state) PARAM_CLASS_DEF (target_type, ASpecialSpot) PARAM_CLASS_DEF (fog_type, AActor) PARAM_INT_DEF (flags) @@ -5449,7 +5449,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Warp) PARAM_FLOAT_DEF(zofs) PARAM_ANGLE_DEF(angle) PARAM_INT_DEF(flags) - PARAM_STATE_DEF(success_state) + PARAM_STATE_ACTION_DEF(success_state) PARAM_FLOAT_DEF(heightoffset) PARAM_FLOAT_DEF(radiusoffset) PARAM_ANGLE_DEF(pitch) From a4d146c843570561ac83a83c6d76b5f358e3ba8e Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Thu, 9 Feb 2017 15:06:53 +0800 Subject: [PATCH 48/50] Added DONTCULLBACKFACES MODELDEF flag to forcefully disable backface culling on models --- src/gl/models/gl_models.cpp | 7 ++++++- src/gl/models/gl_models.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 47283b51a..0bfc059a1 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -787,6 +787,10 @@ void gl_InitModels() map[c]=1; } } + else if (sc.Compare("dontcullbackfaces")) + { + smf.flags |= MDL_DONTCULLBACKFACES; + } else { sc.ScriptMessage("Unrecognized string \"%s\"", sc.String); @@ -949,8 +953,9 @@ void gl_RenderModel(GLSprite * spr) gl_RenderState.EnableTexture(true); // [BB] In case the model should be rendered translucent, do back face culling. // This solves a few of the problems caused by the lack of depth sorting. + // [Nash] Don't do back face culling if explicitly specified in MODELDEF // TO-DO: Implement proper depth sorting. - if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) + if (!(spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES)) { glEnable(GL_CULL_FACE); glFrontFace(GL_CW); diff --git a/src/gl/models/gl_models.h b/src/gl/models/gl_models.h index f0267b891..c37b69b5e 100644 --- a/src/gl/models/gl_models.h +++ b/src/gl/models/gl_models.h @@ -370,6 +370,7 @@ enum MDL_USEACTORPITCH = 32, MDL_USEACTORROLL = 64, MDL_BADROTATION = 128, + MDL_DONTCULLBACKFACES = 256, }; struct FSpriteModelFrame From 3d9673af44e54c92a963458089016b963f4e40b7 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Thu, 9 Feb 2017 16:35:28 +0800 Subject: [PATCH 49/50] Fixed: Models did not take SpriteRotation into account --- src/gl/models/gl_models.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 0bfc059a1..fe974f4df 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -1017,6 +1017,9 @@ void gl_RenderModel(GLSprite * spr) // Model space => World space gl_RenderState.mModelMatrix.translate(spr->x, spr->z, spr->y ); + // [Nash] take SpriteRotation into account + angle += spr->actor->SpriteRotation.Degrees; + if (spr->actor->renderflags & RF_INTERPOLATEANGLES) { // [Nash] use interpolated angles From 4e1300ecbe0611e193c1fc8448e596ff236b2753 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 9 Feb 2017 12:02:07 +0100 Subject: [PATCH 50/50] - added a script export for ACS's ReplaceTextures function. --- src/p_acs.cpp | 55 ++++---------------------------- src/p_acs.h | 1 - src/p_local.h | 11 +++++++ src/p_sectors.cpp | 57 ++++++++++++++++++++++++++++++++++ wadsrc/static/zscript/base.txt | 12 +++++++ 5 files changed, 86 insertions(+), 50 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 197a0616d..00b1d7be8 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -114,13 +114,6 @@ FRandom pr_acs ("ACS"); #define HUDMSG_VISIBILITY_MASK (0x00070000) // See HUDMSG visibility enumerations in sbar.h -// Flags for ReplaceTextures -#define NOT_BOTTOM 1 -#define NOT_MIDDLE 2 -#define NOT_TOP 4 -#define NOT_FLOOR 8 -#define NOT_CEILING 16 - // LineAttack flags #define FHF_NORANDOMPUFFZ 1 #define FHF_NOIMPACTDECAL 2 @@ -3322,47 +3315,6 @@ void DLevelScript::SetLineTexture (int lineid, int side, int position, int name) } } -void DLevelScript::ReplaceTextures (int fromnamei, int tonamei, int flags) -{ - const char *fromname = FBehavior::StaticLookupString (fromnamei); - const char *toname = FBehavior::StaticLookupString (tonamei); - FTextureID picnum1, picnum2; - - if (fromname == NULL) - return; - - if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0) - { - picnum1 = TexMan.GetTexture (fromname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); - picnum2 = TexMan.GetTexture (toname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); - - for (auto &side : level.sides) - { - for(int j=0;j<3;j++) - { - static BYTE bits[]={NOT_TOP, NOT_MIDDLE, NOT_BOTTOM}; - if (!(flags & bits[j]) && side.GetTexture(j) == picnum1) - { - side.SetTexture(j, picnum2); - } - } - } - } - if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0) - { - picnum1 = TexMan.GetTexture (fromname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); - picnum2 = TexMan.GetTexture (toname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); - - for (auto &sec : level.sectors) - { - if (!(flags & NOT_FLOOR) && sec.GetTexture(sector_t::floor) == picnum1) - sec.SetTexture(sector_t::floor, picnum2); - if (!(flags & NOT_CEILING) && sec.GetTexture(sector_t::ceiling) == picnum1) - sec.SetTexture(sector_t::ceiling, picnum2); - } - } -} - int DLevelScript::DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, bool force) { PClassActor *info = PClass::FindActor(FBehavior::StaticLookupString (type)); @@ -8352,9 +8304,14 @@ scriptwait: break; case PCD_REPLACETEXTURES: - ReplaceTextures (STACK(3), STACK(2), STACK(1)); + { + const char *fromname = FBehavior::StaticLookupString(STACK(3)); + const char *toname = FBehavior::StaticLookupString(STACK(2)); + + P_ReplaceTextures(fromname, toname, STACK(1)); sp -= 3; break; + } case PCD_SETLINEBLOCKING: { diff --git a/src/p_acs.h b/src/p_acs.h index 52665a39b..8265e5b37 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -913,7 +913,6 @@ protected: static void ChangeFlat (int tag, int name, bool floorOrCeiling); static int CountPlayers (); static void SetLineTexture (int lineid, int side, int position, int name); - static void ReplaceTextures (int fromname, int toname, int flags); static int DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, bool force); static int DoSpawn(int type, int x, int y, int z, int tid, int angle, bool force); static bool DoCheckActorTexture(int tid, AActor *activator, int string, bool floor); diff --git a/src/p_local.h b/src/p_local.h index d50d2be52..89346328e 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -441,4 +441,15 @@ enum EDmgFlags // bool P_AlignFlat (int linenum, int side, int fc); +enum ETexReplaceFlags +{ + NOT_BOTTOM = 1, + NOT_MIDDLE = 2, + NOT_TOP = 4, + NOT_FLOOR = 8, + NOT_CEILING = 16 +}; + +void P_ReplaceTextures(const char *fromname, const char *toname, int flags); + #endif // __P_LOCAL__ diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index e85fd744f..5e0a8f6ac 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -2120,6 +2120,63 @@ bool P_AlignFlat (int linenum, int side, int fc) return true; } + + +//========================================================================== +// +// P_ReplaceTextures +// +//========================================================================== + +void P_ReplaceTextures(const char *fromname, const char *toname, int flags) +{ + FTextureID picnum1, picnum2; + + if (fromname == nullptr) + return; + + if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0) + { + picnum1 = TexMan.GetTexture(fromname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); + picnum2 = TexMan.GetTexture(toname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); + + for (auto &side : level.sides) + { + for (int j = 0; j<3; j++) + { + static uint8_t bits[] = { NOT_TOP, NOT_MIDDLE, NOT_BOTTOM }; + if (!(flags & bits[j]) && side.GetTexture(j) == picnum1) + { + side.SetTexture(j, picnum2); + } + } + } + } + if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0) + { + picnum1 = TexMan.GetTexture(fromname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); + picnum2 = TexMan.GetTexture(toname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); + + for (auto &sec : level.sectors) + { + if (!(flags & NOT_FLOOR) && sec.GetTexture(sector_t::floor) == picnum1) + sec.SetTexture(sector_t::floor, picnum2); + if (!(flags & NOT_CEILING) && sec.GetTexture(sector_t::ceiling) == picnum1) + sec.SetTexture(sector_t::ceiling, picnum2); + } + } +} + +DEFINE_ACTION_FUNCTION(_TexMan, ReplaceTextures) +{ + PARAM_PROLOGUE; + PARAM_STRING(from); + PARAM_STRING(to); + PARAM_INT(flags); + P_ReplaceTextures(from, to, flags); + return 0; +} + //========================================================================== // // P_BuildPolyBSP diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 1ff8a5e92..5ba744a8e 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -28,8 +28,20 @@ struct TexMan ShortNameOnly = 16, DontCreate = 32 }; + + enum ETexReplaceFlags + { + NOT_BOTTOM = 1, + NOT_MIDDLE = 2, + NOT_TOP = 4, + NOT_FLOOR = 8, + NOT_CEILING = 16, + NOT_WALL = 7, + NOT_FLAT = 24 + }; native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny); + native static void ReplaceTextures(String from, String to, int flags); } enum DrawTextureTags