// Create a new class based on an existing class PClass *PClass::CreateDerivedClass (FName name, unsigned int size) { assert (size >= Size); PClass *type; bool notnew; const PClass *existclass = FindClass(name); // This is a placeholder so fill it in if (existclass != NULL && existclass->Size == (unsigned)-1) { type = const_cast<PClass*>(existclass); if (!IsDescendantOf(type->ParentClass)) { 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 { type = new PClass; notnew = false; } type->TypeName = name; type->ParentClass = this; type->Size = size; type->Pointers = NULL; type->ConstructNative = ConstructNative; if (!notnew) { type->ClassIndex = m_Types.Push (type); } type->Meta = Meta; // Set up default instance of the new class. type->Defaults = new BYTE[size]; memcpy (type->Defaults, Defaults, Size); if (size > Size) { memset (type->Defaults + Size, 0, size - Size); } type->FlatPointers = NULL; type->bRuntimeClass = true; type->ActorInfo = NULL; type->Symbols.SetParentTable (&this->Symbols); if (!notnew) type->InsertIntoHash(); // If this class has an actor info, then any classes derived from it // also need an actor info. if (this->ActorInfo != NULL) { FActorInfo *info = type->ActorInfo = new FActorInfo; info->Class = type; info->GameFilter = GAME_Any; info->SpawnID = 0; info->DoomEdNum = -1; info->OwnedStates = NULL; info->NumOwnedStates = 0; info->Replacement = NULL; info->Replacee = NULL; info->StateList = NULL; info->DamageFactors = NULL; info->PainChances = NULL; m_RuntimeActors.Push (type); } return type; }
void LoadActors() { cycle_t timer; timer.Reset(); timer.Clock(); FScriptPosition::ResetErrorCounter(); InitThingdef(); FScriptPosition::StrictErrors = true; ParseScripts(); FScriptPosition::StrictErrors = false; ParseAllDecorate(); FunctionBuildList.Build(); if (FScriptPosition::ErrorCounter > 0) { I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); } FScriptPosition::ResetErrorCounter(); for (int i = PClassActor::AllActorClasses.Size() - 1; i >= 0; i--) { auto ti = PClassActor::AllActorClasses[i]; if (ti->Size == TentativeClass) { if (ti->ObjectFlags & OF_Transient) { Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::WarnCounter++; DObject::StaticPointerSubstitution(ti, nullptr); PClassActor::AllActorClasses.Delete(i); } else { Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::ErrorCounter++; } continue; } if (GetDefaultByType(ti) == nullptr) { Printf(TEXTCOLOR_RED "No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); FScriptPosition::ErrorCounter++; continue; } CheckStates(ti); if (ti->bDecorateClass && ti->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) { // either a DECORATE based weapon or CustomInventory. // These are subject to relaxed rules for user variables in states. // Although there is a runtime check for bogus states, let's do a quick analysis if any of the known entry points // hits an unsafe state. If we can find something here it can be handled wuth a compile error rather than a runtime error. CheckForUnsafeStates(ti); } } if (FScriptPosition::ErrorCounter > 0) { I_Error("%d errors during actor postprocessing", FScriptPosition::ErrorCounter); } timer.Unclock(); if (!batchrun) Printf("script parsing took %.2f ms\n", timer.TimeMS()); // Since these are defined in DECORATE now the table has to be initialized here. for (int i = 0; i < 31; i++) { char fmt[20]; mysnprintf(fmt, countof(fmt), "QuestItem%d", i + 1); QuestItemClasses[i] = PClass::FindActor(fmt); } StateSourceLines.Clear(); }
void PClass::InitializeDefaults() { if (IsDescendantOf(RUNTIME_CLASS(AActor))) { assert(Defaults == nullptr); Defaults = (uint8_t *)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 != nullptr) { 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)); } assert(MetaSize >= ParentClass->MetaSize); if (MetaSize != 0) { Meta = (uint8_t*)M_Malloc(MetaSize); // Copy the defaults from the parent but leave the DObject part alone because it contains important data. if (ParentClass->Meta != nullptr) { memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); if (MetaSize > ParentClass->MetaSize) { memset(Meta + ParentClass->MetaSize, 0, MetaSize - ParentClass->MetaSize); } } else { memset(Meta, 0, MetaSize); } if (MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); else memset(Meta, 0, MetaSize); } } if (VMType != nullptr) // purely internal classes have no symbol table { if (bRuntimeClass) { // Copy parent values from the parent defaults. assert(ParentClass != nullptr); if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); for (const PField *field : Fields) { if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) { field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); } } } if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); for (const PField *field : Fields) { if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) { field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); } } } }