2026-03-26 10:49:41 +08:00
|
|
|
using System;
|
2026-04-17 21:01:20 +08:00
|
|
|
using System.Collections.Generic;
|
2026-03-26 10:49:41 +08:00
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
namespace AlicizaX
|
|
|
|
|
{
|
|
|
|
|
public enum PoolResourceLoaderType
|
|
|
|
|
{
|
|
|
|
|
AssetBundle = 0,
|
|
|
|
|
Resources = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum PoolMatchMode
|
|
|
|
|
{
|
|
|
|
|
Exact = 0,
|
|
|
|
|
Prefix = 1
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
public enum PoolOverflowPolicy
|
|
|
|
|
{
|
|
|
|
|
FailFast = 0,
|
|
|
|
|
InstantiateOneShot = 1,
|
|
|
|
|
AutoExpand = 2,
|
|
|
|
|
RecycleOldestInactive = 3,
|
|
|
|
|
DropNewestRequest = 4
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum PoolTrimPolicy
|
|
|
|
|
{
|
|
|
|
|
None = 0,
|
|
|
|
|
IdleOnly = 1,
|
|
|
|
|
IdleAndPriority = 2,
|
|
|
|
|
AggressiveOnLowMemory = 3
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum PoolActivationMode
|
|
|
|
|
{
|
|
|
|
|
SetActive = 0,
|
|
|
|
|
SleepWake = 1,
|
|
|
|
|
Custom = 2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum PoolResetMode
|
|
|
|
|
{
|
|
|
|
|
TransformOnly = 0,
|
|
|
|
|
PoolableCallbacks = 1,
|
|
|
|
|
FullReset = 2,
|
|
|
|
|
Custom = 3
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 10:49:41 +08:00
|
|
|
[Serializable]
|
2026-04-17 21:01:20 +08:00
|
|
|
public sealed class PoolEntry
|
2026-03-26 10:49:41 +08:00
|
|
|
{
|
|
|
|
|
public const string DefaultGroup = "Default";
|
2026-04-17 21:01:20 +08:00
|
|
|
public const string DefaultEntryName = "DefaultPool";
|
2026-03-26 10:49:41 +08:00
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
public string entryName = DefaultEntryName;
|
2026-03-26 10:49:41 +08:00
|
|
|
public string group = DefaultGroup;
|
|
|
|
|
public string assetPath;
|
|
|
|
|
public PoolMatchMode matchMode = PoolMatchMode.Exact;
|
2026-04-17 21:01:20 +08:00
|
|
|
public PoolResourceLoaderType loaderType = PoolResourceLoaderType.AssetBundle;
|
|
|
|
|
public PoolOverflowPolicy overflowPolicy = PoolOverflowPolicy.FailFast;
|
|
|
|
|
public PoolTrimPolicy trimPolicy = PoolTrimPolicy.IdleOnly;
|
|
|
|
|
public PoolActivationMode activationMode = PoolActivationMode.SetActive;
|
|
|
|
|
public PoolResetMode resetMode = PoolResetMode.PoolableCallbacks;
|
|
|
|
|
|
|
|
|
|
[Min(0)]
|
|
|
|
|
public int minRetained = 0;
|
|
|
|
|
|
|
|
|
|
[Min(1)]
|
|
|
|
|
public int softCapacity = 8;
|
|
|
|
|
|
|
|
|
|
[Min(1)]
|
|
|
|
|
public int hardCapacity = 8;
|
2026-03-26 10:49:41 +08:00
|
|
|
|
|
|
|
|
[Min(0f)]
|
2026-04-17 21:01:20 +08:00
|
|
|
public float idleTrimDelay = 30f;
|
2026-03-26 10:49:41 +08:00
|
|
|
|
|
|
|
|
[Min(0f)]
|
2026-04-17 21:01:20 +08:00
|
|
|
public float prefabUnloadDelay = 60f;
|
|
|
|
|
|
|
|
|
|
[Min(0f)]
|
|
|
|
|
public float autoRecycleDelay = 0f;
|
2026-03-26 10:49:41 +08:00
|
|
|
|
|
|
|
|
[Min(1)]
|
2026-04-17 21:01:20 +08:00
|
|
|
public int trimBatchPerTick = 2;
|
2026-03-26 10:49:41 +08:00
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
[Min(1)]
|
|
|
|
|
public int warmupBatchPerFrame = 2;
|
|
|
|
|
|
|
|
|
|
[Min(0f)]
|
|
|
|
|
public float warmupFrameBudgetMs = 1f;
|
2026-03-26 10:49:41 +08:00
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
public bool allowRuntimeExpand;
|
|
|
|
|
public bool keepPrefabResident;
|
|
|
|
|
public bool aggressiveTrimOnLowMemory;
|
|
|
|
|
public int priority;
|
2026-03-26 10:49:41 +08:00
|
|
|
|
|
|
|
|
public void Normalize()
|
|
|
|
|
{
|
2026-04-17 21:01:20 +08:00
|
|
|
entryName = string.IsNullOrWhiteSpace(entryName) ? DefaultEntryName : entryName.Trim();
|
2026-03-26 10:49:41 +08:00
|
|
|
group = string.IsNullOrWhiteSpace(group) ? DefaultGroup : group.Trim();
|
|
|
|
|
assetPath = NormalizeAssetPath(assetPath);
|
2026-04-17 21:01:20 +08:00
|
|
|
minRetained = Mathf.Max(0, minRetained);
|
|
|
|
|
softCapacity = Mathf.Max(1, softCapacity);
|
|
|
|
|
hardCapacity = Mathf.Max(softCapacity, hardCapacity);
|
|
|
|
|
minRetained = Mathf.Min(minRetained, hardCapacity);
|
|
|
|
|
idleTrimDelay = Mathf.Max(0f, idleTrimDelay);
|
2026-03-26 10:49:41 +08:00
|
|
|
prefabUnloadDelay = Mathf.Max(0f, prefabUnloadDelay);
|
2026-04-17 21:01:20 +08:00
|
|
|
autoRecycleDelay = Mathf.Max(0f, autoRecycleDelay);
|
|
|
|
|
trimBatchPerTick = Mathf.Max(1, trimBatchPerTick);
|
|
|
|
|
warmupBatchPerFrame = Mathf.Max(1, warmupBatchPerFrame);
|
|
|
|
|
warmupFrameBudgetMs = Mathf.Max(0f, warmupFrameBudgetMs);
|
2026-03-26 10:49:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Matches(string requestedAssetPath, string requestedGroup = null)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(assetPath) || string.IsNullOrWhiteSpace(requestedAssetPath))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(requestedGroup) &&
|
|
|
|
|
!string.Equals(group, requestedGroup, StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return matchMode switch
|
|
|
|
|
{
|
|
|
|
|
PoolMatchMode.Exact => string.Equals(requestedAssetPath, assetPath, StringComparison.Ordinal),
|
|
|
|
|
PoolMatchMode.Prefix => requestedAssetPath.StartsWith(assetPath, StringComparison.Ordinal),
|
|
|
|
|
_ => false
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string BuildResolvedPoolKey(string resolvedAssetPath)
|
|
|
|
|
{
|
2026-04-17 21:01:20 +08:00
|
|
|
string concretePath = NormalizeAssetPath(resolvedAssetPath);
|
|
|
|
|
return $"{group}|{(int)matchMode}|{assetPath}|{(int)loaderType}|{concretePath}|{entryName}";
|
2026-03-26 10:49:41 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
public static int CompareByPriority(PoolEntry left, PoolEntry right)
|
2026-03-26 10:49:41 +08:00
|
|
|
{
|
|
|
|
|
if (ReferenceEquals(left, right))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (left == null)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (right == null)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
int priorityCompare = right.priority.CompareTo(left.priority);
|
|
|
|
|
if (priorityCompare != 0)
|
|
|
|
|
{
|
|
|
|
|
return priorityCompare;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 10:49:41 +08:00
|
|
|
int modeCompare = left.matchMode.CompareTo(right.matchMode);
|
|
|
|
|
if (modeCompare != 0)
|
|
|
|
|
{
|
|
|
|
|
return modeCompare;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
int leftLength = left.assetPath?.Length ?? 0;
|
|
|
|
|
int rightLength = right.assetPath?.Length ?? 0;
|
|
|
|
|
int pathLengthCompare = rightLength.CompareTo(leftLength);
|
2026-03-26 10:49:41 +08:00
|
|
|
if (pathLengthCompare != 0)
|
|
|
|
|
{
|
|
|
|
|
return pathLengthCompare;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string.Compare(left.group, right.group, StringComparison.Ordinal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string NormalizeAssetPath(string value)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value.Trim().Replace('\\', '/');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 21:01:20 +08:00
|
|
|
[Serializable]
|
|
|
|
|
public sealed class ResolvedPoolConfig
|
|
|
|
|
{
|
|
|
|
|
public string entryName;
|
|
|
|
|
public string group;
|
|
|
|
|
public string assetPath;
|
|
|
|
|
public PoolMatchMode matchMode;
|
|
|
|
|
public PoolResourceLoaderType loaderType;
|
|
|
|
|
public PoolOverflowPolicy overflowPolicy;
|
|
|
|
|
public PoolTrimPolicy trimPolicy;
|
|
|
|
|
public PoolActivationMode activationMode;
|
|
|
|
|
public PoolResetMode resetMode;
|
|
|
|
|
public int minRetained;
|
|
|
|
|
public int softCapacity;
|
|
|
|
|
public int hardCapacity;
|
|
|
|
|
public float idleTrimDelay;
|
|
|
|
|
public float prefabUnloadDelay;
|
|
|
|
|
public float autoRecycleDelay;
|
|
|
|
|
public int trimBatchPerTick;
|
|
|
|
|
public int warmupBatchPerFrame;
|
|
|
|
|
public float warmupFrameBudgetMs;
|
|
|
|
|
public bool allowRuntimeExpand;
|
|
|
|
|
public bool keepPrefabResident;
|
|
|
|
|
public bool aggressiveTrimOnLowMemory;
|
|
|
|
|
public int priority;
|
|
|
|
|
|
|
|
|
|
public string BuildResolvedPoolKey(string resolvedAssetPath)
|
|
|
|
|
{
|
|
|
|
|
string concretePath = PoolEntry.NormalizeAssetPath(resolvedAssetPath);
|
|
|
|
|
return $"{group}|{(int)matchMode}|{assetPath}|{(int)loaderType}|{concretePath}|{entryName}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ResolvedPoolConfig From(PoolEntry entry)
|
|
|
|
|
{
|
|
|
|
|
if (entry == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException(nameof(entry));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new ResolvedPoolConfig
|
|
|
|
|
{
|
|
|
|
|
entryName = entry.entryName,
|
|
|
|
|
group = entry.group,
|
|
|
|
|
assetPath = entry.assetPath,
|
|
|
|
|
matchMode = entry.matchMode,
|
|
|
|
|
loaderType = entry.loaderType,
|
|
|
|
|
overflowPolicy = entry.overflowPolicy,
|
|
|
|
|
trimPolicy = entry.trimPolicy,
|
|
|
|
|
activationMode = entry.activationMode,
|
|
|
|
|
resetMode = entry.resetMode,
|
|
|
|
|
minRetained = entry.minRetained,
|
|
|
|
|
softCapacity = entry.softCapacity,
|
|
|
|
|
hardCapacity = entry.hardCapacity,
|
|
|
|
|
idleTrimDelay = entry.idleTrimDelay,
|
|
|
|
|
prefabUnloadDelay = entry.prefabUnloadDelay,
|
|
|
|
|
autoRecycleDelay = entry.autoRecycleDelay,
|
|
|
|
|
trimBatchPerTick = entry.trimBatchPerTick,
|
|
|
|
|
warmupBatchPerFrame = entry.warmupBatchPerFrame,
|
|
|
|
|
warmupFrameBudgetMs = entry.warmupFrameBudgetMs,
|
|
|
|
|
allowRuntimeExpand = entry.allowRuntimeExpand,
|
|
|
|
|
keepPrefabResident = entry.keepPrefabResident,
|
|
|
|
|
aggressiveTrimOnLowMemory = entry.aggressiveTrimOnLowMemory,
|
|
|
|
|
priority = entry.priority
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
public sealed class PoolConfigCatalog
|
|
|
|
|
{
|
|
|
|
|
public readonly List<PoolEntry> entries;
|
|
|
|
|
|
|
|
|
|
public PoolConfigCatalog(List<PoolEntry> entries)
|
|
|
|
|
{
|
|
|
|
|
this.entries = entries ?? throw new ArgumentNullException(nameof(entries));
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-26 10:49:41 +08:00
|
|
|
}
|