From b484cbf18ab36a3303d8ed7302411367cbfe3f50 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Feb 2016 23:08:51 +0100 Subject: [PATCH] - fixed: It is not guaranteed that the class object that is created by FindClassTentative actually matches the real object that is required later, so it needs to be replaced wherever it could be referenced once the real object is created. - removed some unneeded code from earlier attempts to fix the class type resolving issue. --- src/d_player.h | 1 + src/dobject.h | 1 + src/dobjtype.cpp | 37 +++++++++++++++++++++------------- src/dobjtype.h | 3 +-- src/g_shared/a_pickups.cpp | 12 +++++++++++ src/g_shared/a_pickups.h | 2 ++ src/g_shared/a_weaponpiece.cpp | 12 +++++++++++ src/g_shared/a_weaponpiece.h | 11 +++++++++- src/g_shared/a_weapons.cpp | 13 ++++++++++++ src/info.cpp | 31 ++++++++++++++++++++++++++++ src/info.h | 1 + src/p_user.cpp | 10 +++++++++ src/thingdef/thingdef.cpp | 9 ++------- 13 files changed, 119 insertions(+), 24 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 168327f8a..9a4e60d0f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -80,6 +80,7 @@ public: FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } void SetPainFlash(FName type, PalEntry color); bool GetPainFlash(FName type, PalEntry *color) const; + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); FString DisplayName; // Display name (used in menus, etc.) FString SoundClass; // Sound class diff --git a/src/dobject.h b/src/dobject.h index 4b6f1ec49..f478cfc08 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -98,6 +98,7 @@ enum CLASSREG_PClassPlayerPawn, CLASSREG_PClassType, CLASSREG_PClassClass, + CLASSREG_PClassWeaponPiece }; struct ClassReg diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7e80eca0c..f16bd588d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -44,6 +44,7 @@ #include "autosegs.h" #include "v_text.h" #include "a_pickups.h" +#include "a_weaponpiece.h" #include "d_player.h" #include "fragglescript/t_fs.h" @@ -2163,6 +2164,7 @@ PClass *ClassReg::RegisterClass() &PClassPlayerPawn::RegistrationInfo, &PClassType::RegistrationInfo, &PClassClass::RegistrationInfo, + &PClassWeaponPiece::RegistrationInfo, }; // Skip classes that have already been registered @@ -2318,34 +2320,29 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) assert (size >= Size); PClass *type; bool notnew; + size_t bucket; - const PClass *existclass = FindClass(name); + PClass *existclass = static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket)); // This is a placeholder so fill it in - if (existclass != NULL && (existclass->Size == TClass_Fatal || existclass->Size == TClass_Nonfatal)) + if (existclass != NULL && (existclass->Size == TentativeClass)) { type = const_cast(existclass); if (!IsDescendantOf(type->ParentClass)) { - if (existclass->Size == TClass_Fatal) - { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); - } - else - { - Printf(TEXTCOLOR_RED "%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); - } + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } DPrintf("Defining placeholder class %s\n", name.GetChars()); notnew = true; } else { - // Create a new type object of the same type as us. (We may be a derived class of PClass.) - 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->Size = size; type->bRuntimeClass = true; @@ -2354,6 +2351,18 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { type->InsertIntoHash(); } + else + { + PClassActor::AllActorClasses.Pop(); // remove the newly added class from the list + // todo: replace all affected fields + for (unsigned i = 0; i < PClassActor::AllActorClasses.Size(); i++) + { + PClassActor::AllActorClasses[i]->ReplaceClassRef(existclass, type); + if (PClassActor::AllActorClasses[i] == existclass) + PClassActor::AllActorClasses[i] = static_cast(type); + } + TypeTable.ReplaceType(type, existclass, bucket); + } return type; } @@ -2403,11 +2412,11 @@ PClass *PClass::FindClassTentative(FName name, bool fatal) return static_cast(found); } PClass *type = static_cast(GetClass()->CreateNew()); - DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); + Printf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); type->TypeName = name; type->ParentClass = this; - type->Size = fatal? TClass_Fatal : TClass_Nonfatal; + type->Size = TentativeClass; type->bRuntimeClass = true; TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket); return type; diff --git a/src/dobjtype.h b/src/dobjtype.h index 900059cab..8e0331f2f 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -601,8 +601,7 @@ public: enum { - TClass_Fatal = UINT_MAX, - TClass_Nonfatal = UINT_MAX - 1 + TentativeClass = UINT_MAX, }; class PClassClass; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index f6bca1294..f192f650f 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -39,6 +39,18 @@ void PClassInventory::Derive(PClass *newclass) newc->PickupMessage = PickupMessage; newc->GiveQuest = GiveQuest; newc->AltHUDIcon = AltHUDIcon; + newc->ForbiddenToPlayerClass = ForbiddenToPlayerClass; + newc->RestrictedToPlayerClass = RestrictedToPlayerClass; +} + +void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass) +{ + Super::ReplaceClassRef(oldclass, newclass); + AInventory *def = (AInventory*)Defaults; + if (def != NULL) + { + if (def->PickupFlash == oldclass) def->PickupFlash = static_cast(newclass); + } } IMPLEMENT_CLASS(PClassAmmo) diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index ef693394a..9c9c1e48c 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -139,6 +139,7 @@ protected: virtual void Derive(PClass *newclass); public: PClassInventory(); + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); FString PickupMessage; int GiveQuest; // Optionally give one of the quest items. @@ -269,6 +270,7 @@ protected: virtual void Derive(PClass *newclass); public: PClassWeapon(); + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); int SlotNumber; fixed_t SlotPriority; diff --git a/src/g_shared/a_weaponpiece.cpp b/src/g_shared/a_weaponpiece.cpp index 6862c1911..1a4c27882 100644 --- a/src/g_shared/a_weaponpiece.cpp +++ b/src/g_shared/a_weaponpiece.cpp @@ -3,8 +3,20 @@ #include "doomstat.h" #include "farchive.h" +IMPLEMENT_CLASS(PClassWeaponPiece) IMPLEMENT_CLASS (AWeaponHolder) +void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass) +{ + Super::ReplaceClassRef(oldclass, newclass); + AWeaponPiece *def = (AWeaponPiece*)Defaults; + if (def != NULL) + { + if (def->WeaponClass == oldclass) def->WeaponClass = static_cast(newclass); + } +} + + void AWeaponHolder::Serialize (FArchive &arc) { Super::Serialize(arc); diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h index 9f495a06e..dfa30f5d7 100644 --- a/src/g_shared/a_weaponpiece.h +++ b/src/g_shared/a_weaponpiece.h @@ -1,7 +1,16 @@ +// Ammo: Something a weapon needs to operate +class PClassWeaponPiece : public PClassInventory +{ + DECLARE_CLASS(PClassWeaponPiece, PClassInventory) +protected: +public: + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); +}; + class AWeaponPiece : public AInventory { - DECLARE_CLASS (AWeaponPiece, AInventory) + DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece) HAS_OBJECT_POINTERS protected: bool PrivateShouldStay (); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index c972c7120..e7242ad3f 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -54,6 +54,19 @@ void PClassWeapon::Derive(PClass *newclass) newc->SlotPriority = SlotPriority; } + +void PClassWeapon::ReplaceClassRef(PClass *oldclass, PClass *newclass) +{ + Super::ReplaceClassRef(oldclass, newclass); + AWeapon *def = (AWeapon*)Defaults; + if (def != NULL) + { + if (def->AmmoType1 == oldclass) def->AmmoType1 = static_cast(newclass); + if (def->AmmoType2 == oldclass) def->AmmoType2 = static_cast(newclass); + if (def->SisterWeaponType == oldclass) def->SisterWeaponType = static_cast(newclass); + } +} + //=========================================================================== // // AWeapon :: Serialize diff --git a/src/info.cpp b/src/info.cpp index 8c2ae06a6..1ca53470c 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -522,6 +522,37 @@ void PClassActor::SetPainChance(FName type, int chance) } } +//========================================================================== +// +// PClassActor :: ReplaceClassRef +// +//========================================================================== + +void PClassActor::ReplaceClassRef(PClass *oldclass, PClass *newclass) +{ + for (unsigned i = 0; i < VisibleToPlayerClass.Size(); i++) + { + if (VisibleToPlayerClass[i] == oldclass) + VisibleToPlayerClass[i] = static_cast(newclass); + } + for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) + { + if (ForbiddenToPlayerClass[i] == oldclass) + ForbiddenToPlayerClass[i] = static_cast(newclass); + } + for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) + { + if (RestrictedToPlayerClass[i] == oldclass) + RestrictedToPlayerClass[i] = static_cast(newclass); + } + AActor *def = (AActor*)Defaults; + if (def != NULL) + { + if (def->TeleFogSourceType == oldclass) def->TeleFogSourceType = static_cast(newclass); + if (def->TeleFogDestType == oldclass) def->TeleFogDestType = static_cast(newclass); + } +} + //========================================================================== // // DmgFactors :: CheckFactor diff --git a/src/info.h b/src/info.h index 2d0c627ec..52ccca305 100644 --- a/src/info.h +++ b/src/info.h @@ -200,6 +200,7 @@ public: PClassActor(); ~PClassActor(); + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); void BuildDefaults(); void ApplyDefaults(BYTE *defaults); void RegisterIDs(); diff --git a/src/p_user.cpp b/src/p_user.cpp index 0427bd64f..e23ccff7b 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -581,6 +581,16 @@ bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const return false; } +void PClassPlayerPawn::ReplaceClassRef(PClass *oldclass, PClass *newclass) +{ + Super::ReplaceClassRef(oldclass, newclass); + APlayerPawn *def = (APlayerPawn*)Defaults; + if (def != NULL) + { + if (def->FlechetteType == oldclass) def->FlechetteType = static_cast(newclass); + } +} + //=========================================================================== // // player_t :: SendPitchLimits diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index b12f45abe..30d94c6a3 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -340,15 +340,10 @@ static void FinishThingdef() { PClassActor *ti = PClassActor::AllActorClasses[i]; - if (ti->Size == TClass_Fatal || ti->Size == TClass_Nonfatal) + if (ti->Size == TentativeClass) { Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); - if (ti->Size == TClass_Fatal) errorcount++; - else - { - // In order to prevent a crash, this class needs to be completed, even though it defines nothing. - ti->ParentClass->CreateDerivedClass(ti->TypeName, ti->ParentClass->Size); - } + errorcount++; continue; }