首页 > 其他分享 >UE对象池

UE对象池

时间:2024-08-02 11:17:17浏览次数:16  
标签:PooledObject 对象 void Object Actor ObjectClass template UE

对象池是用泛型实现的,可以自动管理结构体和对象,可以用泛型去获取对象,可以用可变参去构建对象,也可以用虚幻的类型引用来获取对象,对于类对象可以传入自定义的初始化回调函数/重置函数来修改对象的数据或状态,可以目前是用泛型获取对象的UClass*或UScriptStruct*来存储对象,后续可以考虑用Level为单位去管理对象池。同时目前对象池继承的类是组件类,后面可以考虑继承UTickableWorldSubsystem来实现这个对象池。 在用到虚幻的反射去或者对象的分类的时候,发现其实虚幻的发射也不是纯动态的,也会通过生成部分静态函数,这就和我以前见过的一个宏,宏内部是静态函数,去注册药反射的字段和函数。

  PooledObject.h这个结构体用来描述单个对象。

#include "CoreMinimal.h"
#include "PooledObject.generated.h"

USTRUCT()
struct FPooledObject
{
    GENERATED_BODY()

    UPROPERTY()
    UObject* Object;

    TSharedPtr<void> StructData;

    UPROPERTY()
    bool bIsInUse;

    UPROPERTY()
    FDateTime LastUseTime;
};

ObjectPoolManager.h用来管理对象池

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GenericClassObjectPool.h"
#include "GenericStructObjectPool.h"
#include "Components/ActorComponent.h"
#include "ObjectPoolManager.generated.h"
USTRUCT()
struct FPoolKey
{
    GENERATED_BODY()

    UPROPERTY()
    UClass* ObjectClass;

    UPROPERTY()
    UScriptStruct* StructClass;

    FPoolKey() : ObjectClass(nullptr), StructClass(nullptr) {}

    FPoolKey(UClass* InObjectClass) : ObjectClass(InObjectClass), StructClass(nullptr) {}

    FPoolKey(UScriptStruct* InStructClass) : ObjectClass(nullptr), StructClass(InStructClass) {}

    bool operator==(const FPoolKey& Other) const
    {
        return ObjectClass == Other.ObjectClass && StructClass == Other.StructClass;
    }

    bool operator!=(const FPoolKey& Other) const
    {
        return !(*this == Other);
    }

    friend uint32 GetTypeHash(const FPoolKey& Key)
    {
        uint32 Hash = 0;
        if (Key.ObjectClass)
        {
            Hash = GetTypeHash(Key.ObjectClass);
        }
        else if (Key.StructClass)
        {
            Hash = GetTypeHash(Key.StructClass);
        }
        return Hash;
    }
};

UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class YRP_API UObjectPoolManager : public UActorComponent
{
    GENERATED_BODY()

public:
    UObjectPoolManager();

    //仅用于创建类对象,不能传入结构体
    template <class T, class ... Args>
    T* GetObject(TSubclassOf<T> ObjectClass, Args&& ... InitialParams);
    template<typename T, typename... Args>
    T* GetObject(Args&&... InitialParams);
    
    template<typename T>
    void ReturnObject(T* Object);

    template<typename T>
    void ReturnObject(TSubclassOf<T> ObjectClass, T* Object);
    
    void SetMaxPoolSize(int32 MaxSize);
    void SetAutoCleanupInterval(float Interval);

    template<typename T, typename... Args>
    void PreloadObjects(int32 Count, Args&&... InitialParams);
    
    // 设置初始化回调函数
    template<typename T>
    void SetInitializeCallback(TFunction<void(T*)> Callback);

    // 设置重置回调函数
    template<typename T>
    void SetResetCallback(TFunction<void(T*)> Callback);
    void LogPerformanceStats();
    
protected:
    virtual void BeginPlay() override;
    virtual void TickComponent(float DeltaTime, ELevelTick TickType,
                               FActorComponentTickFunction* ThisTickFunction) override;
    virtual  void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private:
    UPROPERTY()
    TMap<FPoolKey, UObject*> Pools;
    FCriticalSection PoolMutex;
    int32 MaxPoolSize;
    float AutoCleanupInterval;
    float PoolAdjustInterval;
    float TimeSinceLastCleanup;
    float TimeSinceLastPoolAdjust;

    template<typename T>
    UObject* GetOrCreatePool(FPoolKey& Key);

    UObject* GetOrCreatePool(FPoolKey& Key);
};

template <typename T, typename ... Args>
T* UObjectPoolManager::GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams)
{
    FPoolKey PoolKey(ObjectClass.Get());
    if (UObject* Pool = GetOrCreatePool(PoolKey))
    {
        if constexpr (TIsDerivedFrom<T, UObject>::Value)
        {
            return Cast<UGenericClassObjectPool>(Pool)->GetObject<T>(ObjectClass, Forward<Args>(InitialParams)...);
        }
    }
    return nullptr;
}

template <typename T, typename ... Args>
T* UObjectPoolManager::GetObject(Args&&... InitialParams)
{
    FPoolKey PoolKey;
    if( UObject* Pool = GetOrCreatePool<T>(PoolKey))
    {
        if constexpr (TIsDerivedFrom<T, UObject>::Value)
        {
            return Cast<UGenericClassObjectPool>(Pool)->GetObject<T>(Forward<Args>(InitialParams)...);
        }
        else if (TBaseStructure<T>::Get() != nullptr)
        {
            return Cast<UGenericStructObjectPool>(Pool)->GetObject<T>(Forward<Args>(InitialParams)...);
        }
    }
    return nullptr; 
}


