- 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.
This commit is contained in:
Christoph Oelckers 2016-02-09 23:08:51 +01:00
parent ff70cf1ee7
commit b484cbf18a
13 changed files with 119 additions and 24 deletions

View File

@ -80,6 +80,7 @@ public:
FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); }
void SetPainFlash(FName type, PalEntry color); void SetPainFlash(FName type, PalEntry color);
bool GetPainFlash(FName type, PalEntry *color) const; bool GetPainFlash(FName type, PalEntry *color) const;
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
FString DisplayName; // Display name (used in menus, etc.) FString DisplayName; // Display name (used in menus, etc.)
FString SoundClass; // Sound class FString SoundClass; // Sound class

View File

@ -98,6 +98,7 @@ enum
CLASSREG_PClassPlayerPawn, CLASSREG_PClassPlayerPawn,
CLASSREG_PClassType, CLASSREG_PClassType,
CLASSREG_PClassClass, CLASSREG_PClassClass,
CLASSREG_PClassWeaponPiece
}; };
struct ClassReg struct ClassReg

View File

@ -44,6 +44,7 @@
#include "autosegs.h" #include "autosegs.h"
#include "v_text.h" #include "v_text.h"
#include "a_pickups.h" #include "a_pickups.h"
#include "a_weaponpiece.h"
#include "d_player.h" #include "d_player.h"
#include "fragglescript/t_fs.h" #include "fragglescript/t_fs.h"
@ -2163,6 +2164,7 @@ PClass *ClassReg::RegisterClass()
&PClassPlayerPawn::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo,
&PClassType::RegistrationInfo, &PClassType::RegistrationInfo,
&PClassClass::RegistrationInfo, &PClassClass::RegistrationInfo,
&PClassWeaponPiece::RegistrationInfo,
}; };
// Skip classes that have already been registered // Skip classes that have already been registered
@ -2318,34 +2320,29 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
assert (size >= Size); assert (size >= Size);
PClass *type; PClass *type;
bool notnew; bool notnew;
size_t bucket;
const PClass *existclass = FindClass(name); PClass *existclass = static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket));
// This is a placeholder so fill it in // 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<PClass*>(existclass); type = const_cast<PClass*>(existclass);
if (!IsDescendantOf(type->ParentClass)) 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());
{
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());
}
} }
DPrintf("Defining placeholder class %s\n", name.GetChars()); DPrintf("Defining placeholder class %s\n", name.GetChars());
notnew = true; notnew = true;
} }
else else
{ {
// Create a new type object of the same type as us. (We may be a derived class of PClass.)
type = static_cast<PClass *>(GetClass()->CreateNew());
notnew = false; notnew = false;
} }
// Create a new type object of the same type as us. (We may be a derived class of PClass.)
type = static_cast<PClass *>(GetClass()->CreateNew());
type->TypeName = name; type->TypeName = name;
type->Size = size; type->Size = size;
type->bRuntimeClass = true; type->bRuntimeClass = true;
@ -2354,6 +2351,18 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
{ {
type->InsertIntoHash(); 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<PClassActor*>(type);
}
TypeTable.ReplaceType(type, existclass, bucket);
}
return type; return type;
} }
@ -2403,11 +2412,11 @@ PClass *PClass::FindClassTentative(FName name, bool fatal)
return static_cast<PClass *>(found); return static_cast<PClass *>(found);
} }
PClass *type = static_cast<PClass *>(GetClass()->CreateNew()); PClass *type = static_cast<PClass *>(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->TypeName = name;
type->ParentClass = this; type->ParentClass = this;
type->Size = fatal? TClass_Fatal : TClass_Nonfatal; type->Size = TentativeClass;
type->bRuntimeClass = true; type->bRuntimeClass = true;
TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket); TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket);
return type; return type;

View File

@ -601,8 +601,7 @@ public:
enum enum
{ {
TClass_Fatal = UINT_MAX, TentativeClass = UINT_MAX,
TClass_Nonfatal = UINT_MAX - 1
}; };
class PClassClass; class PClassClass;

View File

