- 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); }
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

View file

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

View file

@ -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<PClass *>(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<PClass*>(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<PClass *>(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<PClass *>(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<PClassActor*>(type);
}
TypeTable.ReplaceType(type, existclass, bucket);
}
return type;
}
@ -2403,11 +2412,11 @@ PClass *PClass::FindClassTentative(FName name, bool fatal)
return static_cast<PClass *>(found);
}
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->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;

View file

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

View file

@ -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<PClassActor *>(newclass);
}
}
IMPLEMENT_CLASS(PClassAmmo)

View file

@ -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;

View file

@ -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<PClassWeapon *>(newclass);
}
}
void AWeaponHolder::Serialize (FArchive &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
{
DECLARE_CLASS (AWeaponPiece, AInventory)
DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece)
HAS_OBJECT_POINTERS
protected:
bool PrivateShouldStay ();

View file

@ -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<PClassAmmo *>(newclass);
if (def->AmmoType2 == oldclass) def->AmmoType2 = static_cast<PClassAmmo *>(newclass);
if (def->SisterWeaponType == oldclass) def->SisterWeaponType = static_cast<PClassWeapon *>(newclass);
}
}
//===========================================================================
//
// 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

View file

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

View file

@ -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<PClassInventory *>(newclass);
}
}
//===========================================================================
//
// player_t :: SendPitchLimits

View file

@ -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;
}