template <typename T>
void UObjectPoolManager::ReturnObject(T* Object)
{
    if (Object)
    {
        FPoolKey PoolKey;
        PoolMutex.Lock();
        if (UObject* Pool = GetOrCreatePool<T>(PoolKey))
        {
            if constexpr (TIsDerivedFrom<T, UObject>::Value)
            {
               Cast<UGenericClassObjectPool>(Pool)->ReturnObject(Object);
            }
            else if (TBaseStructure<T>::Get() != nullptr)
            {
                Cast<UGenericStructObjectPool>(Pool)->ReturnObject(Object);
            }
        }
        PoolMutex.Unlock();
    }
}

template <typename T>
void UObjectPoolManager::ReturnObject(TSubclassOf<T> ObjectClass, T* Object)
{
    if (Object)
    {
        FPoolKey PoolKey(ObjectClass.Get());
        PoolMutex.Lock();
        if (UObject* Pool = GetOrCreatePool(PoolKey))
        {
            if constexpr (TIsDerivedFrom<T, UObject>::Value)
            {
                Cast<UGenericClassObjectPool>(Pool)->ReturnObject(ObjectClass,Object);
            }
        }
        PoolMutex.Unlock();
    }
}

template <typename T, typename... Args>
void UObjectPoolManager::PreloadObjects(int32 Count, Args&&... InitialParams)
{
    FPoolKey PoolKey;
    if ( UObject* Pool = GetOrCreatePool<T>(PoolKey))
    {
        if constexpr (TIsDerivedFrom<T, UObject>::Value)
        {
            Cast<UGenericClassObjectPool>(Pool)->PreloadObjects(Count, Forward<Args>(InitialParams)...);
        }
        else if (TBaseStructure<T>::Get() != nullptr)
        {
            Cast<UGenericStructObjectPool>(Pool)->PreloadObjects(Count, Forward<Args>(InitialParams)...);
        }
    }
}

template <typename T>
void UObjectPoolManager::SetInitializeCallback(TFunction<void(T*)> Callback)
{
    FPoolKey PoolKey;
    if ( UObject* Pool = GetOrCreatePool<T>(PoolKey))
    {
        if constexpr (TIsDerivedFrom<T, UObject>::Value)
        {
            Cast<UGenericClassObjectPool>(Pool)->SetInitializeCallback(Callback);
        }
    }
}

template <typename T>
void UObjectPoolManager::SetResetCallback(TFunction<void(T*)> Callback)
{
    FPoolKey PoolKey;
    if (UObject* Pool = GetOrCreatePool<T>(PoolKey))
    {
        if constexpr (TIsDerivedFrom<T, UObject>::Value)
        {
            Cast<UGenericClassObjectPool>(Pool)->SetResetCallback(Callback);
        }
    }
}

template <typename T>
UObject* UObjectPoolManager::GetOrCreatePool(FPoolKey& Key)
{
    if constexpr (TIsDerivedFrom<T, UObject>::Value)
    {
        Key.ObjectClass = T::StaticClass();
    }
    else if (TBaseStructure<T>::Get() != nullptr)
    {
        Key.StructClass = T::StaticStruct();
    }
    PoolMutex.Lock();
    if (!Pools.Contains(Key))
    {
        if (Key.ObjectClass)
        {
            UGenericClassObjectPool* Pool = NewObject<UGenericClassObjectPool>(this);
            if (Pool)
            {
                Pool->SetMaxPoolSize(MaxPoolSize);
                Pool->SetAutoCleanupInterval(AutoCleanupInterval);
                Pools.Add(Key, Pool);
            }
        }
        else if (Key.StructClass)
        {
            UGenericStructObjectPool* Pool = NewObject<UGenericStructObjectPool>(this);
            if (Pool)
            {
                Pool->SetMaxPoolSize(MaxPoolSize);
                Pool->SetAutoCleanupInterval(AutoCleanupInterval);
                Pools.Add(Key, Pool);
            }
        }
        
    }
    UObject* Pool = Pools[Key];
    PoolMutex.Unlock();
    return Pool;
}

ObjectPoolManager.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "PooledObject.h"
#include "UObject/Object.h"
#include "GenericClassObjectPool.generated.h"

UCLASS()
class YRP_API UGenericClassObjectPool : public UObject
{
    GENERATED_BODY()

public:
    friend class UObjectPoolManager;
    UGenericClassObjectPool();
    
    template <class T, class ... Args>
    T* GetObject(Args&& ... InitialParams);
    template<typename T, typename... Args>
    T* GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams);
    
    template<typename T>
    void ReturnObject(T* Object);

    template<typename T>
    void ReturnObject(TSubclassOf<T> ObjectClass, T* Object);
    
    void SetMaxPoolSize(int32 MaxSize);
    void SetAutoCleanupInterval(float Interval);

    template<typename T, typename... Args>
    void PreloadObjects(int32 Count, Args&&... InitialParams);

    // 设置初始化回调函数
    template<typename T>
    void SetInitializeCallback(TFunction<void(T*)> Callback);

    // 设置重置回调函数
    template<typename T>
    void SetResetCallback(TFunction<void(T*)> Callback);

protected:
    virtual void BeginDestroy() override;
    TMap<UClass*, TArray<FPooledObject>> PooledObjects;
    FCriticalSection PoolMutex;
    int32 MaxPoolSize;
    float AutoCleanupInterval;
    float PoolAdjustInterval;
    float TimeSinceLastCleanup;
    float TimeSinceLastPoolAdjust;

    // 初始化回调函数映射
    TMap<UClass*, TFunction<void(UObject*)>> InitializeCallbacks;

    // 重置回调函数映射
    TMap<UClass*, TFunction<void(UObject*)>> ResetCallbacks;
    
    void ManagePool();

    void LogPerformanceStats();

    template<typename T, typename... Args>
    void PreloadObjectsInternal(int32 Count, Args&&... InitialParams);
    template <class T, class ... Args>
    T* CreateObject(TSubclassOf<T> ObjectClass, Args&& ... InitialParams);
    template <class T, class ... Args>
    T* CreateObject(Args&& ... InitialParams);
};

template <typename T, typename... Args>
T* UGenericClassObjectPool::GetObject(Args&&... InitialParams)
{
    UClass* ObjectClass = T::StaticClass();
    PoolMutex.Lock();
    if (PooledObjects.Contains(ObjectClass))
    {
        TArray<FPooledObject>& Objects = PooledObjects[ObjectClass];
        for (FPooledObject& PooledObject : Objects)
        {
            if (!PooledObject.bIsInUse)
            {
                PooledObject.bIsInUse = true;
                PooledObject.LastUseTime = FDateTime::UtcNow();
                T* Object = Cast<T>(PooledObject.Object);
                if (InitializeCallbacks.Contains(ObjectClass))
                {
                    InitializeCallbacks[ObjectClass](Object);
                }
                else if (ObjectClass->IsChildOf(AActor::StaticClass()))
                {
                    // 默认初始化回调函数
                    AActor* Actor = Cast<AActor>(Object);
                    Actor->SetActorHiddenInGame(false);
                    Actor->SetActorEnableCollision(true);
                    Actor->SetActorTickEnabled(true);
                    Actor->SetActorLocation(FVector::ZeroVector);
                    Actor->SetActorRotation(FRotator::ZeroRotator);
                }
                PoolMutex.Unlock();
                return Object;
            }
        }
    }

    {
        T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...);
        const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() };
        if (!PooledObjects.Contains(ObjectClass))
        {
            PooledObjects.Add(ObjectClass, TArray<FPooledObject>());
        }
        if(PooledObjects[ObjectClass].Num() < MaxPoolSize)
        {
            PooledObjects[ObjectClass].Add(PooledObject);
        }
        else
        {
            PoolMutex.Unlock();
            return nullptr;
        }
        if (InitializeCallbacks.Contains(ObjectClass))
        {
            InitializeCallbacks[ObjectClass](NewObject);
        }
        else if (ObjectClass->IsChildOf(AActor::StaticClass()))
        {
            // 默认初始化回调函数
            AActor* Actor = Cast<AActor>(NewObject);
            Actor->SetActorHiddenInGame(false);
            Actor->SetActorEnableCollision(true);
            Actor->SetActorTickEnabled(true);
            Actor->SetActorLocation(FVector::ZeroVector);
            Actor->SetActorRotation(FRotator::ZeroRotator);
        }
        PoolMutex.Unlock();
        return NewObject;
    }
}

template <typename T, typename ... Args>
T* UGenericClassObjectPool::GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams)
{
    UClass* Class = ObjectClass.Get();
    PoolMutex.Lock();
    if (PooledObjects.Contains(Class))
    {
        TArray<FPooledObject>& Objects = PooledObjects[Class];
        for (FPooledObject& PooledObject : Objects)
        {
            if (!PooledObject.bIsInUse)
            {
                PooledObject.bIsInUse = true;
                PooledObject.LastUseTime = FDateTime::UtcNow();
                T* Object = Cast<T>(PooledObject.Object);
                if (InitializeCallbacks.Contains(Class))
                {
                    InitializeCallbacks[Class](Object);
                }
                else if (Class->IsChildOf(AActor::StaticClass()))
                {
                    // 默认初始化回调函数
                    AActor* Actor = Cast<AActor>(Object);
                    Actor->SetActorHiddenInGame(false);
                    Actor->SetActorEnableCollision(true);
                    Actor->SetActorTickEnabled(true);
                    Actor->SetActorLocation(FVector::ZeroVector);
                    Actor->SetActorRotation(FRotator::ZeroRotator);
                }
                PoolMutex.Unlock();
                return Object;
            }
        }
    }

    {
        T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...);
        const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() };
        if (!PooledObjects.Contains(Class))
        {
            PooledObjects.Add(Class, TArray<FPooledObject>());
        }
        if(PooledObjects[Class].Num() < MaxPoolSize)
        {
            PooledObjects[Class].Add(PooledObject);
        }
        else
        {
            PoolMutex.Unlock();
            return nullptr;
        }
        if (InitializeCallbacks.Contains(Class))
        {
            InitializeCallbacks[Class](NewObject);
        }
        else if (Class->IsChildOf(AActor::StaticClass()))
        {
            // 默认初始化回调函数
            AActor* Actor = Cast<AActor>(NewObject);
            Actor->SetActorHiddenInGame(false);
            Actor->SetActorEnableCollision(true);
            Actor->SetActorTickEnabled(true);
            Actor->SetActorLocation(FVector::ZeroVector);
            Actor->SetActorRotation(FRotator::ZeroRotator);
        }
        PoolMutex.Unlock();
        return NewObject;
    }
}

template <typename T>
void UGenericClassObjectPool::ReturnObject(T* Object)
{
    if (Object)
    {
        const UClass* ObjectClass = T::StaticClass();
        PoolMutex.Lock();
        if (PooledObjects.Contains(ObjectClass))
        {
            TArray<FPooledObject>& Objects = PooledObjects[ObjectClass];
            for (FPooledObject& PooledObject : Objects)
            {
                if (PooledObject.Object == Object)
                {
                    PooledObject.bIsInUse = false;
                    PooledObject.LastUseTime = FDateTime::UtcNow();
                    if (ResetCallbacks.Contains(ObjectClass))
                    {
                        ResetCallbacks[ObjectClass](Object);
                    }
                    else if (ObjectClass->IsChildOf(AActor::StaticClass()))
                    {
                        // 默认重置回调函数
                        AActor* Actor = Cast<AActor>(Object);
                        Actor->SetActorHiddenInGame(true);
                        Actor->SetActorEnableCollision(false);
                        Actor->SetActorTickEnabled(false);
                        Actor->SetActorLocation(FVector::ZeroVector);
                        Actor->SetActorRotation(FRotator::ZeroRotator);
                    }
                    PoolMutex.Unlock();
                    return;
                }
            }
        }
        PoolMutex.Unlock();
    }
}