@ -39,6 +39,18 @@ void PClassInventory::Derive(PClass *newclass)
newc->PickupMessage = PickupMessage; newc->PickupMessage = PickupMessage;
newc->GiveQuest = GiveQuest; newc->GiveQuest = GiveQuest;
newc->AltHUDIcon = AltHUDIcon; 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<PClassActor *>(newclass);
}
} }
IMPLEMENT_CLASS(PClassAmmo) IMPLEMENT_CLASS(PClassAmmo)

View File

@ -139,6 +139,7 @@ protected:
virtual void Derive(PClass *newclass); virtual void Derive(PClass *newclass);
public: public:
PClassInventory(); PClassInventory();
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
FString PickupMessage; FString PickupMessage;
int GiveQuest; // Optionally give one of the quest items. int GiveQuest; // Optionally give one of the quest items.
@ -269,6 +270,7 @@ protected:
virtual void Derive(PClass *newclass); virtual void Derive(PClass *newclass);
public: public:
PClassWeapon(); PClassWeapon();
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
int SlotNumber; int SlotNumber;
fixed_t SlotPriority; fixed_t SlotPriority;

View File

@ -3,8 +3,20 @@
#include "doomstat.h" #include "doomstat.h"
#include "farchive.h" #include "farchive.h"
IMPLEMENT_CLASS(PClassWeaponPiece)
IMPLEMENT_CLASS (AWeaponHolder) 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<PClassWeapon *>(newclass);
}
}
void AWeaponHolder::Serialize (FArchive &arc) void AWeaponHolder::Serialize (FArchive &arc)
{ {
Super::Serialize(arc); Super::Serialize(arc);

View File

@ -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 class AWeaponPiece : public AInventory
{ {
DECLARE_CLASS (AWeaponPiece, AInventory) DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece)
HAS_OBJECT_POINTERS HAS_OBJECT_POINTERS
protected: protected:
bool PrivateShouldStay (); bool PrivateShouldStay ();

View File

@ -54,6 +54,19 @@ void PClassWeapon::Derive(PClass *newclass)
newc->SlotPriority = SlotPriority; 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<PClassAmmo *>(newclass);
if (def->AmmoType2 == oldclass) def->AmmoType2 = static_cast<PClassAmmo *>(newclass);
if (def->SisterWeaponType == oldclass) def->SisterWeaponType = static_cast<PClassWeapon *>(newclass);
}
}
//=========================================================================== //===========================================================================
// //
// AWeapon :: Serialize // AWeapon :: Serialize

View File

@ -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<PClassPlayerPawn*>(newclass);
}
for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++)
{
if (ForbiddenToPlayerClass[i] == oldclass)
ForbiddenToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
}
for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++)
{
if (RestrictedToPlayerClass[i] == oldclass)
RestrictedToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
}
AActor *def = (AActor*)Defaults;
if (def != NULL)
{
if (def->TeleFogSourceType == oldclass) def->TeleFogSourceType = static_cast<PClassActor *>(newclass);
if (def->TeleFogDestType == oldclass) def->TeleFogDestType = static_cast<PClassActor *>(newclass);
}
}
//========================================================================== //==========================================================================
// //
// DmgFactors :: CheckFactor // DmgFactors :: CheckFactor

View File

@ -200,6 +200,7 @@ public:
PClassActor(); PClassActor();
~PClassActor(); ~PClassActor();
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
void BuildDefaults(); void BuildDefaults();
void ApplyDefaults(BYTE *defaults); void ApplyDefaults(BYTE *defaults);
void RegisterIDs(); void RegisterIDs();

View File

@ -581,6 +581,16 @@ bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const
return false; 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<PClassInventory *>(newclass);
}
}
//=========================================================================== //===========================================================================
// //
// player_t :: SendPitchLimits // player_t :: SendPitchLimits

View File

@ -340,15 +340,10 @@ static void FinishThingdef()
{ {
PClassActor *ti = PClassActor::AllActorClasses[i]; 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()); Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars());
if (ti->Size == TClass_Fatal) errorcount++; 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);
}
continue; continue;
} }