Files
UnrealEngineUWP/Engine/Source/Editor/UnrealEd/Public/TickableEditorObject.h
matt peters 0724105f6c BulkDataRegistry
Updating FVirtualizedUntypedBulkData and textures to use the BulkDataRegistry.
BulkDataRegistry: Add get/put accessors for the cached BulkDataList of packages.
EditorDomain: Move ClassDigests into a global variable that can be shared with BulkDataRegistry.
EditorDomain: Improve performance of GetFileSize by fetching metadata only.
Tickable Cook Objects, for systems used by the cooker that need to be ticked.
Implementation of the the BulkDataRegistry that uses the DDC cache for persistent storage of the BulkDataList.

#rb Devin.Doucette, Paul.Chipchase, Zousar.Shaker

#ROBOMERGE-SOURCE: CL 16768772 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v835-16672529)

[CL 16768778 by matt peters in ue5-release-engine-test branch]
2021-06-24 00:51:58 -04:00

240 lines
7.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Tickable.h"
/**
* This class provides common registration for gamethread editor only tickable objects. It is an
* abstract base class requiring you to implement the GetStatId, IsTickable, and Tick methods.
* If you need a class that can tick in both the Editor and at Runtime then use FTickableGameObject
* instead, overriding the IsTickableInEditor() function instead.
*/
class UNREALED_API FTickableEditorObject : public FTickableObjectBase
{
public:
static void TickObjects(const float DeltaSeconds)
{
TArray<FTickableEditorObject*>& PendingTickableObjects = GetPendingTickableObjects();
TArray<FTickableObjectEntry>& TickableObjects = GetTickableObjects();
for (FTickableEditorObject* PendingTickable : PendingTickableObjects)
{
AddTickableObject(TickableObjects, PendingTickable);
}
PendingTickableObjects.Empty();
if (TickableObjects.Num() > 0)
{
check(!bIsTickingObjects);
bIsTickingObjects = true;
bool bNeedsCleanup = false;
for (const FTickableObjectEntry& TickableEntry : TickableObjects)
{
if (FTickableObjectBase* TickableObject = TickableEntry.TickableObject)
{
if ((TickableEntry.TickType == ETickableTickType::Always) || TickableObject->IsTickable())
{
ObjectBeingTicked = TickableObject;
TickableObject->Tick(DeltaSeconds);
ObjectBeingTicked = nullptr;
}
// In case it was removed during tick
if (TickableEntry.TickableObject == nullptr)
{
bNeedsCleanup = true;
}
}
else
{
bNeedsCleanup = true;
}
}
if (bNeedsCleanup)
{
TickableObjects.RemoveAll([](const FTickableObjectEntry& Entry) { return (Entry.TickableObject == nullptr); });
}
bIsTickingObjects = false;
}
}
/** Registers this instance with the static array of tickable objects. */
FTickableEditorObject()
{
ensure(IsInGameThread() || IsInAsyncLoadingThread());
check(!GetPendingTickableObjects().Contains(this));
check(!GetTickableObjects().Contains(this));
GetPendingTickableObjects().Add(this);
}
/** Removes this instance from the static array of tickable objects. */
virtual ~FTickableEditorObject()
{
ensureMsgf(ObjectBeingTicked != this, TEXT("Detected possible memory stomp. We are in the Tickable objects Tick function but hit its deconstructor, the 'this' pointer for the Object will now be invalid"));
ensure(IsInGameThread() || IsInAsyncLoadingThread());
if (bCollectionIntact && GetPendingTickableObjects().Remove(this) == 0)
{
RemoveTickableObject(GetTickableObjects(), this, bIsTickingObjects);
}
}
private:
/**
* Class that avoids crashes when unregistering a tickable editor object too late.
*
* Some tickable objects can outlive the collection
* (global/static destructor order is unpredictable).
*/
class TTickableObjectsCollection : public TArray<FTickableObjectEntry>
{
public:
~TTickableObjectsCollection()
{
FTickableEditorObject::bCollectionIntact = false;
}
};
friend class TTickableObjectsCollection;
/** True if collection of tickable objects is still intact. */
static bool bCollectionIntact;
/** True if currently ticking of tickable editor objects. */
static bool bIsTickingObjects;
/** Set if we are in the Tick function for an editor tickable object */
static FTickableObjectBase* ObjectBeingTicked;
static TArray<FTickableObjectEntry>& GetTickableObjects();
static TArray<FTickableEditorObject*>& GetPendingTickableObjects();
};
/**
* The same as FTickableEditorObject, but for systems that need to be ticked periodically during
* cooking.
* If a system needs to be cooked both during cook commandlet and in editor without the cook commandlet,
* it should dual-inherit from both FTickableCookObject and FTickableEditorObject.
* TODO: Reduce duplication between FTickableCookObject and FTickableEditorObject.
*/
class UNREALED_API FTickableCookObject : public FTickableObjectBase
{
public:
static void TickObjects(const float DeltaSeconds, bool bCookComplete)
{
TArray<FTickableCookObject*>& PendingTickableObjects = GetPendingTickableObjects();
TArray<FTickableObjectEntry>& TickableObjects = GetTickableObjects();
for (FTickableCookObject* PendingTickable : PendingTickableObjects)
{
AddTickableObject(TickableObjects, PendingTickable);
}
PendingTickableObjects.Empty();
if (TickableObjects.Num() > 0)
{
check(!bIsTickingObjects);
bIsTickingObjects = true;
bool bNeedsCleanup = false;
for (const FTickableObjectEntry& TickableEntry : TickableObjects)
{
if (FTickableObjectBase* TickableObject = TickableEntry.TickableObject)
{
if ((TickableEntry.TickType == ETickableTickType::Always) || TickableObject->IsTickable())
{
FTickableCookObject* CookTickableObject = static_cast<FTickableCookObject*>(TickableObject);
ObjectBeingTicked = CookTickableObject;
CookTickableObject->TickCook(DeltaSeconds, bCookComplete);
ObjectBeingTicked = nullptr;
}
// In case it was removed during tick
if (TickableEntry.TickableObject == nullptr)
{
bNeedsCleanup = true;
}
}
else
{
bNeedsCleanup = true;
}
}
if (bNeedsCleanup)
{
TickableObjects.RemoveAll([](const FTickableObjectEntry& Entry) { return (Entry.TickableObject == nullptr); });
}
bIsTickingObjects = false;
}
}
/** Registers this instance with the static array of tickable objects. */
FTickableCookObject()
{
ensure(IsInGameThread() || IsInAsyncLoadingThread());
check(!GetPendingTickableObjects().Contains(this));
check(!GetTickableObjects().Contains(this));
GetPendingTickableObjects().Add(this);
}
/** Removes this instance from the static array of tickable objects. */
virtual ~FTickableCookObject()
{
ensureMsgf(ObjectBeingTicked != this, TEXT("Detected possible memory stomp. We are in the Tickable objects Tick function but hit its deconstructor, the 'this' pointer for the Object will now be invalid"));
ensure(IsInGameThread() || IsInAsyncLoadingThread());
if (bCollectionIntact && GetPendingTickableObjects().Remove(this) == 0)
{
RemoveTickableObject(GetTickableObjects(), this, bIsTickingObjects);
}
}
virtual void TickCook(float DeltaTime, bool bCookCompete) = 0;
private:
/**
* Class that avoids crashes when unregistering a tickable editor object too late.
*
* Some tickable objects can outlive the collection
* (global/static destructor order is unpredictable).
*/
class TTickableObjectsCollection : public TArray<FTickableObjectEntry>
{
public:
~TTickableObjectsCollection()
{
FTickableCookObject::bCollectionIntact = false;
}
};
friend class TTickableObjectsCollection;
/** True if collection of tickable objects is still intact. */
static bool bCollectionIntact;
/** True if currently ticking of tickable editor objects. */
static bool bIsTickingObjects;
/** Set if we are in the Tick function for an editor tickable object */
static FTickableCookObject* ObjectBeingTicked;
static TArray<FTickableObjectEntry>& GetTickableObjects();
static TArray<FTickableCookObject*>& GetPendingTickableObjects();
};