- fixed: Non-actor classes never called InitializeDefaults to set up their special variables.

- fixed: DThinkerIterator and DBlockThingsIterator did not have a default constructor that was safe to call from an out-of-game context.
This commit is contained in:
Christoph Oelckers 2017-01-29 18:23:09 +01:00
parent c0ef052d07
commit eef91463ab
6 changed files with 52 additions and 28 deletions

View file

@ -3194,34 +3194,37 @@ void PClass::Derive(PClass *newclass, FName name)
void PClass::InitializeDefaults() void PClass::InitializeDefaults()
{ {
assert(Defaults == NULL); if (IsKindOf(RUNTIME_CLASS(PClassActor)))
Defaults = (BYTE *)M_Malloc(Size);
// run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them.
// Temporarily setting bSerialOverride prevents linking into the thinker chains.
auto s = DThinker::bSerialOverride;
DThinker::bSerialOverride = true;
ConstructNative(Defaults);
DThinker::bSerialOverride = s;
// We must unlink the defaults from the class list because it's just a static block of data to the engine.
DObject *optr = (DObject*)Defaults;
GC::Root = optr->ObjNext;
optr->ObjNext = nullptr;
optr->SetClass(this);
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
if (ParentClass->Defaults != NULL)
{ {
memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject)); assert(Defaults == NULL);
if (Size > ParentClass->Size) Defaults = (BYTE *)M_Malloc(Size);
// run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them.
// Temporarily setting bSerialOverride prevents linking into the thinker chains.
auto s = DThinker::bSerialOverride;
DThinker::bSerialOverride = true;
ConstructNative(Defaults);
DThinker::bSerialOverride = s;
// We must unlink the defaults from the class list because it's just a static block of data to the engine.
DObject *optr = (DObject*)Defaults;
GC::Root = optr->ObjNext;
optr->ObjNext = nullptr;
optr->SetClass(this);
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
if (ParentClass->Defaults != NULL)
{ {
memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size); memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject));
if (Size > ParentClass->Size)
{
memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size);
}
}
else
{
memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject));
} }
}
else
{
memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject));
} }
if (bRuntimeClass) if (bRuntimeClass)

View file

@ -710,8 +710,12 @@ class DThinkerIterator : public DObject, public FThinkerIterator
{ {
DECLARE_CLASS(DThinkerIterator, DObject) DECLARE_CLASS(DThinkerIterator, DObject)
DThinkerIterator()
{
}
public: public:
DThinkerIterator(PClass *cls = nullptr, int statnum = MAX_STATNUM + 1) DThinkerIterator(PClass *cls, int statnum = MAX_STATNUM + 1)
: FThinkerIterator(cls, statnum) : FThinkerIterator(cls, statnum)
{ {
} }

View file

@ -125,6 +125,9 @@ public:
FThinkerIterator (const PClass *type, int statnum, DThinker *prev); FThinkerIterator (const PClass *type, int statnum, DThinker *prev);
DThinker *Next (bool exact = false); DThinker *Next (bool exact = false);
void Reinit (); void Reinit ();
protected:
FThinkerIterator() {}
}; };
template <class T> class TThinkerIterator : public FThinkerIterator template <class T> class TThinkerIterator : public FThinkerIterator

View file

@ -1177,6 +1177,11 @@ class DBlockThingsIterator : public DObject, public FMultiBlockThingsIterator
{ {
DECLARE_CLASS(DBlockThingsIterator, DObject); DECLARE_CLASS(DBlockThingsIterator, DObject);
FPortalGroupArray check; FPortalGroupArray check;
protected:
DBlockThingsIterator()
:FMultiBlockThingsIterator(check)
{
}
public: public:
FMultiBlockThingsIterator::CheckResult cres; FMultiBlockThingsIterator::CheckResult cres;
@ -1186,7 +1191,7 @@ public:
return FMultiBlockThingsIterator::Next(&cres); return FMultiBlockThingsIterator::Next(&cres);
} }
DBlockThingsIterator(AActor *origin = nullptr, double checkradius = -1, bool ignorerestricted = false) DBlockThingsIterator(AActor *origin, double checkradius = -1, bool ignorerestricted = false)
: FMultiBlockThingsIterator(check, origin, checkradius, ignorerestricted) : FMultiBlockThingsIterator(check, origin, checkradius, ignorerestricted)
{ {
cres.thing = nullptr; cres.thing = nullptr;

View file

@ -327,6 +327,8 @@ class FMultiBlockThingsIterator
void startIteratorForGroup(int group); void startIteratorForGroup(int group);
protected:
FMultiBlockThingsIterator(FPortalGroupArray &check) : checklist(check) {}
public: public:
struct CheckResult struct CheckResult

View file

@ -1874,7 +1874,14 @@ void ZCCCompiler::InitDefaults()
if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor)))
{ {
if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->Type()->TypeName.GetChars()); if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->Type()->TypeName.GetChars());
if (c->Type()->ParentClass) c->Type()->ParentClass->DeriveData(c->Type()); if (c->Type()->ParentClass)
{
auto ti = static_cast<PClassActor *>(c->Type());
FString mename = ti->TypeName.GetChars();
ti->InitializeDefaults();
ti->ParentClass->DeriveData(ti);
}
} }
else else
{ {