Created
December 2, 2021 15:20
-
-
Save vgvgvvv/6b539beeca3c1dba2fe65633fe196289 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ActionConsumeTickManager.h" | |
#include "DynamicStats.h" | |
FConsumable* FConsumable::AddAction(TFunction<void()> InFunc) | |
{ | |
Parent->AddAction(InFunc); | |
return this; | |
} | |
void FConsumable::ConsumeAction(float DeltaTime) | |
{ | |
Parent->ConsumeAction(DeltaTime); | |
} | |
FBaseConsumeQueue* FConsumable::GetRoot() | |
{ | |
FConsumable* Root = this; | |
while (Root->Parent != nullptr) | |
{ | |
Root = Root->Parent; | |
} | |
return static_cast<FBaseConsumeQueue*>(Root); | |
} | |
bool FConsumable::IsEmpty() | |
{ | |
return GetRoot()->IsQueueEmpty(); | |
} | |
void FConsumable::Clear() | |
{ | |
GetRoot()->ClearQueue(); | |
} | |
void FConsumable::Flush() | |
{ | |
auto Root = GetRoot(); | |
IsFlushing = true; | |
while (!Root->IsQueueEmpty()) | |
{ | |
ConsumeAction(0); | |
} | |
IsFlushing = false; | |
} | |
FConsumable* FConsumable::AddInterval(float Invertal) | |
{ | |
return new FDelayTimeConsumeQueue(this, Invertal); | |
} | |
FConsumable* FConsumable::SetConsumeNumber(int Count) | |
{ | |
return new FCountConsumeQueue(this, Count); | |
} | |
FConsumable* FConsumable::SetConsumeCondition(TFunction<bool(FConsumable*)> InAddCondition, | |
TFunction<bool(FConsumable*)> InConsumeCondition) | |
{ | |
return new FConditionConsumeQueue(this, InAddCondition, InConsumeCondition); | |
} | |
FConsumable* FConsumable::NotDelayUntilCallCount(int CallCount) | |
{ | |
return new FNotDelayUntilCallCountConsumeQueue(this, CallCount); | |
} | |
FConsumable* FConsumable::SetTimeLimit(int Time) | |
{ | |
return new FTimelimitConsueQueue(this, Time); | |
} | |
FConsumable* FConsumable::SetNext(FConsumable* Next) | |
{ | |
if(!Next) | |
{ | |
return this; | |
} | |
return new FOnNextConsumeQueue(this, Next); | |
} | |
FConsumable* FConsumable::Create() | |
{ | |
return new FBaseConsumeQueue(); | |
} | |
void FConsumable::SetOwner(FActionConsumeTickManager* InOwner) | |
{ | |
Owner = InOwner; | |
} | |
void FBaseConsumeQueue::ConsumeAction(float DeltaTime) | |
{ | |
if (!ConsumeQueue.IsEmpty()) | |
{ | |
FConsumableAction Action; | |
ConsumeQueue.Dequeue(Action); | |
Action.Execute(); | |
} | |
} | |
FConsumable* FBaseConsumeQueue::AddAction(TFunction<void()> InFunc) | |
{ | |
ConsumeQueue.Enqueue(FConsumableAction(InFunc)); | |
return this; | |
} | |
bool FBaseConsumeQueue::IsQueueEmpty() | |
{ | |
return ConsumeQueue.IsEmpty(); | |
} | |
void FBaseConsumeQueue::ClearQueue() | |
{ | |
ConsumeQueue.Empty(); | |
} | |
void FDelayTimeConsumeQueue::ConsumeAction(float DeltaTime) | |
{ | |
if(IsFlushing) | |
{ | |
Clear(); | |
return; | |
} | |
if (IsEmpty()) | |
{ | |
return; | |
} | |
if (CurrentTime < WaitTime) | |
{ | |
CurrentTime += DeltaTime; | |
return; | |
} | |
Parent->ConsumeAction(CurrentTime); | |
CurrentTime = 0; | |
} | |
void FCountConsumeQueue::ConsumeAction(float DeltaTime) | |
{ | |
for (int i = 0; i < ConsumCountOneFrame; i++) | |
{ | |
if (IsEmpty()) | |
{ | |
return; | |
} | |
if (i > 0) | |
{ | |
// 中间的耗时应为0 | |
Parent->ConsumeAction(0); | |
} | |
else | |
{ | |
Parent->ConsumeAction(DeltaTime); | |
} | |
} | |
} | |
FConsumable* FConditionConsumeQueue::AddAction(TFunction<void()> InFunc) | |
{ | |
if(IsFlushing) | |
{ | |
return this; | |
} | |
if (AddCondition(this)) | |
{ | |
Parent->AddAction(InFunc); | |
} | |
return this; | |
} | |
void FConditionConsumeQueue::ConsumeAction(float DeltaTime) | |
{ | |
if (IsFlushing) | |
{ | |
// 防止Flash时反复重试导致死循环 | |
Clear(); | |
return; | |
} | |
if (IsEmpty()) | |
{ | |
return; | |
} | |
if (ConsumeCondition(this)) | |
{ | |
Parent->ConsumeAction(DeltaTime); | |
} | |
} | |
void FNotDelayUntilCallCountConsumeQueue::ConsumeAction(float DeltaTime) | |
{ | |
if(!IsEmpty()) | |
{ | |
Parent->ConsumeAction(DeltaTime); | |
} | |
CurrentCount = 0; | |
} | |
FConsumable* FNotDelayUntilCallCountConsumeQueue::AddAction(TFunction<void()> InFunc) | |
{ | |
if(CurrentCount < CallCount) | |
{ | |
InFunc(); | |
CurrentCount++; | |
}else | |
{ | |
Parent->AddAction(InFunc); | |
} | |
return this; | |
} | |
void FTimelimitConsueQueue::ConsumeAction(float DeltaTime) | |
{ | |
if (IsFlushing) | |
{ | |
// 防止Flash时反复重试导致死循环 | |
Clear(); | |
return; | |
} | |
auto BeginTime = FPlatformTime::Cycles64(); | |
bool IsFirst = true; | |
while (!IsEmpty() && (FPlatformTime::Cycles64() - BeginTime) * FPlatformTime::GetSecondsPerCycle64() * 1000 < ConsumeLimitTime) | |
{ | |
if(IsFirst) | |
{ | |
Parent->ConsumeAction(DeltaTime); | |
IsFirst = false; | |
}else | |
{ | |
Parent->ConsumeAction(0); | |
} | |
} | |
} | |
void FOnNextConsumeQueue::ConsumeAction(float DeltaTime) | |
{ | |
if (IsFlushing) | |
{ | |
// 防止Flash时反复重试导致死循环 | |
Clear(); | |
return; | |
} | |
Parent->ConsumeAction(DeltaTime); | |
if(IsEmpty()) | |
{ | |
Owner->AddConsumeQueue(NextConsumable); | |
} | |
} | |
FActionConsumeTickManager::~FActionConsumeTickManager() | |
{ | |
static TArray<FString> Keys; | |
Keys.Empty(); | |
ConsumeActionQueueMap.GetKeys(Keys); | |
for (int i = 0; i < Keys.Num(); i++) | |
{ | |
auto Temp = ConsumeActionQueueMap[Keys[i]]; | |
Temp->Clear(); | |
ConsumeActionQueueMap.Remove(Keys[i]); | |
delete Temp; | |
} | |
for (int i = TempConsumables.Num() - 1; i >= 0; i--) | |
{ | |
auto Consumable = TempConsumables[i]; | |
Consumable->Clear(); | |
delete Consumable; | |
} | |
TempConsumables.Empty(); | |
} | |
void FActionConsumeTickManager::Tick(float DeltaTime) | |
{ | |
if(bSkipThisFrame) | |
{ | |
bSkipThisFrame = false; | |
return; | |
} | |
QUICK_SCOPE_CYCLE_COUNTER(Stat_FActionConsumeTickManager_Tick) | |
static TArray<FString> Keys; | |
Keys.Empty(); | |
ConsumeActionQueueMap.GetKeys(Keys); | |
for (int i = 0; i < Keys.Num(); i++) | |
{ | |
DYNAMIC_SCOPE_CYCLE_COUNTER(Stat_FActionConsumeTickManager_Tick, Keys[i]) | |
auto Consumable = ConsumeActionQueueMap[Keys[i]]; | |
Consumable->ConsumeAction(DeltaTime); | |
if(Consumable->IsEmpty() && Consumable->AutoRemove) | |
{ | |
ConsumeActionQueueMap.Remove(Keys[i]); | |
delete Consumable; | |
} | |
} | |
static TArray<FConsumable*> Remove; | |
Remove.Empty(); | |
for (int i = TempConsumables.Num() - 1; i >= 0; i--) | |
{ | |
QUICK_SCOPE_CYCLE_COUNTER(Stat_FActionConsumeTickManager_Temp_Tick) | |
auto Consumable = TempConsumables[i]; | |
Consumable->ConsumeAction(DeltaTime); | |
if (Consumable->IsEmpty()) | |
{ | |
Remove.Add(TempConsumables[i]); | |
} | |
} | |
for(int i = 0; i < Remove.Num(); i ++) | |
{ | |
auto Consumable = Remove[i]; | |
TempConsumables.Remove(Consumable); | |
delete Consumable; | |
} | |
} | |
void FActionConsumeTickManager::AddConsumeQueue(FString QueueName, FConsumable* Consumable) | |
{ | |
if (!ConsumeActionQueueMap.Contains(QueueName) && Consumable) | |
{ | |
Consumable->SetOwner(this); | |
ConsumeActionQueueMap.Add(QueueName, Consumable); | |
} | |
} | |
void FActionConsumeTickManager::AddConsumeQueue(FConsumable* Consumable) | |
{ | |
if(!Consumable) | |
{ | |
return; | |
} | |
Consumable->SetOwner(this); | |
TempConsumables.Add(Consumable); | |
} | |
void FActionConsumeTickManager::Flush() | |
{ | |
static TArray<FString> Keys; | |
Keys.Empty(); | |
ConsumeActionQueueMap.GetKeys(Keys); | |
for (int i = 0; i < Keys.Num(); i++) | |
{ | |
ConsumeActionQueueMap[Keys[i]]->Flush(); | |
} | |
for(int i = TempConsumables.Num() - 1; i >=0 ; i--) | |
{ | |
auto Consumable = TempConsumables[i]; | |
Consumable->Flush(); | |
delete Consumable; | |
} | |
TempConsumables.Empty(); | |
} | |
void FActionConsumeTickManager::Clear() | |
{ | |
static TArray<FString> Keys; | |
Keys.Empty(); | |
ConsumeActionQueueMap.GetKeys(Keys); | |
for (int i = 0; i < Keys.Num(); i++) | |
{ | |
ConsumeActionQueueMap[Keys[i]]->Clear(); | |
} | |
for(int i = TempConsumables.Num() - 1; i >=0 ; i--) | |
{ | |
auto Consumable = TempConsumables[i]; | |
Consumable->Clear(); | |
delete Consumable; | |
} | |
TempConsumables.Empty(); | |
} | |
void FActionConsumeTickManager::SkipThisFrame() | |
{ | |
bSkipThisFrame = true; | |
} | |
FConsumable* FActionConsumeTickManager::GetConsumable(FString QueueName) | |
{ | |
if (!ConsumeActionQueueMap.Contains(QueueName)) | |
{ | |
return nullptr; | |
} | |
return ConsumeActionQueueMap[QueueName]; | |
} | |
bool FActionConsumeTickManager::GetOrAddConsumable(FString QueueName, FConsumable*& Result) | |
{ | |
if (!ConsumeActionQueueMap.Contains(QueueName)) | |
{ | |
Result = FConsumable::Create(); | |
ConsumeActionQueueMap.Add(QueueName, Result); | |
return true; | |
} | |
Result = ConsumeActionQueueMap[QueueName]; | |
return false; | |
} | |
bool FActionConsumeTickManager::GetOrAddConsumable(FString QueueName, FConsumable*& Result, TFunction<FConsumable*(FConsumable*)> OnCreate) | |
{ | |
if (!ConsumeActionQueueMap.Contains(QueueName)) | |
{ | |
Result = OnCreate(FConsumable::Create()); | |
ConsumeActionQueueMap.Add(QueueName, Result); | |
return true; | |
} | |
Result = ConsumeActionQueueMap[QueueName]; | |
return false; | |
} | |
bool FActionConsumeTickManager::IsTickable() const | |
{ | |
return true; | |
} | |
TStatId FActionConsumeTickManager::GetStatId() const | |
{ | |
#if UE_BUILD_SHIPPING | |
return TStatId(); | |
#else | |
FString Temp = TEXT("FActionConsumeTickManager"); | |
return FDynamicStats::CreateStatId<FStatGroup_STATGROUP_UObjects>(Temp); | |
#endif | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "Queue.h" | |
#include "Tickable.h" | |
#include "Function.h" | |
class FActionConsumeTickManager; | |
class ENGINE_API FConsumableAction | |
{ | |
public: | |
FConsumableAction() { } | |
FConsumableAction(TFunction<void()> InFunc) { Func = InFunc; } | |
void Execute() | |
{ | |
Func(); | |
}; | |
private: | |
TFunction<void()> Func; | |
}; | |
// 可消耗Tick的基类,用于后续包装 | |
class ENGINE_API FConsumable | |
{ | |
public: | |
FConsumable() : | |
FConsumable(nullptr) {} | |
FConsumable(FConsumable* Consumable) : | |
Owner(nullptr), Parent(Consumable), IsFlushing(false), AutoRemove(false) {} | |
virtual ~FConsumable() | |
{ | |
if (Parent != nullptr) | |
{ | |
delete Parent; | |
} | |
} | |
/** | |
* 添加消耗的行为 | |
*/ | |
virtual FConsumable* AddAction(TFunction<void()> InFunc);; | |
/** | |
* 一帧内的消耗 | |
*/ | |
virtual void ConsumeAction(float DeltaTime); | |
class FConsumable* AddInterval(float Invertal); | |
class FBaseConsumeQueue* GetRoot(); | |
bool IsEmpty(); | |
void Clear(); | |
void Flush(); | |
class FConsumable* SetConsumeNumber(int Count); | |
class FConsumable* SetConsumeCondition(TFunction<bool(FConsumable*)> InAddCondition, TFunction<bool(FConsumable*)> InConsumeCondition); | |
// 在一定数量下直接调用,如果超过则加入消耗队列 | |
class FConsumable* NotDelayUntilCallCount(int CallCount); | |
// 在一定时间内消耗行为,超过时间则停止 | |
class FConsumable* SetTimeLimit(int Time); | |
class FConsumable* SetNext(FConsumable* Next); | |
static class FConsumable* Create(); | |
void SetOwner(FActionConsumeTickManager* InOwner); | |
public: | |
FActionConsumeTickManager* Owner; | |
FConsumable* Parent; | |
bool IsFlushing; | |
bool AutoRemove; | |
}; | |
class FBaseConsumeQueue : public FConsumable | |
{ | |
public: | |
FBaseConsumeQueue() {} | |
void ConsumeAction(float DeltaTime) override; | |
FConsumable* AddAction(TFunction<void()> InFunc) override; | |
bool IsQueueEmpty(); | |
void ClearQueue(); | |
private: | |
TQueue<FConsumableAction> ConsumeQueue; | |
}; | |
class ENGINE_API FDelayTimeConsumeQueue : public FConsumable | |
{ | |
public: | |
FDelayTimeConsumeQueue(FConsumable* Consumable, float InWaitTime) : | |
FConsumable(Consumable) | |
, WaitTime(InWaitTime) | |
, CurrentTime(0) | |
{ | |
} | |
void ConsumeAction(float DeltaTime) override;; | |
private: | |
float WaitTime; | |
float CurrentTime; | |
}; | |
class ENGINE_API FCountConsumeQueue : public FConsumable | |
{ | |
public: | |
FCountConsumeQueue(FConsumable* Consumable, int InConsumCountOneFrame) | |
: FConsumable(Consumable), ConsumCountOneFrame(InConsumCountOneFrame) | |
{ | |
} | |
void ConsumeAction(float DeltaTime) override; | |
private: | |
int ConsumCountOneFrame; | |
}; | |
class ENGINE_API FConditionConsumeQueue : public FConsumable | |
{ | |
public: | |
FConditionConsumeQueue(FConsumable* Consumable, TFunction<bool(FConsumable*)> InAddCondition, TFunction<bool(FConsumable*)> InConsumeCondition) | |
: FConsumable(Consumable), AddCondition(InAddCondition), ConsumeCondition(InConsumeCondition) | |
{ | |
} | |
FConsumable* AddAction(TFunction<void()> InFunc) override; | |
void ConsumeAction(float DeltaTime) override; | |
private: | |
TFunction<bool(FConsumable*)> AddCondition; | |
TFunction<bool(FConsumable*)> ConsumeCondition; | |
}; | |
// 直接进行调用直到一帧内调用次数超过一定数量 | |
class ENGINE_API FNotDelayUntilCallCountConsumeQueue : public FConsumable | |
{ | |
public: | |
FNotDelayUntilCallCountConsumeQueue(FConsumable* Consumable, int InCallCount) | |
: FConsumable(Consumable), CallCount(InCallCount),CurrentCount(0) | |
{ | |
} | |
void ConsumeAction(float DeltaTime) override; | |
FConsumable* AddAction(TFunction<void()> InFunc) override; | |
private: | |
int CallCount; | |
int CurrentCount; | |
}; | |
class ENGINE_API FTimelimitConsueQueue : public FConsumable | |
{ | |
public: | |
FTimelimitConsueQueue(FConsumable* Consumable, int InConsumeLimitTime) | |
: FConsumable(Consumable), ConsumeLimitTime(InConsumeLimitTime) | |
{ | |
} | |
void ConsumeAction(float DeltaTime) override; | |
private: | |
//限制时间单位:ms | |
int ConsumeLimitTime; | |
}; | |
class ENGINE_API FOnNextConsumeQueue : public FConsumable | |
{ | |
public: | |
FOnNextConsumeQueue(FConsumable* Consumable, FConsumable* InNextConsumable) | |
: FConsumable(Consumable), NextConsumable(InNextConsumable) | |
{ | |
} | |
void ConsumeAction(float DeltaTime) override; | |
private: | |
FConsumable* NextConsumable; | |
}; | |
class ENGINE_API FActionConsumeTickManager : public FTickableGameObject | |
{ | |
public: | |
FActionConsumeTickManager() | |
: bSkipThisFrame(false) | |
{ | |
} | |
virtual ~FActionConsumeTickManager() override; | |
void Tick(float DeltaTime) override; | |
bool IsTickable() const override; | |
TStatId GetStatId() const override; | |
void AddConsumeQueue(FString QueueName, FConsumable* Consumable); | |
void AddConsumeQueue(FConsumable* Consumable); | |
FConsumable* GetConsumable(FString QueueName); | |
bool GetOrAddConsumable(FString QueueName, FConsumable*& Result); | |
bool GetOrAddConsumable(FString QueueName, FConsumable*& Result, TFunction<FConsumable*(FConsumable*)> OnCreate); | |
void Flush(); | |
void Clear(); | |
void SkipThisFrame(); | |
private: | |
TMap<FString, FConsumable*> ConsumeActionQueueMap; | |
TArray<FConsumable*> TempConsumables; | |
bool bSkipThisFrame; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment