From 979dfdf4cf79199e7be61ae88d47ee8615066c91 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 16 Dec 2006 12:50:36 +0000 Subject: [PATCH] - Changed state label storage so that each actor owns all the state labels itself and doesn't have to traverse parent lists to find them. This is required for Dehacked actors that inherit states (e.g. NonsolidMeat and Spectre) but it also makes the data much easier to handle. SVN r413 (trunk) --- docs/rh-log.txt | 4 ++ src/decorations.cpp | 2 +- src/info.cpp | 145 ++++++++++++++----------------------------- src/info.h | 1 - src/infodefaults.cpp | 15 ++--- src/thingdef.cpp | 56 ++++++++++------- 6 files changed, 92 insertions(+), 131 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 6cbda931d..006ada99e 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,8 @@ December 16, 2006 (Changes by Graf Zahl) +- Changed state label storage so that each actor owns all the state labels itself + and doesn't have to traverse parent lists to find them. This is required for + Dehacked actors that inherit states (e.g. NonsolidMeat and Spectre) but it also + makes the data much easier to handle. - Merged the fallingdamage setting into one menu item and added Strife damage to it. - Moved deathmatch options into their own category in the gameplay options menu. - Added the sv_smartaim code from GZDoom which tries to avoid autoaiming diff --git a/src/decorations.cpp b/src/decorations.cpp index 8bf4eb938..0297871ee 100644 --- a/src/decorations.cpp +++ b/src/decorations.cpp @@ -357,7 +357,7 @@ static void ParseDecorate (void (*process)(FState *, int)) info = type->ActorInfo; info->GameFilter = 0x80; Decorations.Push (info); - ClearStateLabels(); + MakeStateDefines(parent->ActorInfo->StateList); SC_MustGetString (); while (!SC_Compare ("{")) diff --git a/src/info.cpp b/src/info.cpp index 01c732940..1469ccb68 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -432,19 +432,14 @@ void FStateLabels::Destroy () FState *AActor::FindState (FName label) const { const FActorInfo *info = GetClass()->ActorInfo; - FStateLabel *slabel; - while (info != NULL) + if (info->StateList != NULL) { - if (info->StateList != NULL) + FStateLabel *slabel = info->StateList->FindLabel (label); + if (slabel != NULL) { - slabel = info->StateList->FindLabel (label); - if (slabel != NULL && slabel->valid) - { - return slabel->State; - } + return slabel->State; } - info = info->Class->ParentClass->ActorInfo; } return NULL; } @@ -460,33 +455,17 @@ FState *AActor::FindState (FName label) const bool AActor::HasSpecialDeathStates () const { const FActorInfo *info = GetClass()->ActorInfo; - FStateLabel *slabel; - TArray checkedTypes; - while (info != NULL) + if (info->StateList != NULL) { - if (info->StateList != NULL) + FStateLabel *slabel = info->StateList->FindLabel (NAME_Death); + if (slabel != NULL && slabel->Children != NULL) { - slabel = info->StateList->FindLabel (NAME_Death); - if (slabel != NULL && slabel->Children != NULL) + for(int i=0;iChildren->NumLabels;i++) { - for(int i=0;iChildren->NumLabels;i++) - { - unsigned int j; - for(j=0;jChildren->Labels[i].Label == checkedTypes[j]) break; - } - // Only check if this damage type hasn't been checked by another class with higher priority. - if (j==checkedTypes.Size()) - { - if (slabel->Children->Labels[i].State != NULL) return true; - else if (slabel->Children->Labels[i].valid) checkedTypes.Push(slabel->Children->Labels[i].Label); - } - } + if (slabel->Children->Labels[i].State != NULL) return true; } } - info = info->Class->ParentClass->ActorInfo; } return false; } @@ -504,8 +483,6 @@ bool AActor::HasSpecialDeathStates () const // names until there are no more. If both the argument list and the state // are out of names, it's an exact match, so return it. If the state still // has names, ignore it. If the argument list still has names, remember it. -// Repeat with each successive ancestor class. The state with the longest -// match not exceeding the supplied number of names is returned. // //=========================================================================== @@ -533,53 +510,33 @@ FState *AActor::FindState (int numnames, va_list arglist) const FState *FActorInfo::FindState (int numnames, va_list arglist) const { - const FActorInfo *info = this; + FStateLabels *labels = StateList; FState *best = NULL; - int bestcount = 0; - // Search this actor's class, plus all its ancestors for a match. - while (info != NULL && bestcount < numnames) + if (labels != NULL) { - FStateLabels *labels = info->StateList; + va_list names = arglist; + int count = 0; + FStateLabel *slabel = NULL; + FName label; - if (labels != NULL) + // Find the best-matching label for this class. + while (labels != NULL && count < numnames) { - va_list names = arglist; - int count = 0; - FStateLabel *slabel = NULL; - FName label; + label = ENamedName(va_arg (names, int)); + slabel = labels->FindLabel (label); - // Find the best-matching label for this class. - while (labels != NULL && count < numnames) + if (slabel != NULL) { - label = ENamedName(va_arg (names, int)); - slabel = labels->FindLabel (label); - - if (slabel != NULL) - { - count++; - labels = slabel->Children; - - // Labels that are more specific than what we want do not match. - // Less specific labels do match. - if (slabel->valid && count > bestcount) - { - if (count == numnames) - { - return slabel->State; - } - bestcount = count; - best = slabel->State; - } - } - else - { - break; - } + count++; + labels = slabel->Children; + best = slabel->State; + } + else + { + break; } } - // Walk up the class hierarchy and repeat. - info = info->Class->ParentClass->ActorInfo; } return best; } @@ -602,44 +559,36 @@ FState *FActorInfo::FindStateExact (int numnames, ...) const FState *FActorInfo::FindStateExact (int numnames, va_list arglist) const { - const FActorInfo *info = this; + FStateLabels *labels = StateList; - // Search this actor's class, plus all its ancestors for a match. - while (info != NULL) + if (labels != NULL) { - FStateLabels *labels = info->StateList; + va_list names = arglist; + int count = 0; + FStateLabel *slabel = NULL; + FName label; - if (labels != NULL) + // Look for a matching label for this class. + while (labels != NULL && count < numnames) { - va_list names = arglist; - int count = 0; - FStateLabel *slabel = NULL; - FName label; + label = ENamedName(va_arg (names, int)); + slabel = labels->FindLabel (label); - // Look for a matching label for this class. - while (labels != NULL && count < numnames) + if (slabel != NULL) { - label = ENamedName(va_arg (names, int)); - slabel = labels->FindLabel (label); - - if (slabel != NULL) - { - count++; - labels = slabel->Children; - } - else - { - break; - } + count++; + labels = slabel->Children; } - // Only exact matches count. - if (slabel != NULL && slabel->valid && count == numnames) + else { - return slabel->State; + break; } } - // Walk up the class hierarchy and repeat. - info = info->Class->ParentClass->ActorInfo; + // Only exact matches count. + if (slabel != NULL && count == numnames) + { + return slabel->State; + } } return NULL; } diff --git a/src/info.h b/src/info.h index bb83df647..f6af173d2 100644 --- a/src/info.h +++ b/src/info.h @@ -153,7 +153,6 @@ struct FStateLabels; struct FStateLabel { FName Label; - bool valid; // needed to recognize genuine NULL states FState *State; FStateLabels *Children; }; diff --git a/src/infodefaults.cpp b/src/infodefaults.cpp index 8dd76058c..d3325abfa 100644 --- a/src/infodefaults.cpp +++ b/src/infodefaults.cpp @@ -70,12 +70,6 @@ void FActorInfo::BuildDefaults () { memset (Class->Defaults + parent->Size, 0, Class->Size - parent->Size); } - if (parent == RUNTIME_CLASS(AActor) && OwnedStates == NULL) - { // Stateless actors that are direct subclasses of AActor - // have their spawnstate default to something that won't - // immediately destroy them. - ((AActor *)(Class->Defaults))->SpawnState = &AActor::States[0]; - } } ApplyDefaults (Class->Defaults); } @@ -358,7 +352,14 @@ void FActorInfo::ApplyDefaults (BYTE *defaults) sgClass = Class; sgDefaults = defaults; - ClearStateLabels(); + if (Class != RUNTIME_CLASS(AActor)) + { + MakeStateDefines(Class->ParentClass->ActorInfo->StateList); + } + else + { + ClearStateLabels(); + } #if _MSC_VER const BYTE *parser = DefaultList; diff --git a/src/thingdef.cpp b/src/thingdef.cpp index 4b8314e83..8ee43eb39 100644 --- a/src/thingdef.cpp +++ b/src/thingdef.cpp @@ -774,7 +774,6 @@ static const ActorProps *is_actorprop (const char *str); struct FStateDefine { FName Label; - bool valid; TArray Children; FState *State; }; @@ -803,7 +802,6 @@ static FStateDefine * FindStateLabelInList(TArray & list, FName na FStateDefine def; def.Label=name; def.State=NULL; - def.valid=false; return &list[list.Push(def)]; } return NULL; @@ -882,7 +880,6 @@ void AddState (const char * statename, FState * state) { FStateDefine * std = FindStateAddress(statename); std->State = state; - std->valid = true; } //========================================================================== @@ -902,12 +899,7 @@ FState * FindState(AActor * actor, const PClass * type, const char * name) for(unsigned i=0;iParentClass->ActorInfo; - if (parentinfo) return parentinfo->FindStateExact(namelist.Size(), (va_list)&namelist[0]); - else return NULL; - } + if (statedef == NULL) return NULL; statelist = &statedef->Children; } return statedef? statedef->State : NULL; @@ -961,6 +953,15 @@ static int STACK_ARGS labelcmp(const void * a, const void * b) static FStateLabels * CreateStateLabelList(TArray & statelist) { + // First delete all empty labels from the list + for (int i=statelist.Size()-1;i>=0;i--) + { + if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0)) + { + statelist.Delete(i); + } + } + int count=statelist.Size(); if (count == 0) return NULL; @@ -968,17 +969,11 @@ static FStateLabels * CreateStateLabelList(TArray & statelist) FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); list->NumLabels = count; - int j=0; - for (unsigned i=0;iLabels[j].Label = statelist[i].Label; - list->Labels[j].State = statelist[i].State; - list->Labels[j].valid = statelist[i].valid; - list->Labels[j].Children = CreateStateLabelList(statelist[i].Children); - j++; - } + list->Labels[i].Label = statelist[i].Label; + list->Labels[i].State = statelist[i].State; + list->Labels[i].Children = CreateStateLabelList(statelist[i].Children); } qsort(list->Labels, count, sizeof(FStateLabel), labelcmp); return list; @@ -994,14 +989,28 @@ static FStateLabels * CreateStateLabelList(TArray & statelist) void InstallStates(FActorInfo *info, AActor *defaults) { + // First ensure we have a valid spawn state. FState * state = FindState(defaults, info->Class, "Spawn"); - // If the actor doesn't provide a valid spawn state we have to substutute it - // with the default. - if (state == &AActor::States[2] || state == NULL) + + // Stateless actors that are direct subclasses of AActor + // have their spawnstate default to something that won't + // immediately destroy them. + if (state == &AActor::States[2] && info->Class->ParentClass == RUNTIME_CLASS(AActor)) { AddState("Spawn", &AActor::States[0]); } + else if (state == NULL) + { + // A NULL spawn state will crash the engine so set it to something that will make + // the actor disappear as quickly as possible. + AddState("Spawn", &AActor::States[2]); + } + if (info->StateList != NULL) + { + info->StateList->Destroy(); + free(info->StateList); + } info->StateList = CreateStateLabelList(StateLabels); // Cache these states as member veriables. @@ -1032,7 +1041,6 @@ static void MakeStateList(const FStateLabels *list, TArray &dest) def.Label = list->Labels[i].Label; def.State = list->Labels[i].State; - def.valid = list->Labels[i].valid; dest.Push(def); if (list->Labels[i].Children != NULL) { @@ -1150,7 +1158,7 @@ static FActorInfo * CreateNewActor(FActorInfo ** parentc, Baggage *bag) FActorInfo * info = ti->ActorInfo; Decorations.Push (info); - ClearStateLabels(); + MakeStateDefines(parent->ActorInfo->StateList); info->NumOwnedStates = 0; info->OwnedStates = NULL; info->SpawnID = 0;