template <typename T>
void UGenericClassObjectPool::ReturnObject(TSubclassOf<T> ObjectClass, T* Object)
{
    if (Object)
    {
        UClass* tObject = ObjectClass.Get();
        PoolMutex.Lock();
        if (PooledObjects.Contains(tObject))
        {
            TArray<FPooledObject>& Objects = PooledObjects[tObject];
            for (FPooledObject& PooledObject : Objects)
            {
                if (PooledObject.Object == Object)
                {
                    PooledObject.bIsInUse = false;
                    PooledObject.LastUseTime = FDateTime::UtcNow();
                    if (ResetCallbacks.Contains(tObject))
                    {
                        ResetCallbacks[tObject](Object);
                    }
                    else if (tObject->IsChildOf(AActor::StaticClass()))
                    {
                        // 默认重置回调函数
                        AActor* Actor = Cast<AActor>(Object);
                        Actor->SetActorHiddenInGame(true);
                        Actor->SetActorEnableCollision(false);
                        Actor->SetActorTickEnabled(false);
                        Actor->SetActorLocation(FVector::ZeroVector);
                        Actor->SetActorRotation(FRotator::ZeroRotator);
                    }
                    PoolMutex.Unlock();
                    return;
                }
            }
        }
        PoolMutex.Unlock();
    }
}

template <typename T, typename... Args>
void UGenericClassObjectPool::PreloadObjects(int32 Count, Args&&... InitialParams)
{
    PreloadObjectsInternal<T>(Count, Forward<Args>(InitialParams)...);
}

template <typename T>
void UGenericClassObjectPool::SetInitializeCallback(TFunction<void(T*)> Callback)
{
    UClass* ObjectClass = T::StaticClass();
    InitializeCallbacks.Add(ObjectClass, [Callback](UObject* Object)
    {
        Callback(Cast<T>(Object));
    });
}

template <typename T>
void UGenericClassObjectPool::SetResetCallback(TFunction<void(T*)> Callback)
{
    UClass* ObjectClass = T::StaticClass();
    ResetCallbacks.Add(ObjectClass, [Callback](UObject* Object)
    {
        Callback(Cast<T>(Object));
    });
}

template <typename T, typename... Args>
void UGenericClassObjectPool::PreloadObjectsInternal(int32 Count, Args&&... InitialParams)
{
    UClass* ObjectClass = T::StaticClass();
    PoolMutex.Lock();
    if (!PooledObjects.Contains(ObjectClass))
    {
        PooledObjects.Add(ObjectClass, TArray<FPooledObject>());
    }
    TArray<FPooledObject>& Objects = PooledObjects[ObjectClass];
    for (int32 i = 0; i < Count; ++i)
    {
        T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...);
        FPooledObject PooledObject = { NewObject, nullptr, false, FDateTime::UtcNow() };
        Objects.Add(PooledObject);
    }
    PoolMutex.Unlock();
}

template <typename T, typename... Args>
T* UGenericClassObjectPool::CreateObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams)
{
    UClass* Class = ObjectClass.Get();
    if (Class->IsChildOf(AActor::StaticClass()))
    {
        UWorld* World = GetWorld();
        if (World)
        {
            return World->SpawnActor<T>(ObjectClass, Forward<Args>(InitialParams)...);
        }
    }
    else
    {
        return NewObject<T>(GetOuter(), ObjectClass, Forward<Args>(InitialParams)...);
    }
    return nullptr;
}
template <typename T, typename... Args>
T* UGenericClassObjectPool::CreateObject(Args&&... InitialParams)
{
    UClass* Class = T::StaticClass();
    if (Class->IsChildOf(AActor::StaticClass()))
    {
        UWorld* World = GetWorld();
        if (World)
        {
            return World->SpawnActor<T>(Forward<Args>(InitialParams)...);
        }
    }
    else
    {
        T* NewObj = NewObject<T>(GetOuter(), Forward<Args>(InitialParams)...);
        return NewObj;
    }
   return nullptr;
}

 

GenericClassObjectPool.h泛型类对象池

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "PooledObject.h"
#include "UObject/Object.h"
#include "GenericClassObjectPool.generated.h"

UCLASS()
class YRP_API UGenericClassObjectPool : public UObject
{
    GENERATED_BODY()

public:
    friend class UObjectPoolManager;
    UGenericClassObjectPool();
    
    template <class T, class ... Args>
    T* GetObject(Args&& ... InitialParams);
    template<typename T, typename... Args>
    T* GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams);
    
    template<typename T>
    void ReturnObject(T* Object);

    template<typename T>
    void ReturnObject(TSubclassOf<T> ObjectClass, T* Object);
    
    void SetMaxPoolSize(int32 MaxSize);
    void SetAutoCleanupInterval(float Interval);

    template<typename T, typename... Args>
    void PreloadObjects(int32 Count, Args&&... InitialParams);

    // 设置初始化回调函数
    template<typename T>
    void SetInitializeCallback(TFunction<void(T*)> Callback);

    // 设置重置回调函数
    template<typename T>
    void SetResetCallback(TFunction<void(T*)> Callback);

protected:
    virtual void BeginDestroy() override;
    TMap<UClass*, TArray<FPooledObject>> PooledObjects;
    FCriticalSection PoolMutex;
    int32 MaxPoolSize;
    float AutoCleanupInterval;
    float PoolAdjustInterval;
    float TimeSinceLastCleanup;
    float TimeSinceLastPoolAdjust;

    // 初始化回调函数映射
    TMap<UClass*, TFunction<void(UObject*)>> InitializeCallbacks;

    // 重置回调函数映射
    TMap<UClass*, TFunction<void(UObject*)>> ResetCallbacks;
    
    void ManagePool();

    void LogPerformanceStats();

    template<typename T, typename... Args>
    void PreloadObjectsInternal(int32 Count, Args&&... InitialParams);
    template <class T, class ... Args>
    T* CreateObject(TSubclassOf<T> ObjectClass, Args&& ... InitialParams);
    template <class T, class ... Args>
    T* CreateObject(Args&& ... InitialParams);
};

template <typename T, typename... Args>
T* UGenericClassObjectPool::GetObject(Args&&... InitialParams)
{
    UClass* ObjectClass = T::StaticClass();
    PoolMutex.Lock();
    if (PooledObjects.Contains(ObjectClass))
    {
        TArray<FPooledObject>& Objects = PooledObjects[ObjectClass];
        for (FPooledObject& PooledObject : Objects)
        {
            if (!PooledObject.bIsInUse)
            {
                PooledObject.bIsInUse = true;
                PooledObject.LastUseTime = FDateTime::UtcNow();
                T* Object = Cast<T>(PooledObject.Object);
                if (InitializeCallbacks.Contains(ObjectClass))
                {
                    InitializeCallbacks[ObjectClass](Object);
                }
                else if (ObjectClass->IsChildOf(AActor::StaticClass()))
                {
                    // 默认初始化回调函数
                    AActor* Actor = Cast<AActor>(Object);
                    Actor->SetActorHiddenInGame(false);
                    Actor->SetActorEnableCollision(true);
                    Actor->SetActorTickEnabled(true);
                    Actor->SetActorLocation(FVector::ZeroVector);
                    Actor->SetActorRotation(FRotator::ZeroRotator);
                }
                PoolMutex.Unlock();
                return Object;
            }
        }
    }

    {
        T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...);
        const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() };
        if (!PooledObjects.Contains(ObjectClass))
        {
            PooledObjects.Add(ObjectClass, TArray<FPooledObject>());
        }
        if(PooledObjects[ObjectClass].Num() < MaxPoolSize)
        {
            PooledObjects[ObjectClass].Add(PooledObject);
        }
        else
        {
            PoolMutex.Unlock();
            return nullptr;
        }
        if (InitializeCallbacks.Contains(ObjectClass))
        {
            InitializeCallbacks[ObjectClass](NewObject);
        }
        else if (ObjectClass->IsChildOf(AActor::StaticClass()))
        {
            // 默认初始化回调函数
            AActor* Actor = Cast<AActor>(NewObject);
            Actor->SetActorHiddenInGame(false);
            Actor->SetActorEnableCollision(true);
            Actor->SetActorTickEnabled(true);
            Actor->SetActorLocation(FVector::ZeroVector);
            Actor->SetActorRotation(FRotator::ZeroRotator);
        }
        PoolMutex.Unlock();
        return NewObject;
    }
}

template <typename T, typename ... Args>
T* UGenericClassObjectPool::GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams)
{
    UClass* Class = ObjectClass.Get();
    PoolMutex.Lock();
    if (PooledObjects.Contains(Class))
    {
        TArray<FPooledObject>& Objects = PooledObjects[Class];
        for (FPooledObject& PooledObject : Objects)
        {
            if (!PooledObject.bIsInUse)
            {
                PooledObject.bIsInUse = true;
                PooledObject.LastUseTime = FDateTime::UtcNow();
                T* Object = Cast<T>(PooledObject.Object);
                if (InitializeCallbacks.Contains(Class))
                {
                    InitializeCallbacks[Class](Object);
                }
                else if (Class->IsChildOf(AActor::StaticClass()))
                {
                    // 默认初始化回调函数
                    AActor* Actor = Cast<AActor>(Object);
                    Actor->SetActorHiddenInGame(false);
                    Actor->SetActorEnableCollision(true);
                    Actor->SetActorTickEnabled(true);
                    Actor->SetActorLocation(FVector::ZeroVector);
                    Actor->SetActorRotation(FRotator::ZeroRotator);
                }
                PoolMutex.Unlock();
                return Object;
            }
        }
    }

    {
        T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...);
        const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() };
        if (!PooledObjects.Contains(Class))
        {
            PooledObjects.Add(Class, TArray<FPooledObject>());
        }
        if(PooledObjects[Class].Num() < MaxPoolSize)
        {
            PooledObjects[Class].Add(PooledObject);
        }
        else
        {
            PoolMutex.Unlock();
            return nullptr;
        }
        if (InitializeCallbacks.Contains(Class))
        {
            InitializeCallbacks[Class](NewObject);
        }
        else if (Class->IsChildOf(AActor::StaticClass()))
        {
            // 默认初始化回调函数
            AActor* Actor = Cast<AActor>(NewObject);
            Actor->SetActorHiddenInGame(false);
            Actor->SetActorEnableCollision(true);
            Actor->SetActorTickEnabled(true);
            Actor->SetActorLocation(FVector::ZeroVector);
            Actor->SetActorRotation(FRotator::ZeroRotator);
        }
        PoolMutex.Unlock();
        return NewObject;
    }
}

template <typename T>
void UGenericClassObjectPool::ReturnObject(T* Object)
{
    if (Object)
    {
        const UClass* ObjectClass = T::StaticClass();
        PoolMutex.Lock();
        if (PooledObjects.Contains(ObjectClass))
        {
            TArray<FPooledObject>& Objects = PooledObjects[ObjectClass];
            for (FPooledObject& PooledObject : Objects)
            {
                if (PooledObject.Object == Object)
                {
                    PooledObject.bIsInUse = false;
                    PooledObject.LastUseTime = FDateTime::UtcNow();
                    if (ResetCallbacks.Contains(ObjectClass))
                    {
                        ResetCallbacks[ObjectClass](Object);
                    }
                    else if (ObjectClass->IsChildOf(AActor::StaticClass()))
                    {
                        // 默认重置回调函数
                        AActor* Actor = Cast<AActor>(Object);
                        Actor->SetActorHiddenInGame(true);
                        Actor->SetActorEnableCollision(false);
                        Actor->SetActorTickEnabled(false);
                        Actor->SetActorLocation(FVector::ZeroVector);
                        Actor->SetActorRotation(FRotator::ZeroRotator);
                    }
                    PoolMutex.Unlock();
                    return;
                }
            }
        }
        PoolMutex.Unlock();
    }
}

