/**
* Exports the property values for the specified object as text to the output device.
*
* @param Context Context from which the set of 'inner' objects is extracted. If NULL, an object iterator will be used.
* @param Out the output device to send the exported text to
* @param ObjectClass the class of the object to dump properties for
* @param Object the address of the object to dump properties for
* @param Indent number of spaces to prepend to each line of output
* @param DiffClass the class to use for comparing property values when delta export is desired.
* @param Diff the address of the object to use for determining whether a property value should be exported. If the value in Object matches the corresponding
* value in Diff, it is not exported. Specify NULL to export all properties.
* @param Parent the UObject corresponding to Object
* @param PortFlags flags used for modifying the output and/or behavior of the export
*/
void ExportProperties
(
const FExportObjectInnerContext* Context,
FOutputDevice& Out,
UClass* ObjectClass,
uint8* Object,
int32 Indent,
UClass* DiffClass,
uint8* Diff,
UObject* Parent,
uint32 PortFlags,
UObject* ExportRootScope
)
{
FString ThisName = TEXT("(none)");
check(ObjectClass != NULL);
for( UProperty* Property = ObjectClass->PropertyLink; Property; Property = Property->PropertyLinkNext )
{
if (!Property->ShouldPort(PortFlags))
continue;
ThisName = Property->GetName();
UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property);
UObjectPropertyBase* ExportObjectProp = (Property->PropertyFlags & CPF_ExportObject) != 0 ? Cast<UObjectPropertyBase>(Property) : NULL;
const uint32 ExportFlags = PortFlags | PPF_Delimited;
if ( ArrayProperty != NULL )
{
// Export dynamic array.
UProperty* InnerProp = ArrayProperty->Inner;
ExportObjectProp = (Property->PropertyFlags & CPF_ExportObject) != 0 ? Cast<UObjectPropertyBase>(InnerProp) : NULL;
// This is used as the default value in the case of an array property that has
// fewer elements than the exported object.
uint8* StructDefaults = NULL;
UStructProperty* StructProperty = Cast<UStructProperty>(InnerProp);
if ( StructProperty != NULL )
{
checkSlow(StructProperty->Struct);
StructDefaults = (uint8*)FMemory::Malloc(StructProperty->Struct->GetStructureSize());
StructProperty->InitializeValue(StructDefaults);
}
for( int32 PropertyArrayIndex=0; PropertyArrayIndex<Property->ArrayDim; PropertyArrayIndex++ )
{
void* Arr = Property->ContainerPtrToValuePtr<void>(Object, PropertyArrayIndex);
FScriptArrayHelper ArrayHelper(ArrayProperty, Arr);
void* DiffArr = NULL;
if( DiffClass )
{
DiffArr = Property->ContainerPtrToValuePtrForDefaults<void>(DiffClass, Diff, PropertyArrayIndex);
}
// we won't use this if DiffArr is NULL, but we have to set it up to something
FScriptArrayHelper DiffArrayHelper(ArrayProperty, DiffArr);
bool bAnyElementDiffered = false;
for( int32 DynamicArrayIndex=0; DynamicArrayIndex<ArrayHelper.Num(); DynamicArrayIndex++ )
{
FString Value;
// compare each element's value manually so that elements which match the NULL value for the array's inner property type
// but aren't in the diff array are still exported
uint8* SourceData = ArrayHelper.GetRawPtr(DynamicArrayIndex);
uint8* DiffData = DiffArr && DynamicArrayIndex < DiffArrayHelper.Num()
? DiffArrayHelper.GetRawPtr(DynamicArrayIndex)
: StructDefaults;
bool bExportItem = DiffData == NULL || (DiffData != SourceData && !InnerProp->Identical(SourceData, DiffData, ExportFlags));
if ( bExportItem )
{
bAnyElementDiffered = true;
InnerProp->ExportTextItem(Value, SourceData, DiffData, Parent, ExportFlags, ExportRootScope);
if(ExportObjectProp)
{
UObject* Obj = ExportObjectProp->GetObjectPropertyValue(ArrayHelper.GetRawPtr(DynamicArrayIndex));
check(!Obj || Obj->IsValidLowLevel());
if( Obj && !Obj->HasAnyMarks(OBJECTMARK_TagImp) )
{
// only export the BEGIN OBJECT block for a component if Parent is the component's Outer....when importing subobject definitions,
// (i.e. BEGIN OBJECT), whichever BEGIN OBJECT block a component's BEGIN OBJECT block is located within is the object that will be
// used as the Outer to create the component
// Is this an array of components?
if ( InnerProp->HasAnyPropertyFlags(CPF_InstancedReference) )
{
//.........这里部分代码省略.........
/**
* Process a string command to the logging suppression system
* @param CmdString, string to process
* @param FromBoot, if true, this is a boot time command, and is handled differently
*/
void ProcessCmdString(const FString& CmdString, bool FromBoot = false)
{
// How to use the log command : `log <category> <verbosity>
// e.g., Turn off all logging : `log global none
// e.g., Set specific filter : `log logshaders verbose
// e.g., Combo command : `log global none, log logshaders verbose
static FName NAME_BootGlobal(TEXT("BootGlobal"));
static FName NAME_Reset(TEXT("Reset"));
FString Cmds = CmdString;
Cmds = Cmds.Trim().TrimQuotes();
Cmds.Trim();
TArray<FString> SubCmds;
Cmds.ParseIntoArray(SubCmds, TEXT(","), true);
for (int32 Index = 0; Index < SubCmds.Num(); Index++)
{
static FString LogString(TEXT("Log "));
FString Command = SubCmds[Index].Trim();
if (Command.StartsWith(*LogString))
{
Command = Command.Right(Command.Len() - LogString.Len());
}
TArray<FString> CommandParts;
Command.ParseIntoArrayWS(CommandParts);
if (CommandParts.Num() < 1)
{
continue;
}
FName Category(*CommandParts[0]);
if (Category == NAME_Global && FromBoot)
{
Category = NAME_BootGlobal; // the boot time global is a special one, since we want things like "log global none, log logshaders verbose"
}
TArray<FLogCategoryBase*> CategoryVerbosities;
uint8 Value = 0;
if (FromBoot)
{
// now maybe this was already set at boot, in which case we override what it had
uint8* Boot = BootAssociations.Find(Category);
if (Boot)
{
Value = *Boot;
}
else
{
// see if we had a boot global override
Boot = BootAssociations.Find(NAME_BootGlobal);
if (Boot)
{
Value = *Boot;
}
}
}
else
{
for (TMultiMap<FName, FLogCategoryBase*>::TKeyIterator It(ReverseAssociations, Category); It; ++It)
{
checkSlow(!(It.Value()->Verbosity & ELogVerbosity::BreakOnLog)); // this bit is factored out of this variable, always
Value = It.Value()->Verbosity | (It.Value()->DebugBreakOnLog ? ELogVerbosity::BreakOnLog : 0);
CategoryVerbosities.Add(It.Value());
}
}
if (CommandParts.Num() == 1)
{
// only possibility is the reset and toggle command which is meaningless at boot
if (!FromBoot)
{
if (Category == NAME_Reset)
{
for (TMap<FLogCategoryBase*, FName>::TIterator It(Associations); It; ++It)
{
FLogCategoryBase* Verb = It.Key();
Verb->ResetFromDefault();
// store off the last non-zero one for toggle
checkSlow(!(Verb->Verbosity & ELogVerbosity::BreakOnLog)); // this bit is factored out of this variable, always
if (Verb->Verbosity)
{
// currently on, store this in the pending and clear it
ToggleAssociations.Add(Category, Verb->Verbosity);
}
}
}
else
{
if (Value & ELogVerbosity::VerbosityMask)
{
// currently on, toggle it
Value = Value & ~ELogVerbosity::VerbosityMask;
}
else
{
// try to get a non-zero value from the toggle backup
uint8* Toggle = ToggleAssociations.Find(Category);
if (Toggle && *Toggle)
{
//.........这里部分代码省略.........
void FIndirectLightingCache::UpdateCachePrimitivesInternal(FScene* Scene, FSceneRenderer& Renderer, bool bAllowUnbuiltPreview, TMap<FIntVector, FBlockUpdateInfo>& OutBlocksToUpdate, TArray<FIndirectLightingCacheAllocation*>& OutTransitionsOverTimeToUpdate)
{
SCOPE_CYCLE_COUNTER(STAT_UpdateIndirectLightingCachePrims);
const TMap<FPrimitiveComponentId, FAttachmentGroupSceneInfo>& AttachmentGroups = Scene->AttachmentGroups;
if (IndirectLightingAllowed(Scene, Renderer))
{
if (bUpdateAllCacheEntries)
{
const uint32 PrimitiveCount = Scene->Primitives.Num();
for (uint32 PrimitiveIndex = 0; PrimitiveIndex < PrimitiveCount; ++PrimitiveIndex)
{
FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene->Primitives[PrimitiveIndex];
const bool bPrecomputedLightingBufferWasDirty = PrimitiveSceneInfo->NeedsPrecomputedLightingBufferUpdate();
UpdateCachePrimitive(AttachmentGroups, PrimitiveSceneInfo, false, true, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate);
// If it was already dirty, then the primitive is already in one of the view dirty primitive list at this point.
// This also ensures that a primitive does not get added twice to the list, which could create an array reallocation.
if (!bPrecomputedLightingBufferWasDirty)
{
PrimitiveSceneInfo->MarkPrecomputedLightingBufferDirty();
// Check if it is visible otherwise, it will be updated next time it is visible.
for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++)
{
FViewInfo& View = Renderer.Views[ViewIndex];
if (View.PrimitiveVisibilityMap[PrimitiveIndex])
{
// Since the update can be executed on a threaded job (see GILCUpdatePrimTaskEnabled), no reallocation must happen here.
checkSlow(View.DirtyPrecomputedLightingBufferPrimitives.Num() < View.DirtyPrecomputedLightingBufferPrimitives.Max());
View.DirtyPrecomputedLightingBufferPrimitives.Push(PrimitiveSceneInfo);
break; // We only need to add it in one of the view list.
}
}
}
}
}
else
{
TArray<uint32> SetBitIndices[4];
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_UpdateCachePreWalk);
for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++)
{
FViewInfo& View = Renderer.Views[ViewIndex];
SetBitIndices[ViewIndex].Reserve(View.PrimitiveVisibilityMap.Num());
for (FSceneSetBitIterator BitIt(View.PrimitiveVisibilityMap); BitIt; ++BitIt)
{
uint32 PrimitiveIndex = BitIt.GetIndex();
SetBitIndices[ViewIndex].Add(PrimitiveIndex);
}
// Any visible primitives with an indirect shadow need their ILC updated, since that determines the indirect shadow direction
for (int32 IndirectPrimitiveIndex = 0; IndirectPrimitiveIndex < View.IndirectShadowPrimitives.Num(); IndirectPrimitiveIndex++)
{
int32 PrimitiveIndex = View.IndirectShadowPrimitives[IndirectPrimitiveIndex]->GetIndex();
SetBitIndices[ViewIndex].AddUnique(PrimitiveIndex);
}
}
}
// Go over the views and operate on any relevant visible primitives
for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++)
{
FViewInfo& View = Renderer.Views[ViewIndex];
const TArray<uint32>& SetBits = SetBitIndices[ViewIndex];
for (int32 i = 0; i < SetBits.Num(); ++i)
{
uint32 PrimitiveIndex = SetBits[i];
FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene->Primitives[PrimitiveIndex];
const bool bPrecomputedLightingBufferWasDirty = PrimitiveSceneInfo->NeedsPrecomputedLightingBufferUpdate();
const FPrimitiveViewRelevance& PrimitiveRelevance = View.PrimitiveViewRelevanceMap[PrimitiveIndex];
UpdateCachePrimitive(AttachmentGroups, PrimitiveSceneInfo, bAllowUnbuiltPreview, PrimitiveRelevance.bOpaqueRelevance, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate);
// If it was already dirty, then the primitive is already in one of the view dirty primitive list at this point.
// This also ensures that a primitive does not get added twice to the list, which could create an array reallocation.
if (!bPrecomputedLightingBufferWasDirty && PrimitiveSceneInfo->NeedsPrecomputedLightingBufferUpdate())
{
// Since the update can be executed on a threaded job (see GILCUpdatePrimTaskEnabled), no reallocation must happen here.
checkSlow(View.DirtyPrecomputedLightingBufferPrimitives.Num() < View.DirtyPrecomputedLightingBufferPrimitives.Max());
View.DirtyPrecomputedLightingBufferPrimitives.Push(PrimitiveSceneInfo);
}
}
}
}
bUpdateAllCacheEntries = false;
}
}
//.........这里部分代码省略.........
bool bRedefiningSubobject = false;
if( TemplateClass )
{
}
else
{
// next, verify that a template actually exists in the parent class
UClass* ParentClass = ComponentOwnerClass->GetSuperClass();
check(ParentClass);
UObject* ParentCDO = ParentClass->GetDefaultObject();
check(ParentCDO);
BaseTemplate = StaticFindObjectFast(UObject::StaticClass(), SubobjectOuter, TemplateName);
bRedefiningSubobject = (BaseTemplate != NULL);
if (BaseTemplate == NULL)
{
BaseTemplate = StaticFindObjectFast(UObject::StaticClass(), ParentCDO, TemplateName);
}
if ( BaseTemplate == NULL )
{
// wasn't found
Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: No base template named %s found in parent class %s: %s"), *TemplateName.ToString(), *ParentClass->GetName(), *StrLine);
return NULL;
}
TemplateClass = BaseTemplate->GetClass();
}
// because the outer won't be a default object
checkSlow(TemplateClass != NULL);
if (bRedefiningSubobject)
{
// since we're redefining an object in the same text block, only need to import properties again
SourceText = ImportObjectProperties( (uint8*)BaseTemplate, SourceText, TemplateClass, SubobjectRoot, BaseTemplate,
Warn, Depth + 1, ContextSupplier ? ContextSupplier->CurrentLine : 0, &InstanceGraph, ActorRemapper );
}
else
{
UObject* Archetype = NULL;
UObject* ComponentTemplate = NULL;
// Since we are changing the class we can't use the Archetype,
// however that is fine since we will have been editing the CDO anyways
if (!FBlueprintEditorUtils::IsAnonymousBlueprintClass(SubobjectOuter->GetClass()))
{
// if an archetype was specified in the Begin Object block, use that as the template for the ConstructObject call.
FString ArchetypeName;
if (FParse::Value(Str, TEXT("Archetype="), ArchetypeName))
{
// if given a name, break it up along the ' so separate the class from the name
FString ObjectClass;
FString ObjectPath;
if ( FPackageName::ParseExportTextPath(ArchetypeName, &ObjectClass, &ObjectPath) )
{
// find the class
UClass* ArchetypeClass = (UClass*)StaticFindObject(UClass::StaticClass(), ANY_PACKAGE, *ObjectClass);
if (ArchetypeClass)
{
// if we had the class, find the archetype
Archetype = StaticFindObject(ArchetypeClass, ANY_PACKAGE, *ObjectPath);
}
}
UObject* FObjectInstancingGraph::GetInstancedSubobject( UObject* SourceSubobject, UObject* CurrentValue, UObject* CurrentObject, bool bDoNotCreateNewInstance, bool bAllowSelfReference )
{
checkSlow(SourceSubobject);
UObject* InstancedSubobject = INVALID_OBJECT;
if ( SourceSubobject != NULL && CurrentValue != NULL )
{
bool bAllowedSelfReference = bAllowSelfReference && SourceSubobject == SourceRoot;
bool bShouldInstance = bAllowedSelfReference || SourceSubobject->IsIn(SourceRoot);
if ( !bShouldInstance && CurrentValue->GetOuter() == CurrentObject->GetArchetype() )
{
// this code is intended to catch cases where SourceRoot contains subobjects assigned to instanced object properties, where the subobject's class
// contains components, and the class of the subobject is outside of the inheritance hierarchy of the SourceRoot, for example, a weapon
// class which contains UIObject subobject definitions in its defaultproperties, where the property referencing the UIObjects is marked instanced.
bShouldInstance = true;
// if this case is triggered, ensure that the CurrentValue of the component property is still pointing to the template component.
check(SourceSubobject == CurrentValue);
}
if ( bShouldInstance )
{
// search for the unique component instance that corresponds to this component template
InstancedSubobject = GetDestinationObject(SourceSubobject);
if ( InstancedSubobject == NULL )
{
if (bDoNotCreateNewInstance)
{
InstancedSubobject = INVALID_OBJECT; // leave it unchanged
}
else
{
// if the Outer for the component currently assigned to this property is the same as the object that we're instancing components for,
// the component does not need to be instanced; otherwise, there are two possiblities:
// 1. CurrentValue is a template and needs to be instanced
// 2. CurrentValue is an instanced component, in which case it should already be in InstanceGraph, UNLESS the component was created
// at runtime (editinline export properties, for example). If that is the case, CurrentValue will be an instance that is not linked
// to the component template referenced by CurrentObject's archetype, and in this case, we also don't want to re-instance the component template
bool bIsRuntimeInstance = CurrentValue != SourceSubobject && CurrentValue->GetOuter() == CurrentObject;
if ( bDoNotCreateNewInstance || bIsRuntimeInstance )
{
InstancedSubobject = CurrentValue;
}
else
{
// If the component template is relevant in this context(client vs server vs editor), instance it.
const bool bShouldLoadForClient = SourceSubobject->NeedsLoadForClient();
const bool bShouldLoadForServer = SourceSubobject->NeedsLoadForServer();
const bool bShouldLoadForEditor = ( GIsEditor && ( bShouldLoadForClient || !CurrentObject->RootPackageHasAnyFlags(PKG_PlayInEditor) ) );
if ( ((GIsClient && bShouldLoadForClient) || (GIsServer && bShouldLoadForServer) || bShouldLoadForEditor) )
{
// this is the first time the instance corresponding to SourceSubobject has been requested
// get the object instance corresponding to the source component's Outer - this is the object that
// will be used as the Outer for the destination component
UObject* SubobjectOuter = GetDestinationObject(SourceSubobject->GetOuter());
checkf(SubobjectOuter, TEXT("No corresponding destination object found for '%s' while attempting to instance component '%s'"), *SourceSubobject->GetOuter()->GetFullName(), *SourceSubobject->GetFullName());
FName SubobjectName = SourceSubobject->GetFName();
// final archetype archetype will be the archetype of the template
UObject* FinalSubobjectArchetype = CurrentValue->GetArchetype();
// Don't seach for the existing subobjects on Blueprint-generated classes. What we'll find is a subobject
// created by the constructor which may not have all of its fields initialized to the correct value (which
// should be coming from a blueprint).
// NOTE: Since this function is called ONLY for Blueprint-generated classes, we may as well delete this 'if'.
if (!SubobjectOuter->GetClass()->HasAnyClassFlags(CLASS_CompiledFromBlueprint))
{
InstancedSubobject = StaticFindObjectFast(NULL, SubobjectOuter, SubobjectName);
}
if (InstancedSubobject && IsCreatingArchetype())
{
// since we are updating an archetype, this needs to reconstruct as that is the mechanism used to copy properties
// it will destroy the existing object and overwrite it
InstancedSubobject = NULL;
}
if (!InstancedSubobject)
{
// finally, create the component instance
InstancedSubobject = ConstructObject<UObject>(SourceSubobject->GetClass(), SubobjectOuter,
SubobjectName, SubobjectOuter->GetMaskedFlags(RF_PropagateToSubObjects), SourceSubobject,
true, this);
}
}
}
}
}
else if ( IsLoadingObject() && InstancedSubobject->GetClass()->HasAnyClassFlags(CLASS_HasInstancedReference) )
{
/* When loading an object from disk, in some cases we have a component which has a reference to another component in DestinationObject which
wasn't serialized and hasn't yet been instanced. For example, the PointLight class declared two component templates:
//.........这里部分代码省略.........
请发表评论