From 854053a14f58130f9f3d82d5f00d4c295af7a133 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Apr 2017 23:29:37 +0200 Subject: [PATCH] - use TArrays instead of TMaps to store damage factors and pain chances. For these fields maps have no advantage. Linearly searching a small array with up to 10 entries is nearly always faster than generating a hash for finding the entry in the map. --- src/d_dehacked.cpp | 2 +- src/dobject.cpp | 5 +- src/g_inventory/a_weapons.cpp | 7 +- src/info.cpp | 95 ++++++++++------------ src/info.h | 20 +++-- src/p_interaction.cpp | 10 +-- src/p_mobj.cpp | 8 +- src/scripting/decorate/olddecorations.cpp | 7 +- src/scripting/decorate/thingdef_parse.cpp | 4 +- src/scripting/decorate/thingdef_states.cpp | 2 +- src/scripting/thingdef_properties.cpp | 30 +++---- src/scripting/zscript/zcc_compile.cpp | 2 +- 12 files changed, 90 insertions(+), 102 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index affe344cbd..da68bafe44 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -876,7 +876,7 @@ static int PatchThing (int thingy) else { info = GetDefaultByType (type); - ednum = &type->DoomEdNum; + ednum = &type->ActorInfo()->DoomEdNum; } } } diff --git a/src/dobject.cpp b/src/dobject.cpp index 456305f215..85e5697f63 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -98,9 +98,10 @@ CCMD (dumpactors) PClassActor *acls = dyn_cast(cls); if (acls != NULL) { + auto ainfo = acls->ActorInfo(); Printf("%s\t%i\t%i\t%s\t%s\n", - acls->TypeName.GetChars(), acls->DoomEdNum, - acls->SpawnID, filters[acls->GameFilter & 31], + acls->TypeName.GetChars(), ainfo->DoomEdNum, + ainfo->SpawnID, filters[ainfo->GameFilter & 31], acls->SourceLumpName.GetChars()); } else if (cls != NULL) diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 89c1f00e58..c325a55cab 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -985,7 +985,8 @@ void FWeaponSlots::AddExtraWeapons() continue; } auto weapdef = ((AWeapon*)GetDefaultByType(cls)); - if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) && + auto gf = cls->ActorInfo()->GameFilter; + if ((gf == GAME_Any || (gf & gameinfo.gametype)) && cls->ActorInfo()->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. @@ -1470,8 +1471,8 @@ static int ntoh_cmp(const void *a, const void *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; + int g1 = c1->ActorInfo()->GameFilter == GAME_Any ? 1 : (c1->ActorInfo()->GameFilter & gameinfo.gametype) ? 0 : 2; + int g2 = c2->ActorInfo()->GameFilter == GAME_Any ? 1 : (c2->ActorInfo()->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) { return g1 - g2; diff --git a/src/info.cpp b/src/info.cpp index 55369555f9..203a60d7a5 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -294,12 +294,7 @@ void PClassActor::StaticSetActorNums() PClassActor::PClassActor() { - GameFilter = GAME_Any; - SpawnID = 0; - DoomEdNum = -1; StateList = NULL; - DamageFactors = NULL; - PainChances = NULL; DropItems = NULL; // Record this in the master list. @@ -314,14 +309,6 @@ PClassActor::PClassActor() PClassActor::~PClassActor() { - if (DamageFactors != NULL) - { - delete DamageFactors; - } - if (PainChances != NULL) - { - delete PainChances; - } if (StateList != NULL) { StateList->Destroy(); @@ -340,26 +327,14 @@ void PClassActor::DeriveData(PClass *newclass) assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); PClassActor *newa = static_cast(newclass); - newa->DefaultStateUsage = DefaultStateUsage; newa->distancecheck = distancecheck; newa->DropItems = DropItems; newa->VisibleToPlayerClass = VisibleToPlayerClass; - if (DamageFactors != NULL) - { - // copy damage factors from parent - newa->DamageFactors = new DmgFactors; - *newa->DamageFactors = *DamageFactors; - } - if (PainChances != NULL) - { - // copy pain chances from parent - newa->PainChances = new PainChanceList; - *newa->PainChances = *PainChances; - } - + newa->DamageFactors = DamageFactors; + newa->PainChances = PainChances; newa->DisplayName = DisplayName; } @@ -450,16 +425,18 @@ void PClassActor::RegisterIDs() } // Conversation IDs have never been filtered by game so we cannot start doing that. + auto ConversationID = ActorInfo()->ConversationID; if (ConversationID > 0) { StrifeTypes[ConversationID] = cls; if (cls != this) { - Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars()); + Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", ConversationID, cls->TypeName.GetChars()); } } - if (GameFilter == GAME_Any || (GameFilter & gameinfo.gametype)) + if (ActorInfo()->GameFilter == GAME_Any || (ActorInfo()->GameFilter & gameinfo.gametype)) { + auto SpawnID = ActorInfo()->SpawnID; if (SpawnID > 0) { SpawnableThings[SpawnID] = cls; @@ -468,6 +445,7 @@ void PClassActor::RegisterIDs() Printf(TEXTCOLOR_RED"Spawn ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars()); } } + auto DoomEdNum = ActorInfo()->DoomEdNum; if (DoomEdNum != -1) { FDoomEdEntry *oldent = DoomEdMap.CheckKey(DoomEdNum); @@ -602,11 +580,12 @@ DEFINE_ACTION_FUNCTION(AActor, GetReplacee) void PClassActor::SetDamageFactor(FName type, double factor) { - if (DamageFactors == NULL) + for (auto & p : DamageFactors) { - DamageFactors = new DmgFactors; + if (p.first == type) p.second = factor; + return; } - DamageFactors->Insert(type, factor); + DamageFactors.Push({ type, factor }); } //========================================================================== @@ -617,17 +596,15 @@ void PClassActor::SetDamageFactor(FName type, double factor) void PClassActor::SetPainChance(FName type, int chance) { + for (auto & p : PainChances) + { + if (p.first == type) p.second = chance; + return; + } + if (chance >= 0) { - if (PainChances == NULL) - { - PainChances = new PainChanceList; - } - PainChances->Insert(type, MIN(chance, 256)); - } - else if (PainChances != NULL) - { - PainChances->Remove(type); + PainChances.Push({ type, MIN(chance, 256) }); } } @@ -642,13 +619,22 @@ void PClassActor::SetPainChance(FName type, int chance) int DmgFactors::Apply(FName type, int damage) { - auto pdf = CheckKey(type); - if (pdf == NULL && type != NAME_None) + double factor = -1.; + for (auto & p : *this) { - pdf = CheckKey(NAME_None); + if (p.first == type) + { + factor = p.second; + break; + } + if (p.first == NAME_None) + { + factor = p.second; + } } - if (!pdf) return damage; - return int(damage * *pdf); + + if (factor < 0.) return damage; + return int(damage * factor); } @@ -755,13 +741,15 @@ FString DamageTypeDefinition::GetObituary(FName type) double DamageTypeDefinition::GetMobjDamageFactor(FName type, DmgFactors const * const factors) { + double defaultfac = -1.; if (factors) { // If the actor has named damage factors, look for a specific factor - - auto pdf = factors->CheckKey(type); - if (pdf) return *pdf; // type specific damage type - + for (auto & p : *factors) + { + if (p.first == type) return p.second; // type specific damage type + if (p.first == NAME_None) defaultfac = p.second; + } // If this was nonspecific damage, don't fall back to nonspecific search if (type == NAME_None) return 1.; } @@ -779,18 +767,17 @@ double DamageTypeDefinition::GetMobjDamageFactor(FName type, DmgFactors const * } { - auto pdf = factors->CheckKey(NAME_None); DamageTypeDefinition *dtd = Get(type); // Here we are looking for modifications to untyped damage // If the calling actor defines untyped damage factor, that is contained in "pdf". - if (pdf) // normal damage available + if (defaultfac >= 0.) // normal damage available { if (dtd) { if (dtd->ReplaceFactor) return dtd->DefaultFactor; // use default instead of untyped factor - return *pdf * dtd->DefaultFactor; // use default as modification of untyped factor + return defaultfac * dtd->DefaultFactor; // use default as modification of untyped factor } - return *pdf; // there was no default, so actor default is used + return defaultfac; // there was no default, so actor default is used } else if (dtd) { diff --git a/src/info.h b/src/info.h index 935d629073..406cc845ba 100644 --- a/src/info.h +++ b/src/info.h @@ -201,11 +201,11 @@ struct FStateLabels #include "gametype.h" -struct DmgFactors : public TMap +struct DmgFactors : public TArray> { int Apply(FName type, int damage); }; -typedef TMap PainChanceList; +typedef TArray> PainChanceList; struct DamageTypeDefinition { @@ -244,11 +244,18 @@ struct FActorInfo PClassActor *Replacee = nullptr; FState *OwnedStates = nullptr; int NumOwnedStates = 0; + uint8_t GameFilter = GAME_Any; + uint16_t SpawnID = 0; + uint16_t ConversationID = 0; + int16_t DoomEdNum = 0; + + uint8_t DefaultStateUsage = 0; // state flag defaults for blocks without a qualifier. FActorInfo() {} FActorInfo(const FActorInfo & other) { LightAssociations = other.LightAssociations; + DefaultStateUsage = other.DefaultStateUsage; } }; @@ -293,14 +300,9 @@ public: PClassActor *GetReplacement(bool lookskill=true); PClassActor *GetReplacee(bool lookskill=true); - uint8_t GameFilter; - uint8_t DefaultStateUsage; // state flag defaults for blocks without a qualifier. - uint16_t SpawnID; - uint16_t ConversationID; - int16_t DoomEdNum; FStateLabels *StateList; - DmgFactors *DamageFactors; - PainChanceList *PainChances; + DmgFactors DamageFactors; + PainChanceList PainChances; TArray VisibleToPlayerClass; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b4db7cb0ba..9368a504ad 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -916,7 +916,6 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da int temp; int painchance = 0; FState * woundstate = NULL; - PainChanceList * pc = NULL; bool justhit = false; bool plrDontThrust = false; bool invulpain = false; @@ -1500,14 +1499,13 @@ fakepain: //Needed so we can skip the rest of the above, but still obey the orig if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) && (target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) { - pc = target->GetClass()->PainChances; painchance = target->PainChance; - if (pc != NULL) + for (auto & pc : target->GetClass()->PainChances) { - int *ppc = pc->CheckKey(mod); - if (ppc != NULL) + if (pc.first == mod) { - painchance = *ppc; + painchance = pc.second; + break; } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 0632ba20b2..83233a1f02 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7822,7 +7822,7 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const damage = int(damage * DamageFactor); if (damage > 0) { - damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, GetClass()->DamageFactors); + damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, &GetClass()->DamageFactors); } return damage; } @@ -8273,10 +8273,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors) PARAM_INT(damage); PARAM_INT(defdamage); - DmgFactors *df = itemcls->DamageFactors; - if (df != nullptr && df->CountUsed() != 0) + DmgFactors &df = itemcls->DamageFactors; + if (df.Size() != 0) { - ACTION_RETURN_INT(df->Apply(damagetype, damage)); + ACTION_RETURN_INT(df.Apply(damagetype, damage)); } else { diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 3cf2c4f7db..1984f3a97c 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -124,7 +124,6 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) bag.ClassName = type->TypeName; #endif - type->GameFilter = GAME_Any; sc.MustGetStringName("{"); memset (&extra, 0, sizeof(extra)); @@ -334,7 +333,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, { sc.ScriptError ("DoomEdNum must be in the range [-1,32767]"); } - bag.Info->DoomEdNum = (int16_t)sc.Number; + bag.Info->ActorInfo()->DoomEdNum = (int16_t)sc.Number; } else if (sc.Compare ("SpawnNum")) { @@ -343,7 +342,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, { sc.ScriptError ("SpawnNum must be in the range [0,255]"); } - bag.Info->SpawnID = (uint8_t)sc.Number; + bag.Info->ActorInfo()->SpawnID = (uint8_t)sc.Number; } else if (sc.Compare ("Sprite") || ( (def == DEF_BreakableDecoration || def == DEF_Projectile) && @@ -622,7 +621,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray char *token = strtok (sc.String, ",\t\n\r"); memset (&state, 0, sizeof(state)); - state.UseFlags = info->DefaultStateUsage; + state.UseFlags = info->ActorInfo()->DefaultStateUsage; while (token != nullptr) { diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index edf46d3a7e..8950a70670 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1016,7 +1016,7 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti = DecoDerivedClass(sc, parent, typeName); ti->bDecorateClass = true; // we only set this for 'modern' DECORATE. The original stuff is so limited that it cannot do anything that may require flagging. - ti->DoomEdNum = -1; + ti->ActorInfo()->DoomEdNum = -1; return ti; } @@ -1108,7 +1108,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) try { PClassActor *info = CreateNewActor(sc, typeName, parentName); - info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; + info->ActorInfo()->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); if (!info->SetReplacement(replaceName)) diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 4355941bec..12684a30bc 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -142,7 +142,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & char lastsprite[5] = ""; FxExpression *ScriptCode; FArgumentList *args = nullptr; - int flagdef = actor->DefaultStateUsage; + int flagdef = actor->ActorInfo()->DefaultStateUsage; FScriptPosition scp; if (sc.CheckString("(")) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 50994f1e76..aededa99f6 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -391,10 +391,9 @@ bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index) case DEPF_QUARTERGRAVITY: return actor->Gravity == 1./4; case DEPF_FIRERESIST: - if (info->DamageFactors) + for (auto &df : info->DamageFactors) { - double *df = info->DamageFactors->CheckKey(NAME_Fire); - return df && (*df) == 0.5; + if (df.first == NAME_Fire) return df.second == 0.5; } return false; @@ -464,33 +463,34 @@ static bool PointerCheck(PType *symtype, PType *checktype) DEFINE_INFO_PROPERTY(game, S, Actor) { PROP_STRING_PARM(str, 0); + auto & GameFilter = info->ActorInfo()->GameFilter; if (!stricmp(str, "Doom")) { - info->GameFilter |= GAME_Doom; + GameFilter |= GAME_Doom; } else if (!stricmp(str, "Heretic")) { - info->GameFilter |= GAME_Heretic; + GameFilter |= GAME_Heretic; } else if (!stricmp(str, "Hexen")) { - info->GameFilter |= GAME_Hexen; + GameFilter |= GAME_Hexen; } else if (!stricmp(str, "Raven")) { - info->GameFilter |= GAME_Raven; + GameFilter |= GAME_Raven; } else if (!stricmp(str, "Strife")) { - info->GameFilter |= GAME_Strife; + GameFilter |= GAME_Strife; } else if (!stricmp(str, "Chex")) { - info->GameFilter |= GAME_Chex; + GameFilter |= GAME_Chex; } else if (!stricmp(str, "Any")) { - info->GameFilter = GAME_Any; + GameFilter = GAME_Any; } else { @@ -508,7 +508,7 @@ DEFINE_INFO_PROPERTY(spawnid, I, Actor) { I_Error ("SpawnID must be in the range [0,65535]"); } - else info->SpawnID=(uint16_t)id; + else info->ActorInfo()->SpawnID=(uint16_t)id; } //========================================================================== @@ -521,7 +521,7 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) PROP_INT_PARM(id2, 2); if (convid <= 0 || convid > 65535) return; // 0 is not usable because the dialogue scripts use it as 'no object'. - else info->ConversationID=(uint16_t)convid; + else info->ActorInfo()->ConversationID=(uint16_t)convid; } //========================================================================== @@ -559,7 +559,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) DEFINE_PROPERTY(defaultstateusage, I, Actor) { PROP_INT_PARM(use, 0); - static_cast(bag.Info)->DefaultStateUsage = use; + static_cast(bag.Info)->ActorInfo()->DefaultStateUsage = use; } //========================================================================== @@ -740,7 +740,7 @@ DEFINE_PROPERTY(translation, L, Actor) if (type == 0) { PROP_INT_PARM(trans, 1); - int max = 6;// (gameinfo.gametype == GAME_Strife || (info->GameFilter&GAME_Strife)) ? 6 : 2; + int max = 6; if (trans < 0 || trans > max) { I_Error ("Translation must be in the range [0,%d]", max); @@ -1133,7 +1133,7 @@ static void SetIcon(FTextureID &icon, Baggage &bag, const char *i) { // 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 ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) && + if ((bag.Info->ActorInfo()->GameFilter == GAME_Any || bag.Info->ActorInfo()->GameFilter & gameinfo.gametype) && !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 454cab4706..e3e72b03cd 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2889,7 +2889,7 @@ void ZCCCompiler::CompileStates() } else { - flags = static_cast(c->Type())->DefaultStateUsage; + flags = static_cast(c->Type())->ActorInfo()->DefaultStateUsage; } auto st = s->Body; if (st != nullptr) do