template <typename T>
void UGenericClassObjectPool::ReturnObject(TSubclassOf<T> ObjectClass, T* Object)
{
    if (Object)
    {
        UClass* tObject = ObjectClass.Get();
        PoolMutex.Lock();
        if (PooledObjects.Contains(tObject))
        {
            TArray<FPooledObject>& Objects = PooledObjects[tObject];
            for (FPooledObject& PooledObject : Objects)
            {
                if (PooledObject.Object == Object)
                {
                    PooledObject.bIsInUse = false;
                    PooledObject.LastUseTime = FDateTime::UtcNow();
                    if (ResetCallbacks.Contains(tObject))
                    {
                        ResetCallbacks[tObject](Object);
                    }
                    else if (tObject->IsChildOf(AActor::StaticClass()))
                    {
                        // 默认重置回调函数
                        AActor* Actor = Cast<AActor>(Object);
                        Actor->SetActorHiddenInGame(true);
                        Actor->SetActorEnableCollision(false);
                        Actor->SetActorTickEnabled(false);
                        Actor->SetActorLocation(FVector::ZeroVector);
                        Actor->SetActorRotation(FRotator::ZeroRotator);
                    }
                    PoolMutex.Unlock();
                    return;
                }
            }
        }
        PoolMutex.Unlock();
    }
}

template <typename T, typename... Args>
void UGenericClassObjectPool::PreloadObjects(int32 Count, Args&&... InitialParams)
{
    PreloadObjectsInternal<T>(Count, Forward<Args>(InitialParams)...);
}

template <typename T>
void UGenericClassObjectPool::SetInitializeCallback(TFunction<void(T*)> Callback)
{
    UClass* ObjectClass = T::StaticClass();
    InitializeCallbacks.Add(ObjectClass, [Callback](UObject* Object)
    {
        Callback(Cast<T>(Object));
    });
}

template <typename T>
void UGenericClassObjectPool::SetResetCallback(TFunction<void(T*)> Callback)
{
    UClass* ObjectClass = T::StaticClass();
    ResetCallbacks.Add(ObjectClass, [Callback](UObject* Object)
    {
        Callback(Cast<T>(Object));
    });
}

template <typename T, typename... Args>
void UGenericClassObjectPool::PreloadObjectsInternal(int32 Count, Args&&... InitialParams)
{
    UClass* ObjectClass = T::StaticClass();
    PoolMutex.Lock();
    if (!PooledObjects.Contains(ObjectClass))
    {
        PooledObjects.Add(ObjectClass, TArray<FPooledObject>());
    }
    TArray<FPooledObject>& Objects = PooledObjects[ObjectClass];
    for (int32 i = 0; i < Count; ++i)
    {
        T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...);
        FPooledObject PooledObject = { NewObject, nullptr, false, FDateTime::UtcNow() };
        Objects.Add(PooledObject);
    }
    PoolMutex.Unlock();
}

template <typename T, typename... Args>
T* UGenericClassObjectPool::CreateObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams)
{
    UClass* Class = ObjectClass.Get();
    if (Class->IsChildOf(AActor::StaticClass()))
    {
        UWorld* World = GetWorld();
        if (World)
        {
            return World->SpawnActor<T>(ObjectClass, Forward<Args>(InitialParams)...);
        }
    }
    else
    {
        return NewObject<T>(GetOuter(), ObjectClass, Forward<Args>(InitialParams)...);
    }
    return nullptr;
}
template <typename T, typename... Args>
T* UGenericClassObjectPool::CreateObject(Args&&... InitialParams)
{
    UClass* Class = T::StaticClass();
    if (Class->IsChildOf(AActor::StaticClass()))
    {
        UWorld* World = GetWorld();
        if (World)
        {
            return World->SpawnActor<T>(Forward<Args>(InitialParams)...);
        }
    }
    else
    {
        T* NewObj = NewObject<T>(GetOuter(), Forward<Args>(InitialParams)...);
        return NewObj;
    }
   return nullptr;
}

GenericClassObjectPool.cpp

#include "GenericClassObjectPool.h"

UGenericClassObjectPool::UGenericClassObjectPool()
{
    MaxPoolSize = 100;
    AutoCleanupInterval = 60.0f; // 每60秒清理一次
    PoolAdjustInterval = 5.0f; // 每5秒调整一次池大小
    TimeSinceLastCleanup = 0.0f;
}

void UGenericClassObjectPool::BeginDestroy()
{
    Super::BeginDestroy();
    for (auto& Entry : PooledObjects)
    {
        for (FPooledObject& PooledObject : Entry.Value)
        {
            if(PooledObject.Object)
            {
                if (AActor* actor= Cast<AActor>(PooledObject.Object) )
                {
                    actor->Destroy();
                }else if(UActorComponent* actorComponent= Cast<UActorComponent>(PooledObject.Object))
                {
                    actorComponent->DestroyComponent();
                }
                else
                {
                    PooledObject.Object->ConditionalBeginDestroy();
                }
            }
        }
    }
    PooledObjects.Empty();
}

void UGenericClassObjectPool::SetMaxPoolSize(int32 MaxSize)
{
    MaxPoolSize = MaxSize;
}

void UGenericClassObjectPool::SetAutoCleanupInterval(float Interval)
{
    AutoCleanupInterval = Interval;
}

void UGenericClassObjectPool::ManagePool()
{
    PoolMutex.Lock();
    for (auto& Entry : PooledObjects)
    {
        UClass* ObjectClass = Entry.Key;
        TArray<FPooledObject>& Objects = Entry.Value;
        int32 InUseCount = 0;
        for (int32 i = Objects.Num() - 1; i >= 0; --i)
        {
            if (Objects[i].bIsInUse)
            {
                InUseCount++;
            }
            else if ((FDateTime::UtcNow() - Objects[i].LastUseTime).GetTotalSeconds() > AutoCleanupInterval)
            {
                Objects[i].Object->ConditionalBeginDestroy();
                Objects.RemoveAt(i);
            }
        }

        int32 TargetSize = FMath::Clamp(InUseCount * 2, 10, MaxPoolSize);
        if (Objects.Num() > TargetSize)
        {
            // 释放多余的对象
            for (int32 i = Objects.Num() - 1; i >= TargetSize; --i)
            {
                if (!Objects[i].bIsInUse)
                {
                    Objects[i].Object->ConditionalBeginDestroy();
                    Objects.RemoveAt(i);
                }
            }
        }
    }
    PoolMutex.Unlock();
}

void UGenericClassObjectPool::LogPerformanceStats()
{
    // 记录性能统计数据
    for (auto& Entry : PooledObjects)
    {
        TSubclassOf<UObject> ObjectClass = Entry.Key;
        TArray<FPooledObject>& Objects = Entry.Value;
        int32 InUseCount = 0;
        for (const FPooledObject& PooledObject : Objects)
        {
            if (PooledObject.bIsInUse)
            {
                InUseCount++;
            }
        }
        UE_LOG(LogTemp, Display, TEXT("ObjectPool: Class %s, Total: %d, InUse: %d"), *ObjectClass->GetName(), Objects.Num(), InUseCount);
    }
}

GenericStructObjectPool.h泛型结构体对象池

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "PooledObject.h"
#include "UObject/Object.h"
#include "GenericStructObjectPool.generated.h"


UCLASS()
class YRP_API UGenericStructObjectPool : public UObject
{
    GENERATED_BODY()

public:
    friend class UObjectPoolManager;
    UGenericStructObjectPool();

    template<typename T, typename... Args>
    T* GetObject(Args&&... InitialParams);
    
    template<typename T>
    void ReturnObject(T* Object);

    void SetMaxPoolSize(int32 MaxSize);
    void SetAutoCleanupInterval(float Interval);

    template<typename T, typename... Args>
    void PreloadObjects(int32 Count, Args&&... InitialParams);

protected:
    virtual void BeginDestroy() override;

private:
    TMap<UScriptStruct*, TArray<FPooledObject>> PooledStructs;
    FCriticalSection PoolMutex;
    int32 MaxPoolSize;
    float AutoCleanupInterval;
    float PoolAdjustInterval;
    float TimeSinceLastCleanup;
    float TimeSinceLastPoolAdjust;
    
    template<typename T, typename... Args>
    T* CreateObject(Args&&... InitialParams);

    void ManagePool();

    void LogPerformanceStats();

    template<typename T, typename... Args>
    void PreloadObjectsInternal(int32 Count, Args&&... InitialParams);
};

template <typename T, typename... Args>
T* UGenericStructObjectPool::GetObject(Args&&... InitialParams)
{
    UScriptStruct* StructClass = TBaseStructure<T>::Get();
    PoolMutex.Lock();
    if (PooledStructs.Contains(StructClass))
    {
        TArray<FPooledObject>& Objects = PooledStructs[StructClass];
        for (FPooledObject& PooledObject : Objects)
        {
            if (!PooledObject.bIsInUse)
            {
                PooledObject.bIsInUse = true;
                PooledObject.LastUseTime = FDateTime::UtcNow();
                T* Object = (T*)PooledObject.StructData.Get();
                *Object = T(Forward<Args>(InitialParams)...); // 使用初始参数
                PoolMutex.Unlock();
                return Object;
            }
        }
    }
    {
        T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...);
        const FPooledObject PooledObject = { nullptr, TSharedPtr<void>(NewObject), true, FDateTime::UtcNow() };
        if(!PooledStructs.Contains(StructClass))
        {
            PooledStructs.Add(StructClass, TArray<FPooledObject>());
        }
        if (PooledStructs[StructClass].Num() < MaxPoolSize)
        {
            PooledStructs[StructClass].Add(PooledObject);
        }
        else
        {
            PoolMutex.Unlock();return nullptr;
        }
        PoolMutex.Unlock();return  NewObject;
    }
}

template <typename T>
void UGenericStructObjectPool::ReturnObject(T* Object)
{
    if (Object)
    {
        const UScriptStruct* StructClass = TBaseStructure<T>::Get();
        PoolMutex.Lock();
        if (PooledStructs.Contains(StructClass))
        {
            TArray<FPooledObject>& Objects = PooledStructs[StructClass];
            for (FPooledObject& PooledObject : Objects)
            {
                if (PooledObject.StructData.Get() == Object)
                {
                    PooledObject.bIsInUse = false;
                    PooledObject.LastUseTime = FDateTime::UtcNow();
                    PoolMutex.Unlock();
                    return;
                }
            }
        }
        PoolMutex.Unlock();
    }
}

template <typename T, typename... Args>
void UGenericStructObjectPool::PreloadObjects(int32 Count, Args&&... InitialParams)
{
    PreloadObjectsInternal<T>(Count, Forward<Args>(InitialParams)...);
}

template <typename T, typename... Args>
T* UGenericStructObjectPool::CreateObject(Args&&... InitialParams)
{
    T* NewObject = (T*)FMemory::Malloc(sizeof(T));
    new (NewObject) T(Forward<Args>(InitialParams)...);
    return NewObject;
}



template <typename T, typename... Args>
void UGenericStructObjectPool::PreloadObjectsInternal(int32 Count, Args&&... InitialParams)
{
    UScriptStruct* StructClass = TBaseStructure<T>::Get();
    PoolMutex.Lock();
    if (!PooledStructs.Contains(StructClass))
    {
        PooledStructs.Add(StructClass, TArray<FPooledObject>());
    }
    TArray<FPooledObject>& Objects = PooledStructs[StructClass];
    for (int32 i = 0; i < Count; ++i)
    {
        T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...);
        FPooledObject PooledObject = { nullptr, TSharedPtr<void>(NewObject), false, FDateTime::UtcNow() };
        Objects.Add(PooledObject);
    }
    PoolMutex.Unlock();
}

GenericStructObjectPool.cpp

#include "GenericStructObjectPool.h"

UGenericStructObjectPool::UGenericStructObjectPool()
{
    MaxPoolSize = 100;
    AutoCleanupInterval = 60.0f; // 每60秒清理一次
    PoolAdjustInterval = 5.0f; // 每5秒调整一次池大小
    TimeSinceLastCleanup = 0.0f;
}

void UGenericStructObjectPool::BeginDestroy()
{
    Super::BeginDestroy();
    PooledStructs.Empty();
}

void UGenericStructObjectPool::SetMaxPoolSize(int32 MaxSize)
{
    MaxPoolSize = MaxSize;
}

void UGenericStructObjectPool::SetAutoCleanupInterval(float Interval)
{
    AutoCleanupInterval = Interval;
}

void UGenericStructObjectPool::ManagePool()
{
    PoolMutex.Lock();
    for (auto& Entry : PooledStructs)
    {
        UScriptStruct* StructClass = Entry.Key;
        TArray<FPooledObject>& Objects = Entry.Value;
        int32 InUseCount = 0;
        for (int32 i = Objects.Num() - 1; i >= 0; --i)
        {
            if (Objects[i].bIsInUse)
            {
                InUseCount++;
            }
            else if ((FDateTime::UtcNow() - Objects[i].LastUseTime).GetTotalSeconds() > AutoCleanupInterval)
            {
                FMemory::Free(Objects[i].StructData.Get());
                Objects.RemoveAt(i);
            }
        }

        int32 TargetSize = FMath::Clamp(InUseCount * 2, 10, MaxPoolSize);
        if (Objects.Num() > TargetSize)
        {
            // 释放多余的对象
            for (int32 i = Objects.Num() - 1; i >= TargetSize; --i)
            {
                if (!Objects[i].bIsInUse)
                {
                    FMemory::Free(Objects[i].StructData.Get());
                    Objects.RemoveAt(i);
                }
            }
        }
    }
    PoolMutex.Unlock();
}

void UGenericStructObjectPool::LogPerformanceStats()
{
    // 记录性能统计数据
    for (auto& Entry : PooledStructs)
    {
        UScriptStruct* StructClass = Entry.Key;
        TArray<FPooledObject>& Objects = Entry.Value;
        int32 InUseCount = 0;
        for (const FPooledObject& PooledObject : Objects)
        {
            if (PooledObject.bIsInUse)
            {
                InUseCount++;
            }
        }
        UE_LOG(LogTemp, Display, TEXT("ObjectPool: Struct %s, Total: %d, InUse: %d"), *StructClass->GetName(), Objects.Num(), InUseCount);
    }
}

 

标签:PooledObject,对象,void,Object,Actor,ObjectClass,template,UE
From: https://www.cnblogs.com/zjr0/p/18338364

相关文章

  • 基于SpringBoot+Vue+uniapp的图书管理系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的多角色学生管理系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的健身房管理系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的菜匣子优选系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • UE5-自定义插件使用第三方库
    制作插件使用到了第三方库,后面很长时间没有用这个插件,导致插件启用不了,吃亏了,所以记录下制作过程。第一步:在继承ModuleRules的C#脚本里添加代码:privatestringModulePath { get { returnModuleDirectory; } } privatestringThirdPartyPath { get{re......
  • vue项目播放本地音频和数据库音频
    前期准备:vue项目,安装好了axios和mock,如果没有可以看我的博客全新vue项目使用mock实现效果:点击按钮之后,可以播放音频,本地音频是放在vue项目里的,数据库音频是需要调用后端请求获得音频的(这里是获取mock中的base64音频数据)vue项目vue-audio目录结果如下,其中我在public/static中放了......
  • 全新vue项目使用mock
    首先这里不介绍mockjs有多少优点,只是记录一个全新的vue项目如何安装并使用mock。安装vue项目(不想安装新项目,可直接跳过,看安装mockjs内容)在命令行输入安装命令vuecreatevue-mock    vue3或者vue2都可以,默认enter键一直就装好了安装mockjs使用vsCode打开刚才的项目......
  • vue的watch场景
    这里主要列举一下,监听的是对象的各种情况data(){return{test:{id:'id1',name:'name1'}};},情况一:监听对象watch:{test:{handler(value){console.log('test-value',value);},deep:false}}情况......
  • vue的computed场景
    这里主要列举一下,计算属性内是对象的各种情况data(){return{test:{id:'id1',name:'name1'}};},情况一:返回对象computed:{testValue(){returnthis.test;}}情况二:返回对象的属性computed:{testValue(){returnthis.t......
  • vue生成初始化名字相近的变量并放到数组中
    项目上有一个需求,页面上有50、60个数据变量,是依次排序递增的变量,中间有个别变量用不到,不想把这些变量直接定义在data(){}内。直接上代码1.在mounted(){},大括号内定义并初始化变量1this.yx_1hddj_arr=[];2this.yx_2hddj_arr=[];3this.yx_3hddj_arr......