Compare commits
4 Commits
9bcf20ad6a
...
5188a9c35f
| Author | SHA1 | Date | |
|---|---|---|---|
| 5188a9c35f | |||
| 61bd3873c5 | |||
| 93957f889b | |||
| 6397cc03b2 |
485
Editor/Localization/LocalizationAiWriteTool.cs
Normal file
485
Editor/Localization/LocalizationAiWriteTool.cs
Normal file
@ -0,0 +1,485 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using AlicizaX.Localization.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Localization.Editor
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class LocalizationAiWriteRequest
|
||||
{
|
||||
public string TableAssetPath;
|
||||
public string SectionName = "AI";
|
||||
public string Key;
|
||||
public bool AllowUpdate = true;
|
||||
public bool AutoCreateSection = true;
|
||||
public bool AutoCreateLanguageAsset = true;
|
||||
public bool FillMissingLanguagesWithEmpty = true;
|
||||
public bool SaveAssets = true;
|
||||
public bool HotReloadWhenPlaying = true;
|
||||
public List<LocalizationAiTranslation> Translations = new();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class LocalizationAiTranslation
|
||||
{
|
||||
public string Language;
|
||||
public string Text;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class LocalizationAiWriteResult
|
||||
{
|
||||
public bool Success;
|
||||
public string TableAssetPath;
|
||||
public string SectionName;
|
||||
public string Key;
|
||||
public string RuntimeKey;
|
||||
public bool CreatedSection;
|
||||
public bool CreatedEntry;
|
||||
public bool HotReloaded;
|
||||
public List<string> UpdatedLanguages = new();
|
||||
public List<string> Warnings = new();
|
||||
public string Message;
|
||||
}
|
||||
|
||||
public static class LocalizationAiWriteTool
|
||||
{
|
||||
private const string DefaultSectionName = "AI";
|
||||
private const string LastSelectedTableKey = "LastSelectedGameLocaizationTable";
|
||||
|
||||
public static LocalizationAiWriteResult Execute(LocalizationAiWriteRequest request)
|
||||
{
|
||||
LocalizationAiWriteResult result = new();
|
||||
if (request == null)
|
||||
{
|
||||
result.Message = "Request is null.";
|
||||
return result;
|
||||
}
|
||||
|
||||
string tablePath = request.TableAssetPath;
|
||||
if (string.IsNullOrWhiteSpace(tablePath))
|
||||
{
|
||||
tablePath = EditorPrefs.GetString(LastSelectedTableKey, string.Empty);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(tablePath))
|
||||
{
|
||||
result.Message = "TableAssetPath is empty.";
|
||||
return result;
|
||||
}
|
||||
|
||||
GameLocaizationTable table = AssetDatabase.LoadAssetAtPath<GameLocaizationTable>(tablePath);
|
||||
if (table == null)
|
||||
{
|
||||
result.Message = $"Can not load GameLocaizationTable from path: {tablePath}";
|
||||
result.TableAssetPath = tablePath;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.TableAssetPath = tablePath;
|
||||
|
||||
string sectionName = request.SectionName;
|
||||
string itemKey = request.Key;
|
||||
ParseAndNormalizeKey(ref sectionName, ref itemKey);
|
||||
|
||||
if (string.IsNullOrEmpty(sectionName))
|
||||
{
|
||||
sectionName = DefaultSectionName;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(itemKey))
|
||||
{
|
||||
result.Message = "Key is empty after normalization.";
|
||||
return result;
|
||||
}
|
||||
|
||||
if (table.TableSheet == null)
|
||||
{
|
||||
table.TableSheet = new List<GameLocaizationTable.TableData>();
|
||||
}
|
||||
|
||||
if (table.Languages == null)
|
||||
{
|
||||
table.Languages = new List<LocalizationLanguage>();
|
||||
}
|
||||
|
||||
int sectionIndex = FindSectionIndex(table, sectionName);
|
||||
if (sectionIndex < 0)
|
||||
{
|
||||
if (!request.AutoCreateSection)
|
||||
{
|
||||
result.Message = $"Section '{sectionName}' does not exist.";
|
||||
return result;
|
||||
}
|
||||
|
||||
GameLocaizationTable.TableData newSection = new(sectionName, GenerateUniqueSectionId(table));
|
||||
table.TableSheet.Add(newSection);
|
||||
sectionIndex = table.TableSheet.Count - 1;
|
||||
result.CreatedSection = true;
|
||||
}
|
||||
|
||||
GameLocaizationTable.TableData section = table.TableSheet[sectionIndex];
|
||||
if (section.SectionSheet == null)
|
||||
{
|
||||
section.SectionSheet = new List<GameLocaizationTable.SheetItem>();
|
||||
}
|
||||
|
||||
int entryIndex = FindEntryIndex(section, itemKey);
|
||||
bool createdEntry = false;
|
||||
if (entryIndex < 0)
|
||||
{
|
||||
GameLocaizationTable.SheetItem newItem = new(itemKey, GenerateUniqueEntryId(table), true);
|
||||
section.SectionSheet.Add(newItem);
|
||||
entryIndex = section.SectionSheet.Count - 1;
|
||||
createdEntry = true;
|
||||
result.CreatedEntry = true;
|
||||
}
|
||||
else if (!request.AllowUpdate)
|
||||
{
|
||||
result.Message = $"Key '{itemKey}' already exists in section '{sectionName}'.";
|
||||
return result;
|
||||
}
|
||||
|
||||
GameLocaizationTable.SheetItem entry = section.SectionSheet[entryIndex];
|
||||
string runtimeKey = BuildRuntimeKey(section.SectionName, entry.Key);
|
||||
|
||||
Dictionary<string, string> translationMap = BuildTranslationMap(request.Translations, result.Warnings);
|
||||
EnsureEntryExistsForAllLanguages(table, section, entry, runtimeKey, translationMap, request, result);
|
||||
|
||||
table.TableSheet[sectionIndex] = section;
|
||||
|
||||
table.InvalidateLanguageLookup();
|
||||
EditorUtility.SetDirty(table);
|
||||
if (request.SaveAssets)
|
||||
{
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
if (request.HotReloadWhenPlaying &&
|
||||
Application.isPlaying &&
|
||||
AppServices.TryGet<ILocalizationService>(out var localizationService))
|
||||
{
|
||||
localizationService.ReloadLocalizationConfig(table);
|
||||
result.HotReloaded = true;
|
||||
}
|
||||
|
||||
result.Success = true;
|
||||
result.SectionName = section.SectionName;
|
||||
result.Key = entry.Key;
|
||||
result.RuntimeKey = runtimeKey;
|
||||
result.Message = createdEntry
|
||||
? $"Added localization entry '{runtimeKey}'."
|
||||
: $"Updated localization entry '{runtimeKey}'.";
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string ExecuteJson(string json)
|
||||
{
|
||||
LocalizationAiWriteRequest request = Utility.Json.ToObject<LocalizationAiWriteRequest>(json);
|
||||
LocalizationAiWriteResult result = Execute(request);
|
||||
return Utility.Json.ToJson(result);
|
||||
}
|
||||
|
||||
private static void EnsureEntryExistsForAllLanguages(
|
||||
GameLocaizationTable table,
|
||||
GameLocaizationTable.TableData section,
|
||||
GameLocaizationTable.SheetItem entry,
|
||||
string runtimeKey,
|
||||
Dictionary<string, string> translationMap,
|
||||
LocalizationAiWriteRequest request,
|
||||
LocalizationAiWriteResult result)
|
||||
{
|
||||
for (int i = 0; i < table.Languages.Count; i++)
|
||||
{
|
||||
LocalizationLanguage language = table.Languages[i];
|
||||
if (language == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UpsertLanguageEntry(
|
||||
language,
|
||||
section.Id,
|
||||
entry.Id,
|
||||
runtimeKey,
|
||||
translationMap.TryGetValue(language.LanguageName, out string text) ? text : string.Empty,
|
||||
translationMap.ContainsKey(language.LanguageName) || request.FillMissingLanguagesWithEmpty);
|
||||
|
||||
EditorUtility.SetDirty(language);
|
||||
result.UpdatedLanguages.Add(language.LanguageName);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> pair in translationMap)
|
||||
{
|
||||
if (HasLanguage(table, pair.Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!request.AutoCreateLanguageAsset)
|
||||
{
|
||||
result.Warnings.Add($"Language asset '{pair.Key}' does not exist in table '{table.name}'.");
|
||||
continue;
|
||||
}
|
||||
|
||||
LocalizationLanguage language = CreateLanguageAsset(table, pair.Key);
|
||||
UpsertLanguageEntry(language, section.Id, entry.Id, runtimeKey, pair.Value, true);
|
||||
EditorUtility.SetDirty(language);
|
||||
result.UpdatedLanguages.Add(language.LanguageName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpsertLanguageEntry(
|
||||
LocalizationLanguage language,
|
||||
int sectionId,
|
||||
int entryId,
|
||||
string runtimeKey,
|
||||
string value,
|
||||
bool shouldWrite)
|
||||
{
|
||||
if (language.Strings == null)
|
||||
{
|
||||
language.Strings = new List<LocalizationLanguage.LocalizationString>();
|
||||
}
|
||||
|
||||
int index = FindLanguageStringIndex(language, sectionId, entryId);
|
||||
if (index >= 0)
|
||||
{
|
||||
LocalizationLanguage.LocalizationString item = language.Strings[index];
|
||||
item.Key = runtimeKey;
|
||||
if (shouldWrite)
|
||||
{
|
||||
item.Value = value ?? string.Empty;
|
||||
}
|
||||
|
||||
language.Strings[index] = item;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldWrite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
language.Strings.Add(new LocalizationLanguage.LocalizationString
|
||||
{
|
||||
SectionId = sectionId,
|
||||
EntryId = entryId,
|
||||
Key = runtimeKey,
|
||||
Value = value ?? string.Empty
|
||||
});
|
||||
}
|
||||
|
||||
private static LocalizationLanguage CreateLanguageAsset(GameLocaizationTable table, string languageName)
|
||||
{
|
||||
LocalizationLanguage language = ScriptableObject.CreateInstance<LocalizationLanguage>();
|
||||
language.name = languageName;
|
||||
language.LanguageName = languageName;
|
||||
language.Strings = new List<LocalizationLanguage.LocalizationString>();
|
||||
AssetDatabase.AddObjectToAsset(language, table);
|
||||
table.Languages.Add(language);
|
||||
table.InvalidateLanguageLookup();
|
||||
EditorUtility.SetDirty(table);
|
||||
return language;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> BuildTranslationMap(
|
||||
List<LocalizationAiTranslation> translations,
|
||||
List<string> warnings)
|
||||
{
|
||||
Dictionary<string, string> map = new(StringComparer.Ordinal);
|
||||
if (translations == null)
|
||||
{
|
||||
return map;
|
||||
}
|
||||
|
||||
for (int i = 0; i < translations.Count; i++)
|
||||
{
|
||||
LocalizationAiTranslation translation = translations[i];
|
||||
if (translation == null || string.IsNullOrWhiteSpace(translation.Language))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string normalizedLanguage = NormalizePart(translation.Language);
|
||||
if (string.IsNullOrEmpty(normalizedLanguage))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (map.ContainsKey(normalizedLanguage))
|
||||
{
|
||||
warnings.Add($"Duplicate language '{normalizedLanguage}' found. Last value wins.");
|
||||
}
|
||||
|
||||
map[normalizedLanguage] = translation.Text ?? string.Empty;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private static bool HasLanguage(GameLocaizationTable table, string languageName)
|
||||
{
|
||||
for (int i = 0; i < table.Languages.Count; i++)
|
||||
{
|
||||
LocalizationLanguage language = table.Languages[i];
|
||||
if (language != null && string.Equals(language.LanguageName, languageName, StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int FindSectionIndex(GameLocaizationTable table, string sectionName)
|
||||
{
|
||||
for (int i = 0; i < table.TableSheet.Count; i++)
|
||||
{
|
||||
if (string.Equals(table.TableSheet[i].SectionName, sectionName, StringComparison.Ordinal))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int FindEntryIndex(GameLocaizationTable.TableData section, string itemKey)
|
||||
{
|
||||
for (int i = 0; i < section.SectionSheet.Count; i++)
|
||||
{
|
||||
if (string.Equals(section.SectionSheet[i].Key, itemKey, StringComparison.Ordinal))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int FindLanguageStringIndex(LocalizationLanguage language, int sectionId, int entryId)
|
||||
{
|
||||
for (int i = 0; i < language.Strings.Count; i++)
|
||||
{
|
||||
LocalizationLanguage.LocalizationString item = language.Strings[i];
|
||||
if (item.SectionId == sectionId && item.EntryId == entryId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int GenerateUniqueSectionId(GameLocaizationTable table)
|
||||
{
|
||||
return GenerateUniqueId(table, true);
|
||||
}
|
||||
|
||||
private static int GenerateUniqueEntryId(GameLocaizationTable table)
|
||||
{
|
||||
return GenerateUniqueId(table, false);
|
||||
}
|
||||
|
||||
private static int GenerateUniqueId(GameLocaizationTable table, bool checkSectionIds)
|
||||
{
|
||||
int candidate = Mathf.Abs(Guid.NewGuid().GetHashCode());
|
||||
while (candidate == 0 || ContainsId(table, candidate, checkSectionIds))
|
||||
{
|
||||
candidate = Mathf.Abs(Guid.NewGuid().GetHashCode());
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private static bool ContainsId(GameLocaizationTable table, int id, bool checkSectionIds)
|
||||
{
|
||||
for (int i = 0; i < table.TableSheet.Count; i++)
|
||||
{
|
||||
GameLocaizationTable.TableData section = table.TableSheet[i];
|
||||
if (checkSectionIds && section.Id == id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (section.SectionSheet == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < section.SectionSheet.Count; j++)
|
||||
{
|
||||
if (!checkSectionIds && section.SectionSheet[j].Id == id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string BuildRuntimeKey(string sectionName, string itemKey)
|
||||
{
|
||||
return string.Concat(sectionName, ".", itemKey);
|
||||
}
|
||||
|
||||
private static void ParseAndNormalizeKey(ref string sectionName, ref string itemKey)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(itemKey))
|
||||
{
|
||||
int separatorIndex = itemKey.IndexOf('.');
|
||||
if (separatorIndex > 0 && separatorIndex < itemKey.Length - 1)
|
||||
{
|
||||
sectionName = itemKey.Substring(0, separatorIndex);
|
||||
itemKey = itemKey.Substring(separatorIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
sectionName = NormalizePart(sectionName);
|
||||
itemKey = NormalizePart(itemKey);
|
||||
}
|
||||
|
||||
private static string NormalizePart(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder builder = new(value.Length);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
char current = value[i];
|
||||
if (char.IsLetterOrDigit(current) || current == '_')
|
||||
{
|
||||
builder.Append(current);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char.IsWhiteSpace(current) || current == '-' || current == '/')
|
||||
{
|
||||
builder.Append('_');
|
||||
}
|
||||
}
|
||||
|
||||
while (builder.Length > 0 && builder[0] == '_')
|
||||
{
|
||||
builder.Remove(0, 1);
|
||||
}
|
||||
|
||||
while (builder.Length > 0 && builder[builder.Length - 1] == '_')
|
||||
{
|
||||
builder.Remove(builder.Length - 1, 1);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Editor/Localization/LocalizationAiWriteTool.cs.meta
Normal file
11
Editor/Localization/LocalizationAiWriteTool.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 511aa2d0442ccf746aa6dd266d5197d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,11 +1,25 @@
|
||||
namespace AlicizaX
|
||||
{
|
||||
/// <summary>
|
||||
/// 框架内置的 App Scope 标记类,生命周期与 ServiceWorld 相同。
|
||||
/// </summary>
|
||||
public static class ServiceDomainOrder
|
||||
{
|
||||
public const int App = -10000;
|
||||
public const int Scene = -5000;
|
||||
public const int Gameplay = 0;
|
||||
}
|
||||
|
||||
public sealed class AppScope : IScope
|
||||
{
|
||||
public int Order => -10000;
|
||||
public int Order => ServiceDomainOrder.App;
|
||||
}
|
||||
|
||||
public sealed class SceneScope : IScope
|
||||
{
|
||||
public int Order => ServiceDomainOrder.Scene;
|
||||
}
|
||||
|
||||
public sealed class GameplayScope : IScope
|
||||
{
|
||||
public int Order => ServiceDomainOrder.Gameplay;
|
||||
}
|
||||
|
||||
public interface IScope
|
||||
|
||||
@ -7,6 +7,8 @@ namespace AlicizaX
|
||||
private static ServiceWorld _world;
|
||||
|
||||
public static bool HasWorld => _world != null;
|
||||
public static bool HasScene => _world != null && _world.HasScene;
|
||||
public static bool HasGameplay => _world != null && _world.HasGameplay;
|
||||
|
||||
public static ServiceWorld World
|
||||
{
|
||||
@ -18,36 +20,45 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
|
||||
public static ServiceScope App => World.AppScope;
|
||||
public static ServiceScope App => World.App;
|
||||
|
||||
public static ServiceWorld EnsureWorld(int appScopeOrder = -10000)
|
||||
public static ServiceScope Scene => World.Scene;
|
||||
|
||||
public static ServiceScope Gameplay => World.Gameplay;
|
||||
|
||||
public static ServiceWorld EnsureWorld(int appScopeOrder = ServiceDomainOrder.App)
|
||||
{
|
||||
if (_world == null)
|
||||
_world = new ServiceWorld(appScopeOrder);
|
||||
return _world;
|
||||
}
|
||||
|
||||
// ── Scope 管理 ──────────────────────────────────────────────────────────
|
||||
public static ServiceScope EnsureScene(int order = ServiceDomainOrder.Scene)
|
||||
=> World.EnsureScene(order);
|
||||
|
||||
public static ServiceScope CreateScope<TScope>(int order = 0) where TScope : IScope
|
||||
=> World.CreateScope<TScope>(order);
|
||||
|
||||
public static ServiceScope GetOrCreateScope<TScope>(int order = 0) where TScope : IScope
|
||||
=> World.GetOrCreateScope<TScope>(order);
|
||||
|
||||
public static bool TryGetScope<TScope>(out ServiceScope scope) where TScope : IScope
|
||||
public static bool TryGetScene(out ServiceScope scope)
|
||||
{
|
||||
if (_world == null) { scope = null; return false; }
|
||||
return _world.TryGetScope<TScope>(out scope);
|
||||
return _world.TryGetScene(out scope);
|
||||
}
|
||||
|
||||
public static bool DestroyScope<TScope>() where TScope : IScope
|
||||
public static ServiceScope ResetScene(int order = ServiceDomainOrder.Scene)
|
||||
=> World.ResetScene(order);
|
||||
|
||||
public static bool DestroyScene()
|
||||
=> _world != null && _world.DestroyScene();
|
||||
|
||||
public static ServiceScope EnsureGameplay(int order = ServiceDomainOrder.Gameplay)
|
||||
=> World.EnsureGameplay(order);
|
||||
|
||||
public static bool TryGetGameplay(out ServiceScope scope)
|
||||
{
|
||||
if (_world == null) return false;
|
||||
return _world.DestroyScope<TScope>();
|
||||
if (_world == null) { scope = null; return false; }
|
||||
return _world.TryGetGameplay(out scope);
|
||||
}
|
||||
|
||||
// ── Service 查找 ────────────────────────────────────────────────────────
|
||||
public static bool DestroyGameplay()
|
||||
=> _world != null && _world.DestroyGameplay();
|
||||
|
||||
public static bool TryGet<T>(out T service) where T : class, IService
|
||||
{
|
||||
@ -58,8 +69,6 @@ namespace AlicizaX
|
||||
public static T Require<T>() where T : class, IService
|
||||
=> World.Require<T>();
|
||||
|
||||
// ── 生命周期 ────────────────────────────────────────────────────────────
|
||||
|
||||
public static void Shutdown()
|
||||
{
|
||||
if (_world == null) return;
|
||||
|
||||
@ -12,7 +12,17 @@ namespace AlicizaX
|
||||
|
||||
public ServiceScope Scope { get; }
|
||||
|
||||
public ServiceScope AppScope => World.AppScope;
|
||||
public ServiceScope App => World.App;
|
||||
|
||||
public ServiceScope AppScope => App;
|
||||
|
||||
public bool HasScene => World.HasScene;
|
||||
|
||||
public bool HasGameplay => World.HasGameplay;
|
||||
|
||||
public ServiceScope Scene => World.Scene;
|
||||
|
||||
public ServiceScope Gameplay => World.Gameplay;
|
||||
|
||||
public T Require<T>() where T : class, IService
|
||||
=> World.Require<T>(Scope);
|
||||
@ -20,13 +30,28 @@ namespace AlicizaX
|
||||
public bool TryGet<T>(out T service) where T : class, IService
|
||||
=> World.TryGet(Scope, out service);
|
||||
|
||||
public ServiceScope CreateScope<TScope>(int order = 0) where TScope : IScope
|
||||
=> World.CreateScope<TScope>(order);
|
||||
public ServiceScope EnsureScene(int order = ServiceDomainOrder.Scene)
|
||||
=> World.EnsureScene(order);
|
||||
|
||||
public ServiceScope GetOrCreateScope<TScope>(int order = 0) where TScope : IScope
|
||||
=> World.GetOrCreateScope<TScope>(order);
|
||||
public bool TryGetScene(out ServiceScope scope)
|
||||
=> World.TryGetScene(out scope);
|
||||
|
||||
public bool TryGetScope<TScope>(out ServiceScope scope) where TScope : IScope
|
||||
=> World.TryGetScope<TScope>(out scope);
|
||||
public ServiceScope ResetScene(int order = ServiceDomainOrder.Scene)
|
||||
=> World.ResetScene(order);
|
||||
|
||||
public ServiceScope EnsureGameplay(int order = ServiceDomainOrder.Gameplay)
|
||||
=> World.EnsureGameplay(order);
|
||||
|
||||
public bool TryGetGameplay(out ServiceScope scope)
|
||||
=> World.TryGetGameplay(out scope);
|
||||
|
||||
public T RequireApp<T>() where T : class, IService
|
||||
=> App.Require<T>();
|
||||
|
||||
public T RequireScene<T>() where T : class, IService
|
||||
=> Scene.Require<T>();
|
||||
|
||||
public T RequireGameplay<T>() where T : class, IService
|
||||
=> Gameplay.Require<T>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,58 +10,89 @@ namespace AlicizaX
|
||||
|
||||
private ServiceScope[] _scopeSnapshot = Array.Empty<ServiceScope>();
|
||||
private bool _scopesDirty;
|
||||
private ServiceScope _sceneScope;
|
||||
private ServiceScope _gameplayScope;
|
||||
|
||||
public ServiceWorld(int appScopeOrder = -10000)
|
||||
public ServiceWorld(int appScopeOrder = ServiceDomainOrder.App)
|
||||
{
|
||||
AppScope = CreateScopeInternal(typeof(AppScope), appScopeOrder);
|
||||
App = CreateScopeInternal(typeof(AppScope), nameof(AppScope), appScopeOrder);
|
||||
}
|
||||
|
||||
public ServiceScope AppScope { get; }
|
||||
public ServiceScope App { get; }
|
||||
|
||||
// ── Scope 管理(Type-based) ────────────────────────────────────────────
|
||||
public ServiceScope AppScope => App;
|
||||
|
||||
public ServiceScope CreateScope<TScope>(int order = 0) where TScope : IScope
|
||||
public bool HasScene => _sceneScope != null && !_sceneScope.IsDisposed;
|
||||
|
||||
public bool HasGameplay => _gameplayScope != null && !_gameplayScope.IsDisposed;
|
||||
|
||||
public ServiceScope Scene
|
||||
{
|
||||
var type = typeof(TScope);
|
||||
if (_scopesByType.ContainsKey(type))
|
||||
throw new InvalidOperationException($"Scope {type.Name} already exists.");
|
||||
return CreateScopeInternal(type, order);
|
||||
get
|
||||
{
|
||||
if (!HasScene)
|
||||
throw new InvalidOperationException("Scene scope has not been created yet.");
|
||||
return _sceneScope;
|
||||
}
|
||||
}
|
||||
|
||||
public ServiceScope GetOrCreateScope<TScope>(int order = 0) where TScope : IScope
|
||||
public ServiceScope Gameplay
|
||||
{
|
||||
var type = typeof(TScope);
|
||||
if (_scopesByType.TryGetValue(type, out var existing))
|
||||
return existing;
|
||||
return CreateScopeInternal(type, order);
|
||||
get
|
||||
{
|
||||
if (!HasGameplay)
|
||||
throw new InvalidOperationException("Gameplay scope has not been created yet.");
|
||||
return _gameplayScope;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetScope<TScope>(out ServiceScope scope) where TScope : IScope
|
||||
=> _scopesByType.TryGetValue(typeof(TScope), out scope);
|
||||
public ServiceScope EnsureScene(int order = ServiceDomainOrder.Scene)
|
||||
=> _sceneScope is { IsDisposed: false }
|
||||
? _sceneScope
|
||||
: _sceneScope = CreateScopeInternal(typeof(SceneScope), nameof(SceneScope), order);
|
||||
|
||||
public ServiceScope GetScope<TScope>() where TScope : IScope
|
||||
public bool TryGetScene(out ServiceScope scope)
|
||||
{
|
||||
if (TryGetScope<TScope>(out var scope)) return scope;
|
||||
throw new InvalidOperationException($"Scope {typeof(TScope).Name} does not exist.");
|
||||
scope = HasScene ? _sceneScope : null;
|
||||
return scope != null;
|
||||
}
|
||||
|
||||
public bool DestroyScope<TScope>() where TScope : IScope
|
||||
public ServiceScope ResetScene(int order = ServiceDomainOrder.Scene)
|
||||
{
|
||||
if (typeof(TScope) == typeof(AppScope))
|
||||
throw new InvalidOperationException("AppScope can only be destroyed when the world is disposed.");
|
||||
DestroyScene();
|
||||
return EnsureScene(order);
|
||||
}
|
||||
|
||||
var type = typeof(TScope);
|
||||
if (!_scopesByType.TryGetValue(type, out var scope))
|
||||
public bool DestroyScene()
|
||||
{
|
||||
if (!HasScene)
|
||||
return false;
|
||||
|
||||
_scopesByType.Remove(type);
|
||||
_scopes.Remove(scope);
|
||||
_scopesDirty = true;
|
||||
scope.Dispose();
|
||||
return true;
|
||||
var scope = _sceneScope;
|
||||
_sceneScope = null;
|
||||
return DestroyScope(scope, typeof(SceneScope));
|
||||
}
|
||||
|
||||
// ── Service 查找 ────────────────────────────────────────────────────────
|
||||
public ServiceScope EnsureGameplay(int order = ServiceDomainOrder.Gameplay)
|
||||
=> _gameplayScope is { IsDisposed: false }
|
||||
? _gameplayScope
|
||||
: _gameplayScope = CreateScopeInternal(typeof(GameplayScope), nameof(GameplayScope), order);
|
||||
|
||||
public bool TryGetGameplay(out ServiceScope scope)
|
||||
{
|
||||
scope = HasGameplay ? _gameplayScope : null;
|
||||
return scope != null;
|
||||
}
|
||||
|
||||
public bool DestroyGameplay()
|
||||
{
|
||||
if (!HasGameplay)
|
||||
return false;
|
||||
|
||||
var scope = _gameplayScope;
|
||||
_gameplayScope = null;
|
||||
return DestroyScope(scope, typeof(GameplayScope));
|
||||
}
|
||||
|
||||
public bool TryGet<T>(out T service) where T : class, IService
|
||||
=> TryGet(null, out service);
|
||||
@ -91,8 +122,6 @@ namespace AlicizaX
|
||||
throw new InvalidOperationException($"Service {typeof(T).FullName} was not found in any active scope.");
|
||||
}
|
||||
|
||||
// ── Tick ────────────────────────────────────────────────────────────────
|
||||
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
var snapshot = GetScopeSnapshot();
|
||||
@ -117,23 +146,37 @@ namespace AlicizaX
|
||||
for (var i = 0; i < snapshot.Length; i++) snapshot[i].DrawGizmos();
|
||||
}
|
||||
|
||||
// ── Dispose ─────────────────────────────────────────────────────────────
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var snapshot = _scopes.ToArray();
|
||||
for (var i = snapshot.Length - 1; i >= 0; i--)
|
||||
snapshot[i].Dispose();
|
||||
|
||||
_sceneScope = null;
|
||||
_gameplayScope = null;
|
||||
_scopes.Clear();
|
||||
_scopesByType.Clear();
|
||||
_scopeSnapshot = Array.Empty<ServiceScope>();
|
||||
}
|
||||
|
||||
// ── 内部 ────────────────────────────────────────────────────────────────
|
||||
|
||||
private ServiceScope CreateScopeInternal(Type scopeType, int order)
|
||||
private bool DestroyScope(ServiceScope scope, Type scopeType)
|
||||
{
|
||||
var scope = new ServiceScope(this, scopeType.Name, order);
|
||||
if (scope == null)
|
||||
return false;
|
||||
|
||||
_scopesByType.Remove(scopeType);
|
||||
_scopes.Remove(scope);
|
||||
_scopesDirty = true;
|
||||
scope.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
private ServiceScope CreateScopeInternal(Type scopeType, string scopeName, int order)
|
||||
{
|
||||
if (_scopesByType.ContainsKey(scopeType))
|
||||
throw new InvalidOperationException($"Scope {scopeType.Name} already exists.");
|
||||
|
||||
var scope = new ServiceScope(this, scopeName, order);
|
||||
_scopes.Add(scope);
|
||||
_scopesByType.Add(scopeType, scope);
|
||||
_scopes.Sort(CompareScopeOrder);
|
||||
|
||||
@ -10,7 +10,7 @@ namespace AlicizaX
|
||||
private static AppServiceRoot s_activeRoot;
|
||||
|
||||
[SerializeField] private bool _dontDestroyOnLoad = true;
|
||||
[SerializeField] private int _appScopeOrder = -10000;
|
||||
[SerializeField] private int _appScopeOrder = ServiceDomainOrder.App;
|
||||
|
||||
private bool _ownsWorld;
|
||||
|
||||
@ -32,7 +32,7 @@ namespace AlicizaX
|
||||
_ownsWorld = createdWorld;
|
||||
|
||||
if (createdWorld)
|
||||
RegisterAppServices(world.AppScope);
|
||||
RegisterAppServices(world.App);
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
|
||||
@ -2,9 +2,6 @@ using UnityEngine;
|
||||
|
||||
namespace AlicizaX
|
||||
{
|
||||
/// <summary>
|
||||
/// Mono 服务基类(不自动注册,适合需要手动控制注册时机的场景)。
|
||||
/// </summary>
|
||||
public abstract class MonoServiceBehaviour : MonoBehaviour, IMonoService
|
||||
{
|
||||
public ServiceContext Context { get; private set; }
|
||||
@ -39,25 +36,11 @@ namespace AlicizaX
|
||||
protected virtual void OnDestroyService() { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mono 服务基类(自动注册到 <typeparamref name="TScope"/>)。
|
||||
/// <para>
|
||||
/// 场景服务:<c>_dontDestroyOnLoad = false</c>(默认),销毁时自动注销。<br/>
|
||||
/// 跨场景服务:<c>_dontDestroyOnLoad = true</c>,首个实例持久化并注册;
|
||||
/// 后续场景中出现的重复实例自动销毁自身。
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 子类通过 <see cref="OnAwake"/> 执行额外的 Awake 逻辑,
|
||||
/// 通过 <see cref="OnServiceInitialize"/> 执行注册后的初始化,
|
||||
/// 通过 <see cref="OnServiceDestroy"/> 执行注销前的清理。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract class MonoServiceBehaviour<TScope> : MonoServiceBehaviour
|
||||
where TScope : IScope
|
||||
{
|
||||
[SerializeField] private bool _dontDestroyOnLoad = false;
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
OnAwake();
|
||||
@ -65,9 +48,8 @@ namespace AlicizaX
|
||||
|
||||
private void Start()
|
||||
{
|
||||
var scope = AppServices.GetOrCreateScope<TScope>();
|
||||
var scope = ResolveOrCreateScope();
|
||||
|
||||
// 跨场景重复实例检测:契约已被占用则销毁自身
|
||||
if (scope.HasContract(GetType()))
|
||||
{
|
||||
Destroy(gameObject);
|
||||
@ -84,15 +66,43 @@ namespace AlicizaX
|
||||
{
|
||||
if (!IsInitialized) return;
|
||||
if (!AppServices.HasWorld) return;
|
||||
if (!AppServices.TryGetScope<TScope>(out var scope)) return;
|
||||
if (!TryResolveScope(out var scope)) return;
|
||||
|
||||
scope.Unregister(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在 Awake 阶段执行(早于 Start 中的自动注册)。
|
||||
/// 适合缓存组件引用等不依赖服务系统的初始化。
|
||||
/// </summary>
|
||||
private static ServiceScope ResolveOrCreateScope()
|
||||
{
|
||||
if (typeof(TScope) == typeof(AppScope))
|
||||
return AppServices.App;
|
||||
|
||||
if (typeof(TScope) == typeof(SceneScope))
|
||||
return AppServices.EnsureScene();
|
||||
|
||||
if (typeof(TScope) == typeof(GameplayScope))
|
||||
return AppServices.EnsureGameplay();
|
||||
|
||||
throw new System.InvalidOperationException($"Unsupported service scope: {typeof(TScope).FullName}.");
|
||||
}
|
||||
|
||||
private static bool TryResolveScope(out ServiceScope scope)
|
||||
{
|
||||
if (typeof(TScope) == typeof(AppScope))
|
||||
{
|
||||
scope = AppServices.App;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof(TScope) == typeof(SceneScope))
|
||||
return AppServices.TryGetScene(out scope);
|
||||
|
||||
if (typeof(TScope) == typeof(GameplayScope))
|
||||
return AppServices.TryGetGameplay(out scope);
|
||||
|
||||
scope = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void OnAwake() { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,8 @@ namespace AlicizaX
|
||||
private UniTask _initializeTask;
|
||||
private bool _initializationCompleted;
|
||||
private Exception _initializationException;
|
||||
private float _lastCleanupTime;
|
||||
private bool _cleanupScheduled;
|
||||
private float _nextCleanupTime = float.MaxValue;
|
||||
|
||||
private bool _isShuttingDown;
|
||||
|
||||
@ -51,11 +52,14 @@ namespace AlicizaX
|
||||
_shutdownTokenSource = new CancellationTokenSource();
|
||||
EnsureDefaultResourceLoaders();
|
||||
EnsurePoolContainer();
|
||||
enabled = false;
|
||||
Application.lowMemory += OnLowMemory;
|
||||
_initializeTask = InitializeAsync(_shutdownTokenSource.Token);
|
||||
}
|
||||
|
||||
protected override void OnDestroyService()
|
||||
{
|
||||
Application.lowMemory -= OnLowMemory;
|
||||
_shutdownTokenSource?.Cancel();
|
||||
ClearAllPools();
|
||||
|
||||
@ -75,9 +79,9 @@ namespace AlicizaX
|
||||
{
|
||||
await UniTask.WaitUntil(() => YooAsset.YooAssets.Initialized, cancellationToken: cancellationToken);
|
||||
LoadConfigs();
|
||||
_lastCleanupTime = Time.time;
|
||||
_initializationCompleted = true;
|
||||
await PrewarmConfiguredPoolsAsync(cancellationToken);
|
||||
ScheduleCleanup();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@ -92,18 +96,19 @@ namespace AlicizaX
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!IsReady)
|
||||
if (!IsReady || !_cleanupScheduled)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Time.time - _lastCleanupTime < checkInterval)
|
||||
if (Time.time < _nextCleanupTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PerformCleanup();
|
||||
_lastCleanupTime = Time.time;
|
||||
ScheduleCleanup();
|
||||
}
|
||||
|
||||
public void SetResourceLoader(IResourceLoader resourceLoader)
|
||||
@ -205,7 +210,7 @@ namespace AlicizaX
|
||||
}
|
||||
|
||||
PerformCleanup();
|
||||
_lastCleanupTime = Time.time;
|
||||
ScheduleCleanup();
|
||||
}
|
||||
|
||||
public void ClearAllPools()
|
||||
@ -224,6 +229,9 @@ namespace AlicizaX
|
||||
_resolvedConfigCache.Clear();
|
||||
_groupLoaderCache.Clear();
|
||||
ReleaseDebugSnapshots();
|
||||
_cleanupScheduled = false;
|
||||
_nextCleanupTime = float.MaxValue;
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
public List<GameObjectPoolSnapshot> GetDebugSnapshots()
|
||||
@ -248,6 +256,7 @@ namespace AlicizaX
|
||||
}
|
||||
|
||||
_ownersByObject[gameObject] = pool;
|
||||
NotifyPoolStateChanged();
|
||||
}
|
||||
|
||||
internal void UnregisterOwnedObject(GameObject gameObject)
|
||||
@ -258,6 +267,17 @@ namespace AlicizaX
|
||||
}
|
||||
|
||||
_ownersByObject.Remove(gameObject);
|
||||
NotifyPoolStateChanged();
|
||||
}
|
||||
|
||||
internal void NotifyPoolStateChanged()
|
||||
{
|
||||
if (!IsReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ScheduleCleanup();
|
||||
}
|
||||
|
||||
private GameObject GetGameObjectInternal(string assetPath, string group, Transform parent)
|
||||
@ -347,6 +367,7 @@ namespace AlicizaX
|
||||
_shutdownTokenSource != null ? _shutdownTokenSource.Token : default);
|
||||
|
||||
_poolsByKey.Add(poolKey, pool);
|
||||
ScheduleCleanup();
|
||||
return pool;
|
||||
}
|
||||
|
||||
@ -359,6 +380,43 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
|
||||
private void ScheduleCleanup()
|
||||
{
|
||||
if (!IsReady)
|
||||
{
|
||||
_cleanupScheduled = false;
|
||||
_nextCleanupTime = float.MaxValue;
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
float nextDueTime = float.MaxValue;
|
||||
float now = Time.time;
|
||||
foreach (RuntimePrefabPool pool in _poolsByKey.Values)
|
||||
{
|
||||
float candidate = pool.GetNextCleanupTime(now, checkInterval);
|
||||
if (candidate < nextDueTime)
|
||||
{
|
||||
nextDueTime = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
_nextCleanupTime = nextDueTime;
|
||||
_cleanupScheduled = nextDueTime < float.MaxValue;
|
||||
enabled = _cleanupScheduled;
|
||||
}
|
||||
|
||||
private void OnLowMemory()
|
||||
{
|
||||
if (!IsReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PerformCleanup();
|
||||
ScheduleCleanup();
|
||||
}
|
||||
|
||||
private void EnsureDefaultResourceLoaders()
|
||||
{
|
||||
if (!_resourceLoaders.ContainsKey(PoolResourceLoaderType.AssetBundle))
|
||||
|
||||
@ -16,18 +16,51 @@ namespace AlicizaX
|
||||
|
||||
public class UnityResourcesLoader : IResourceLoader
|
||||
{
|
||||
private static bool AllowLegacyResourcesFallback => Application.isEditor || Debug.isDebugBuild;
|
||||
|
||||
public GameObject LoadPrefab(string location)
|
||||
{
|
||||
return Resources.Load<GameObject>(location);
|
||||
if (TryGetResourceService(out var resourceService))
|
||||
{
|
||||
var prefab = resourceService.LoadAsset<GameObject>(location);
|
||||
if (prefab != null)
|
||||
{
|
||||
return prefab;
|
||||
}
|
||||
}
|
||||
|
||||
return AllowLegacyResourcesFallback ? Resources.Load<GameObject>(location) : null;
|
||||
}
|
||||
|
||||
public async UniTask<GameObject> LoadPrefabAsync(string location, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await Resources.LoadAsync<GameObject>(location).ToUniTask(cancellationToken: cancellationToken) as GameObject;
|
||||
if (TryGetResourceService(out var resourceService))
|
||||
{
|
||||
var prefab = await resourceService.LoadAssetAsync<GameObject>(location, cancellationToken);
|
||||
if (prefab != null)
|
||||
{
|
||||
return prefab;
|
||||
}
|
||||
}
|
||||
|
||||
return AllowLegacyResourcesFallback
|
||||
? await Resources.LoadAsync<GameObject>(location).ToUniTask(cancellationToken: cancellationToken) as GameObject
|
||||
: null;
|
||||
}
|
||||
|
||||
public GameObject LoadGameObject(string location, Transform parent = null)
|
||||
{
|
||||
if (TryGetResourceService(out var resourceService))
|
||||
{
|
||||
var managedObject = resourceService.LoadGameObject(location, parent);
|
||||
if (managedObject != null)
|
||||
{
|
||||
return managedObject;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AllowLegacyResourcesFallback) return null;
|
||||
|
||||
var prefab = Resources.Load<GameObject>(location);
|
||||
if (prefab == null) return null;
|
||||
|
||||
@ -42,6 +75,17 @@ namespace AlicizaX
|
||||
|
||||
public async UniTask<GameObject> LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (TryGetResourceService(out var resourceService))
|
||||
{
|
||||
var managedObject = await resourceService.LoadGameObjectAsync(location, parent, cancellationToken);
|
||||
if (managedObject != null)
|
||||
{
|
||||
return managedObject;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AllowLegacyResourcesFallback) return null;
|
||||
|
||||
var prefab = await Resources.LoadAsync<GameObject>(location).ToUniTask(cancellationToken: cancellationToken) as GameObject;
|
||||
if (prefab == null) return null;
|
||||
|
||||
@ -59,6 +103,11 @@ namespace AlicizaX
|
||||
// Resources.UnloadAsset cannot unload GameObjects.
|
||||
// The prefab reference is nulled by the caller; Unity handles cleanup via UnloadUnusedAssets.
|
||||
}
|
||||
|
||||
private static bool TryGetResourceService(out IResourceService resourceService)
|
||||
{
|
||||
return AppServices.TryGet(out resourceService);
|
||||
}
|
||||
}
|
||||
|
||||
public class AssetBundleResourceLoader : IResourceLoader
|
||||
|
||||
@ -241,6 +241,7 @@ namespace AlicizaX
|
||||
|
||||
instance.InactiveNode = _inactiveInstances.AddLast(instance);
|
||||
TouchPrefab();
|
||||
_service.NotifyPoolStateChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -281,6 +282,34 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
|
||||
public float GetNextCleanupTime(float now, float fallbackDelay)
|
||||
{
|
||||
float nextDueTime = float.MaxValue;
|
||||
|
||||
if (_config.instanceIdleTimeout > 0f && _inactiveInstances.First != null)
|
||||
{
|
||||
float instanceDueTime = _inactiveInstances.First.Value.LastReleaseTime + _config.instanceIdleTimeout;
|
||||
nextDueTime = Math.Min(nextDueTime, Math.Max(now, instanceDueTime));
|
||||
}
|
||||
|
||||
if (_prefab != null &&
|
||||
_instancesByObject.Count == 0 &&
|
||||
_config.prefabUnloadDelay > 0f)
|
||||
{
|
||||
float prefabDueTime = _lastPrefabTouchTime + _config.prefabUnloadDelay;
|
||||
nextDueTime = Math.Min(nextDueTime, Math.Max(now, prefabDueTime));
|
||||
}
|
||||
|
||||
if (nextDueTime < float.MaxValue)
|
||||
{
|
||||
return nextDueTime;
|
||||
}
|
||||
|
||||
return _instancesByObject.Count > 0 || _prefab != null
|
||||
? now + Math.Max(fallbackDelay, 0.1f)
|
||||
: float.MaxValue;
|
||||
}
|
||||
|
||||
public GameObjectPoolSnapshot CreateSnapshot()
|
||||
{
|
||||
var snapshot = MemoryPool.Acquire<GameObjectPoolSnapshot>();
|
||||
@ -489,6 +518,7 @@ namespace AlicizaX
|
||||
transform.localScale = Vector3.one;
|
||||
instance.GameObject.SetActive(false);
|
||||
instance.InactiveNode = _inactiveInstances.AddLast(instance);
|
||||
_service.NotifyPoolStateChanged();
|
||||
}
|
||||
|
||||
private void DestroyInstance(RuntimePooledInstance instance)
|
||||
@ -528,6 +558,7 @@ namespace AlicizaX
|
||||
_instancesByObject.Remove(gameObject);
|
||||
_service.UnregisterOwnedObject(gameObject);
|
||||
TouchPrefab();
|
||||
_service.NotifyPoolStateChanged();
|
||||
}
|
||||
|
||||
private void RemoveInactiveNode(RuntimePooledInstance instance)
|
||||
|
||||
@ -9,9 +9,9 @@ namespace AlicizaX
|
||||
{
|
||||
public class ModuleDynamicBind : MonoBehaviour
|
||||
{
|
||||
[FormerlySerializedAs("_resourceServiceBehaviour")] [SerializeField] private ResourceComponent resourceComponent;
|
||||
[FormerlySerializedAs("_debuggerServiceBehaviour")] [SerializeField] private DebuggerComponent debuggerComponent;
|
||||
[FormerlySerializedAs("_localizationServiceBehaviour")] [SerializeField] private LocalizationComponent localizationComponent;
|
||||
[SerializeField] private ResourceComponent resourceComponent;
|
||||
[SerializeField] private DebuggerComponent debuggerComponent;
|
||||
[SerializeField] private LocalizationComponent localizationComponent;
|
||||
private ModuleDynamicBindInfo _dynamicBindInfo;
|
||||
|
||||
private void OnValidate()
|
||||
@ -24,7 +24,23 @@ namespace AlicizaX
|
||||
private void Awake()
|
||||
{
|
||||
if (Application.isEditor) return;
|
||||
TextAsset text = Resources.Load<TextAsset>("ModuleDynamicBindInfo");
|
||||
TextAsset text = null;
|
||||
if (AppServices.TryGet<IResourceService>(out var resourceService))
|
||||
{
|
||||
text = resourceService.LoadAsset<TextAsset>("ModuleDynamicBindInfo");
|
||||
}
|
||||
|
||||
if (text == null)
|
||||
{
|
||||
text = Resources.Load<TextAsset>("ModuleDynamicBindInfo");
|
||||
}
|
||||
|
||||
if (text == null)
|
||||
{
|
||||
Log.Warning("ModuleDynamicBindInfo not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
_dynamicBindInfo = Utility.Json.ToObject<ModuleDynamicBindInfo>(text.text);
|
||||
|
||||
if (resourceComponent != null)
|
||||
|
||||
@ -1,745 +1,80 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX;
|
||||
|
||||
namespace AlicizaX.ObjectPool
|
||||
{
|
||||
public readonly struct ObjectPoolCreateOptions
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly bool AllowMultiSpawn;
|
||||
public readonly float AutoReleaseInterval;
|
||||
public readonly int Capacity;
|
||||
public readonly float ExpireTime;
|
||||
public readonly int Priority;
|
||||
|
||||
public ObjectPoolCreateOptions(
|
||||
string name = "",
|
||||
bool allowMultiSpawn = false,
|
||||
float autoReleaseInterval = float.MaxValue,
|
||||
int capacity = int.MaxValue,
|
||||
float expireTime = float.MaxValue,
|
||||
int priority = 0)
|
||||
{
|
||||
Name = name ?? string.Empty;
|
||||
AllowMultiSpawn = allowMultiSpawn;
|
||||
AutoReleaseInterval = autoReleaseInterval;
|
||||
Capacity = capacity;
|
||||
ExpireTime = expireTime;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
public ObjectPoolCreateOptions WithName(string name)
|
||||
=> new ObjectPoolCreateOptions(name, AllowMultiSpawn, AutoReleaseInterval, Capacity, ExpireTime, Priority);
|
||||
|
||||
public static ObjectPoolCreateOptions Single(string name = "")
|
||||
=> new ObjectPoolCreateOptions(name: name);
|
||||
|
||||
public static ObjectPoolCreateOptions Multi(string name = "")
|
||||
=> new ObjectPoolCreateOptions(name: name, allowMultiSpawn: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对象池管理器。
|
||||
/// </summary>
|
||||
public interface IObjectPoolService : IService, IServiceTickable
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取对象池数量。
|
||||
/// </summary>
|
||||
int Count
|
||||
{
|
||||
get;
|
||||
}
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <returns>是否存在对象池。</returns>
|
||||
bool HasObjectPool<T>() where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <returns>是否存在对象池。</returns>
|
||||
bool HasObjectPool(Type objectType);
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>是否存在对象池。</returns>
|
||||
bool HasObjectPool<T>(string name) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>是否存在对象池。</returns>
|
||||
bool HasObjectPool(Type objectType, string name);
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在对象池。
|
||||
/// </summary>
|
||||
/// <param name="condition">要检查的条件。</param>
|
||||
/// <returns>是否存在对象池。</returns>
|
||||
bool HasObjectPool(Predicate<ObjectPoolBase> condition);
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <returns>要获取的对象池。</returns>
|
||||
IObjectPool<T> GetObjectPool<T>() where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <returns>要获取的对象池。</returns>
|
||||
ObjectPoolBase GetObjectPool(Type objectType);
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>要获取的对象池。</returns>
|
||||
IObjectPool<T> GetObjectPool<T>(string name) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>要获取的对象池。</returns>
|
||||
ObjectPoolBase GetObjectPool(Type objectType, string name);
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池。
|
||||
/// </summary>
|
||||
/// <param name="condition">要检查的条件。</param>
|
||||
/// <returns>要获取的对象池。</returns>
|
||||
ObjectPoolBase GetObjectPool(Predicate<ObjectPoolBase> condition);
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池。
|
||||
/// </summary>
|
||||
/// <param name="condition">要检查的条件。</param>
|
||||
/// <returns>要获取的对象池。</returns>
|
||||
ObjectPoolBase[] GetObjectPools(Predicate<ObjectPoolBase> condition);
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池。
|
||||
/// </summary>
|
||||
/// <param name="condition">要检查的条件。</param>
|
||||
/// <param name="results">要获取的对象池。</param>
|
||||
void GetObjectPools(Predicate<ObjectPoolBase> condition, List<ObjectPoolBase> results);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有对象池。
|
||||
/// </summary>
|
||||
/// <returns>所有对象池。</returns>
|
||||
ObjectPoolBase[] GetAllObjectPools();
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有对象池。
|
||||
/// </summary>
|
||||
/// <param name="results">所有对象池。</param>
|
||||
void GetAllObjectPools(List<ObjectPoolBase> results);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有对象池。
|
||||
/// </summary>
|
||||
/// <param name="sort">是否根据对象池的优先级排序。</param>
|
||||
/// <returns>所有对象池。</returns>
|
||||
ObjectPoolBase[] GetAllObjectPools(bool sort);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有对象池。
|
||||
/// </summary>
|
||||
/// <param name="sort">是否根据对象池的优先级排序。</param>
|
||||
/// <param name="results">所有对象池。</param>
|
||||
void GetAllObjectPools(bool sort, List<ObjectPoolBase> results);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>() where T : ObjectBase;
|
||||
IObjectPool<T> CreatePool<T>(ObjectPoolCreateOptions options = default) where T : ObjectBase;
|
||||
ObjectPoolBase CreatePool(Type objectType, ObjectPoolCreateOptions options = default);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity, float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity, float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="autoReleaseInterval">对象池自动释放可释放对象的间隔秒数。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="autoReleaseInterval">对象池自动释放可释放对象的间隔秒数。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许单次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>() where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity, float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity, float expireTime) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="autoReleaseInterval">对象池自动释放可释放对象的间隔秒数。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许多次获取的对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">对象池名称。</param>
|
||||
/// <param name="autoReleaseInterval">对象池自动释放可释放对象的间隔秒数。</param>
|
||||
/// <param name="capacity">对象池的容量。</param>
|
||||
/// <param name="expireTime">对象池对象过期秒数。</param>
|
||||
/// <param name="priority">对象池的优先级。</param>
|
||||
/// <returns>要创建的允许多次获取的对象池。</returns>
|
||||
ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority);
|
||||
|
||||
/// <summary>
|
||||
/// 销毁对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <returns>是否销毁对象池成功。</returns>
|
||||
bool DestroyObjectPool<T>() where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 销毁对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <returns>是否销毁对象池成功。</returns>
|
||||
bool DestroyObjectPool(Type objectType);
|
||||
|
||||
/// <summary>
|
||||
/// 销毁对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="name">要销毁的对象池名称。</param>
|
||||
/// <returns>是否销毁对象池成功。</returns>
|
||||
bool DestroyObjectPool<T>(string name) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 销毁对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectType">对象类型。</param>
|
||||
/// <param name="name">要销毁的对象池名称。</param>
|
||||
/// <returns>是否销毁对象池成功。</returns>
|
||||
bool DestroyObjectPool(Type objectType, string name);
|
||||
|
||||
/// <summary>
|
||||
/// 销毁对象池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型。</typeparam>
|
||||
/// <param name="objectPool">要销毁的对象池。</param>
|
||||
/// <returns>是否销毁对象池成功。</returns>
|
||||
bool DestroyObjectPool<T>(IObjectPool<T> objectPool) where T : ObjectBase;
|
||||
|
||||
/// <summary>
|
||||
/// 销毁对象池。
|
||||
/// </summary>
|
||||
/// <param name="objectPool">要销毁的对象池。</param>
|
||||
/// <returns>是否销毁对象池成功。</returns>
|
||||
bool DestroyObjectPool(ObjectPoolBase objectPool);
|
||||
|
||||
/// <summary>
|
||||
/// 释放对象池中的可释放对象。
|
||||
/// </summary>
|
||||
void Release();
|
||||
|
||||
/// <summary>
|
||||
/// 释放对象池中的所有未使用对象。
|
||||
/// </summary>
|
||||
void ReleaseAllUnused();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX.ObjectPool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象池组件。
|
||||
/// 对象池组件。
|
||||
/// </summary>
|
||||
public sealed class ObjectPoolComponent : MonoBehaviour
|
||||
{
|
||||
private IObjectPoolService _mObjectPoolService = null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象池数量。
|
||||
/// 获取对象池数量。
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
@ -20,7 +20,7 @@ namespace AlicizaX
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_mObjectPoolService = AppServices.GetOrCreateScope<AppScope>().Register(new ObjectPoolService());
|
||||
_mObjectPoolService = AppServices.App.Register(new ObjectPoolService());
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
@ -29,13 +29,14 @@ namespace AlicizaX
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有对象池。
|
||||
/// 获取所有对象池。
|
||||
/// </summary>
|
||||
/// <param name="sort">是否根据对象池的优先级排序。</param>
|
||||
/// <returns>所有对象池。</returns>
|
||||
/// <param name="sort">是否根据对象池的优先级排序。</param>
|
||||
/// <returns>所有对象池。</returns>
|
||||
public ObjectPoolBase[] GetAllObjectPools(bool sort)
|
||||
{
|
||||
return _mObjectPoolService.GetAllObjectPools(sort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -354,6 +354,29 @@ namespace AlicizaX.ObjectPool
|
||||
}
|
||||
}
|
||||
|
||||
public IObjectPool<T> CreatePool<T>(ObjectPoolCreateOptions options = default) where T : ObjectBase
|
||||
{
|
||||
return InternalCreateObjectPool<T>(
|
||||
options.Name,
|
||||
options.AllowMultiSpawn,
|
||||
NormalizeAutoReleaseInterval(options.AutoReleaseInterval),
|
||||
NormalizeCapacity(options.Capacity),
|
||||
NormalizeExpireTime(options.ExpireTime),
|
||||
options.Priority);
|
||||
}
|
||||
|
||||
public ObjectPoolBase CreatePool(Type objectType, ObjectPoolCreateOptions options = default)
|
||||
{
|
||||
return InternalCreateObjectPool(
|
||||
objectType,
|
||||
options.Name,
|
||||
options.AllowMultiSpawn,
|
||||
NormalizeAutoReleaseInterval(options.AutoReleaseInterval),
|
||||
NormalizeCapacity(options.Capacity),
|
||||
NormalizeExpireTime(options.ExpireTime),
|
||||
options.Priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建允许单次获取的对象池。
|
||||
/// </summary>
|
||||
@ -1212,6 +1235,21 @@ namespace AlicizaX.ObjectPool
|
||||
return m_ObjectPools.ContainsKey(typeNamePair);
|
||||
}
|
||||
|
||||
private static float NormalizeAutoReleaseInterval(float autoReleaseInterval)
|
||||
{
|
||||
return autoReleaseInterval == default ? DefaultExpireTime : autoReleaseInterval;
|
||||
}
|
||||
|
||||
private static int NormalizeCapacity(int capacity)
|
||||
{
|
||||
return capacity == default ? DefaultCapacity : capacity;
|
||||
}
|
||||
|
||||
private static float NormalizeExpireTime(float expireTime)
|
||||
{
|
||||
return expireTime == default ? DefaultExpireTime : expireTime;
|
||||
}
|
||||
|
||||
private ObjectPoolBase InternalGetObjectPool(TypeNamePair typeNamePair)
|
||||
{
|
||||
ObjectPoolBase objectPool = null;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Internal;
|
||||
@ -17,6 +16,7 @@ namespace AlicizaX
|
||||
{
|
||||
private static GameObject _entity;
|
||||
private static MainBehaviour _behaviour;
|
||||
private static UtilityLoopService _loopService;
|
||||
|
||||
#region 控制协程Coroutine
|
||||
|
||||
@ -103,13 +103,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void AddUpdateListener(UnityAction fun)
|
||||
{
|
||||
AddUpdateListenerImp(fun).Forget();
|
||||
}
|
||||
|
||||
private static async UniTaskVoid AddUpdateListenerImp(UnityAction fun)
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.LastPreUpdate);
|
||||
_behaviour.AddUpdateListener(fun);
|
||||
EnsureLoopService().AddUpdateListener(fun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -118,13 +112,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void AddFixedUpdateListener(UnityAction fun)
|
||||
{
|
||||
AddFixedUpdateListenerImp(fun).Forget();
|
||||
}
|
||||
|
||||
private static async UniTaskVoid AddFixedUpdateListenerImp(UnityAction fun)
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.LastEarlyUpdate);
|
||||
_behaviour.AddFixedUpdateListener(fun);
|
||||
EnsureLoopService().AddFixedUpdateListener(fun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -133,13 +121,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void AddLateUpdateListener(UnityAction fun)
|
||||
{
|
||||
AddLateUpdateListenerImp(fun).Forget();
|
||||
}
|
||||
|
||||
private static async UniTaskVoid AddLateUpdateListenerImp(UnityAction fun)
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.LastPreLateUpdate);
|
||||
_behaviour.AddLateUpdateListener(fun);
|
||||
EnsureLoopService().AddLateUpdateListener(fun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -148,7 +130,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void RemoveUpdateListener(UnityAction fun)
|
||||
{
|
||||
_behaviour.RemoveUpdateListener(fun);
|
||||
_loopService?.RemoveUpdateListener(fun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -157,7 +139,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void RemoveFixedUpdateListener(UnityAction fun)
|
||||
{
|
||||
_behaviour.RemoveFixedUpdateListener(fun);
|
||||
_loopService?.RemoveFixedUpdateListener(fun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -166,7 +148,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void RemoveLateUpdateListener(UnityAction fun)
|
||||
{
|
||||
_behaviour.RemoveLateUpdateListener(fun);
|
||||
_loopService?.RemoveLateUpdateListener(fun);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -196,7 +178,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void AddOnDrawGizmosListener(UnityAction fun)
|
||||
{
|
||||
_behaviour.AddOnDrawGizmosListener(fun);
|
||||
EnsureLoopService().AddOnDrawGizmosListener(fun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -205,7 +187,7 @@ namespace AlicizaX
|
||||
/// <param name="fun"></param>
|
||||
public static void RemoveOnDrawGizmosListener(UnityAction fun)
|
||||
{
|
||||
_behaviour.RemoveOnDrawGizmosListener(fun);
|
||||
_loopService?.RemoveOnDrawGizmosListener(fun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -256,6 +238,7 @@ namespace AlicizaX
|
||||
_entity.SetActive(true);
|
||||
_entity.transform.SetParent(parent);
|
||||
_behaviour = _entity.AddComponent<MainBehaviour>();
|
||||
RegisterLoopServiceIfNeeded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -270,6 +253,12 @@ namespace AlicizaX
|
||||
_behaviour.Shutdown();
|
||||
}
|
||||
|
||||
if (_loopService != null)
|
||||
{
|
||||
_loopService.Clear();
|
||||
_loopService = null;
|
||||
}
|
||||
|
||||
if (_entity != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(_entity);
|
||||
@ -279,40 +268,44 @@ namespace AlicizaX
|
||||
_entity = null;
|
||||
}
|
||||
|
||||
private static void RegisterLoopServiceIfNeeded()
|
||||
{
|
||||
if (_loopService != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AppServices.HasWorld)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AppServices.TryGet(out UtilityLoopService service))
|
||||
{
|
||||
_loopService = service;
|
||||
return;
|
||||
}
|
||||
|
||||
_loopService = AppServices.App.Register(new UtilityLoopService());
|
||||
}
|
||||
|
||||
private static UtilityLoopService EnsureLoopService()
|
||||
{
|
||||
RegisterLoopServiceIfNeeded();
|
||||
if (_loopService == null)
|
||||
{
|
||||
throw new InvalidOperationException("Utility loop service is not available.");
|
||||
}
|
||||
|
||||
return _loopService;
|
||||
}
|
||||
|
||||
private class MainBehaviour : MonoBehaviour
|
||||
{
|
||||
private event UnityAction UpdateEvent;
|
||||
private event UnityAction FixedUpdateEvent;
|
||||
private event UnityAction LateUpdateEvent;
|
||||
private event UnityAction DestroyEvent;
|
||||
private event UnityAction OnDrawGizmosEvent;
|
||||
private event UnityAction<bool> OnApplicationPauseEvent;
|
||||
private event UnityAction OnApplicationQuitEvent;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (UpdateEvent != null)
|
||||
{
|
||||
UpdateEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
if (FixedUpdateEvent != null)
|
||||
{
|
||||
FixedUpdateEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (LateUpdateEvent != null)
|
||||
{
|
||||
LateUpdateEvent();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (DestroyEvent != null)
|
||||
@ -321,14 +314,6 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (OnDrawGizmosEvent != null)
|
||||
{
|
||||
OnDrawGizmosEvent();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationPause(bool pauseStatus)
|
||||
{
|
||||
if (OnApplicationPauseEvent != null)
|
||||
@ -345,36 +330,6 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
|
||||
public void AddLateUpdateListener(UnityAction fun)
|
||||
{
|
||||
LateUpdateEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveLateUpdateListener(UnityAction fun)
|
||||
{
|
||||
LateUpdateEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddFixedUpdateListener(UnityAction fun)
|
||||
{
|
||||
FixedUpdateEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveFixedUpdateListener(UnityAction fun)
|
||||
{
|
||||
FixedUpdateEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddUpdateListener(UnityAction fun)
|
||||
{
|
||||
UpdateEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveUpdateListener(UnityAction fun)
|
||||
{
|
||||
UpdateEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddDestroyListener(UnityAction fun)
|
||||
{
|
||||
DestroyEvent += fun;
|
||||
@ -385,16 +340,6 @@ namespace AlicizaX
|
||||
DestroyEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddOnDrawGizmosListener(UnityAction fun)
|
||||
{
|
||||
OnDrawGizmosEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveOnDrawGizmosListener(UnityAction fun)
|
||||
{
|
||||
OnDrawGizmosEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddOnApplicationPauseListener(UnityAction<bool> fun)
|
||||
{
|
||||
OnApplicationPauseEvent += fun;
|
||||
@ -418,10 +363,6 @@ namespace AlicizaX
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
UpdateEvent = null;
|
||||
FixedUpdateEvent = null;
|
||||
LateUpdateEvent = null;
|
||||
OnDrawGizmosEvent = null;
|
||||
DestroyEvent = null;
|
||||
OnApplicationPauseEvent = null;
|
||||
OnApplicationQuitEvent = null;
|
||||
@ -439,6 +380,91 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class UtilityLoopService : ServiceBase, IServiceTickable, IServiceLateTickable, IServiceFixedTickable, IServiceGizmoDrawable
|
||||
{
|
||||
private event UnityAction UpdateEvent;
|
||||
private event UnityAction FixedUpdateEvent;
|
||||
private event UnityAction LateUpdateEvent;
|
||||
private event UnityAction OnDrawGizmosEvent;
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnDestroyService()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void IServiceTickable.Tick(float deltaTime)
|
||||
{
|
||||
UpdateEvent?.Invoke();
|
||||
}
|
||||
|
||||
void IServiceLateTickable.LateTick(float deltaTime)
|
||||
{
|
||||
LateUpdateEvent?.Invoke();
|
||||
}
|
||||
|
||||
void IServiceFixedTickable.FixedTick(float fixedDeltaTime)
|
||||
{
|
||||
FixedUpdateEvent?.Invoke();
|
||||
}
|
||||
|
||||
void IServiceGizmoDrawable.DrawGizmos()
|
||||
{
|
||||
OnDrawGizmosEvent?.Invoke();
|
||||
}
|
||||
|
||||
public void AddUpdateListener(UnityAction fun)
|
||||
{
|
||||
UpdateEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveUpdateListener(UnityAction fun)
|
||||
{
|
||||
UpdateEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddFixedUpdateListener(UnityAction fun)
|
||||
{
|
||||
FixedUpdateEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveFixedUpdateListener(UnityAction fun)
|
||||
{
|
||||
FixedUpdateEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddLateUpdateListener(UnityAction fun)
|
||||
{
|
||||
LateUpdateEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveLateUpdateListener(UnityAction fun)
|
||||
{
|
||||
LateUpdateEvent -= fun;
|
||||
}
|
||||
|
||||
public void AddOnDrawGizmosListener(UnityAction fun)
|
||||
{
|
||||
OnDrawGizmosEvent += fun;
|
||||
}
|
||||
|
||||
public void RemoveOnDrawGizmosListener(UnityAction fun)
|
||||
{
|
||||
OnDrawGizmosEvent -= fun;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
UpdateEvent = null;
|
||||
FixedUpdateEvent = null;
|
||||
LateUpdateEvent = null;
|
||||
OnDrawGizmosEvent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
using AlicizaX;
|
||||
using AlicizaX;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
namespace AlicizaX.Audio.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 音效管理,为游戏提供统一的音效播放接口。
|
||||
/// 音效管理,为游戏提供统一的音效播放接口。
|
||||
/// </summary>
|
||||
/// <remarks>场景3D音效挂到场景物件、技能3D音效挂到技能特效上,并在AudioSource的Output上设置对应分类的AudioMixerGroup</remarks>
|
||||
/// <remarks>场景3D音效挂到场景物件、技能3D音效挂到技能特效上,并在AudioSource的Output上设置对应分类的AudioMixerGroup</remarks>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Game Framework/Audio")]
|
||||
public sealed class AudioComponent : MonoBehaviour
|
||||
@ -22,11 +22,11 @@ namespace AlicizaX.Audio.Runtime
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_audioService = AppServices.GetOrCreateScope<AppScope>().Register(new AudioService());
|
||||
_audioService = AppServices.App.Register(new AudioService());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化音频模块。
|
||||
/// 初始化音频模块。
|
||||
/// </summary>
|
||||
void Start()
|
||||
{
|
||||
@ -46,3 +46,4 @@ namespace AlicizaX.Audio.Runtime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ using Object = UnityEngine.Object;
|
||||
namespace AlicizaX.Debugger.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试器组件。
|
||||
/// 靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD>隞嗚<EFBFBD>?
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Game Framework/Debugger")]
|
||||
@ -28,17 +28,17 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认调试器漂浮框大小。
|
||||
/// 暺䁅恕靚<EFBFBD><EFBFBD><EFBFBD>冽<EFBFBD>瘚格<EFBFBD>憭批<EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
internal static readonly Rect DefaultIconRect = new Rect(10f, 10f, 60f, 60f);
|
||||
|
||||
/// <summary>
|
||||
/// 默认调试器窗口大小。
|
||||
/// 暺䁅恕靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD>之撠譌<EFBFBD>?
|
||||
/// </summary>
|
||||
internal static readonly Rect DefaultWindowRect = new Rect(10f, 10f, 640f, 480f);
|
||||
|
||||
/// <summary>
|
||||
/// 默认调试器窗口缩放比例。
|
||||
/// 暺䁅恕靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD>憬<EFBFBD>暹<EFBFBD>靘卝<EFBFBD>?
|
||||
/// </summary>
|
||||
internal static readonly float DefaultWindowScale = 1f;
|
||||
|
||||
@ -95,7 +95,7 @@ namespace AlicizaX.Debugger.Runtime
|
||||
private FpsCounter m_FpsCounter = null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置调试器窗口是否激活。
|
||||
/// <EFBFBD>瑕<EFBFBD><EFBFBD>𤥁挽蝵株<EFBFBD>霂訫膥蝒堒藁<EFBFBD>臬炏瞈<EFBFBD>瘣颯<EFBFBD>?
|
||||
/// </summary>
|
||||
public bool ActiveWindow
|
||||
{
|
||||
@ -108,7 +108,7 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否显示完整调试器界面。
|
||||
/// <EFBFBD>瑕<EFBFBD><EFBFBD>𤥁挽蝵格糓<EFBFBD>行遬蝷箏<EFBFBD><EFBFBD>渲<EFBFBD>霂訫膥<EFBFBD>屸𢒰<EFBFBD>?
|
||||
/// </summary>
|
||||
public bool ShowFullWindow
|
||||
{
|
||||
@ -117,7 +117,7 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置调试器漂浮框大小。
|
||||
/// <EFBFBD>瑕<EFBFBD><EFBFBD>𤥁挽蝵株<EFBFBD>霂訫膥瞍<EFBFBD>筑獢<EFBFBD>之撠譌<EFBFBD>?
|
||||
/// </summary>
|
||||
public Rect IconRect
|
||||
{
|
||||
@ -126,7 +126,7 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置调试器窗口大小。
|
||||
/// <EFBFBD>瑕<EFBFBD><EFBFBD>𤥁挽蝵株<EFBFBD>霂訫膥蝒堒藁憭批<EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
public Rect WindowRect
|
||||
{
|
||||
@ -135,7 +135,7 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置调试器窗口缩放比例。
|
||||
/// <EFBFBD>瑕<EFBFBD><EFBFBD>𤥁挽蝵株<EFBFBD>霂訫膥蝒堒藁蝻拇𦆮瘥𥪯<EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
public float WindowScale
|
||||
{
|
||||
@ -144,12 +144,12 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏框架组件初始化。
|
||||
/// 皜豢<EFBFBD>獢<EFBFBD>沲蝏<EFBFBD>辣<EFBFBD>嘥<EFBFBD><EFBFBD>硔<EFBFBD>?
|
||||
/// </summary>
|
||||
private void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
_mDebuggerService = AppServices.GetOrCreateScope<AppScope>().Register(new DebuggerService());
|
||||
_mDebuggerService = AppServices.App.Register(new DebuggerService());
|
||||
if (_mDebuggerService == null)
|
||||
{
|
||||
Log.Error("Debugger manager is invalid.");
|
||||
@ -256,48 +256,48 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册调试器窗口。
|
||||
/// 瘜典<EFBFBD>靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
/// <param name="path">调试器窗口路径。</param>
|
||||
/// <param name="debuggerWindow">要注册的调试器窗口。</param>
|
||||
/// <param name="args">初始化调试器窗口参数。</param>
|
||||
/// <param name="path">靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD>楝敺<EFBFBD><EFBFBD>?/param>
|
||||
/// <param name="debuggerWindow">閬<EFBFBD>釣<EFBFBD>𣬚<EFBFBD>靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?/param>
|
||||
/// <param name="args"><EFBFBD>嘥<EFBFBD><EFBFBD>𤥁<EFBFBD>霂訫膥蝒堒藁<EFBFBD><EFBFBD>㺭<EFBFBD>?/param>
|
||||
public void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args)
|
||||
{
|
||||
_mDebuggerService.RegisterDebuggerWindow(path, debuggerWindow, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解除注册调试器窗口。
|
||||
/// 閫<EFBFBD>膄瘜典<EFBFBD>靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
/// <param name="path">调试器窗口路径。</param>
|
||||
/// <returns>是否解除注册调试器窗口成功。</returns>
|
||||
/// <param name="path">靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD>楝敺<EFBFBD><EFBFBD>?/param>
|
||||
/// <returns><EFBFBD>臬炏閫<EFBFBD>膄瘜典<EFBFBD>靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>麄<EFBFBD>?/returns>
|
||||
public bool UnregisterDebuggerWindow(string path)
|
||||
{
|
||||
return _mDebuggerService.UnregisterDebuggerWindow(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取调试器窗口。
|
||||
/// <EFBFBD>瑕<EFBFBD>靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
/// <param name="path">调试器窗口路径。</param>
|
||||
/// <returns>要获取的调试器窗口。</returns>
|
||||
/// <param name="path">靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD>楝敺<EFBFBD><EFBFBD>?/param>
|
||||
/// <returns>閬<EFBFBD>繮<EFBFBD>𣇉<EFBFBD>靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?/returns>
|
||||
public IDebuggerWindow GetDebuggerWindow(string path)
|
||||
{
|
||||
return _mDebuggerService.GetDebuggerWindow(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中调试器窗口。
|
||||
/// <EFBFBD>劐葉靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
/// <param name="path">调试器窗口路径。</param>
|
||||
/// <returns>是否成功选中调试器窗口。</returns>
|
||||
/// <param name="path">靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD>楝敺<EFBFBD><EFBFBD>?/param>
|
||||
/// <returns><EFBFBD>臬炏<EFBFBD>𣂼<EFBFBD><EFBFBD>劐葉靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?/returns>
|
||||
public bool SelectDebuggerWindow(string path)
|
||||
{
|
||||
return _mDebuggerService.SelectDebuggerWindow(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 还原调试器窗口布局。
|
||||
/// 餈睃<EFBFBD>靚<EFBFBD><EFBFBD><EFBFBD>函<EFBFBD><EFBFBD><EFBFBD><EFBFBD>撅<EFBFBD><EFBFBD>?
|
||||
/// </summary>
|
||||
public void ResetLayout()
|
||||
{
|
||||
@ -307,19 +307,19 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取记录的所有日志。
|
||||
/// <EFBFBD>瑕<EFBFBD>霈啣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㗇𠯫敹𨰜<EFBFBD>?
|
||||
/// </summary>
|
||||
/// <param name="results">要获取的日志。</param>
|
||||
/// <param name="results">閬<EFBFBD>繮<EFBFBD>𣇉<EFBFBD><EFBFBD>亙<EFBFBD><EFBFBD>?/param>
|
||||
public void GetRecentLogs(List<LogNode> results)
|
||||
{
|
||||
m_ConsoleWindow.GetRecentLogs(results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取记录的最近日志。
|
||||
/// <EFBFBD>瑕<EFBFBD>霈啣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>餈烐𠯫敹𨰜<EFBFBD>?
|
||||
/// </summary>
|
||||
/// <param name="results">要获取的日志。</param>
|
||||
/// <param name="count">要获取最近日志的数量。</param>
|
||||
/// <param name="results">閬<EFBFBD>繮<EFBFBD>𣇉<EFBFBD><EFBFBD>亙<EFBFBD><EFBFBD>?/param>
|
||||
/// <param name="count">閬<EFBFBD>繮<EFBFBD>𡝗<EFBFBD>餈烐𠯫敹㛖<EFBFBD><EFBFBD>圈<EFBFBD><EFBFBD>?/param>
|
||||
public void GetRecentLogs(List<LogNode> results, int count)
|
||||
{
|
||||
m_ConsoleWindow.GetRecentLogs(results, count);
|
||||
@ -417,3 +417,4 @@ namespace AlicizaX.Debugger.Runtime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,36 +1,152 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using AlicizaX.Resource.Runtime;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Localization.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 本地化组件。
|
||||
/// ±¾µØ»¯×é¼þ¡£
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Game Framework/Localization")]
|
||||
public sealed class LocalizationComponent : MonoBehaviour
|
||||
{
|
||||
private const string DefaultLanguage = "ChineseSimplified";
|
||||
private const string RuntimeLanguagePrefsKey = "AlicizaX.Localization.Language";
|
||||
|
||||
private ILocalizationService _mLocalizationService = null;
|
||||
|
||||
public static string PrefsKey = Application.dataPath.GetHashCode() + "Language";
|
||||
|
||||
[SerializeField] private string _language;
|
||||
[SerializeField] private List<GameLocaizationTable> _startupTables = new();
|
||||
[SerializeField] private List<string> _startupTableLocations = new();
|
||||
[SerializeField] private string _resourcePackageName = string.Empty;
|
||||
|
||||
internal void SetLanguage(string language)
|
||||
{
|
||||
_language = language;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
internal static void SaveLanguagePreference(string language)
|
||||
{
|
||||
_mLocalizationService = AppServices.GetOrCreateScope<AppScope>().Register(new LocalizationService());
|
||||
if (string.IsNullOrEmpty(language))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorPrefs.SetString(PrefsKey, language);
|
||||
#endif
|
||||
PlayerPrefs.SetString(RuntimeLanguagePrefsKey, language);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
private static string LoadLanguagePreference(string fallbackLanguage)
|
||||
{
|
||||
string fallback = string.IsNullOrEmpty(fallbackLanguage) ? DefaultLanguage : fallbackLanguage;
|
||||
string language = PlayerPrefs.GetString(RuntimeLanguagePrefsKey, fallback);
|
||||
#if UNITY_EDITOR
|
||||
language = UnityEditor.EditorPrefs.GetString(PrefsKey, language);
|
||||
#endif
|
||||
return string.IsNullOrEmpty(language) ? fallback : language;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (!AppServices.App.TryGet<ILocalizationService>(out _mLocalizationService))
|
||||
{
|
||||
_mLocalizationService = AppServices.App.Register(new LocalizationService());
|
||||
}
|
||||
|
||||
if (_mLocalizationService == null)
|
||||
{
|
||||
Log.Info("Localization manager is invalid.");
|
||||
return;
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
_language = UnityEditor.EditorPrefs.GetString(LocalizationComponent.PrefsKey, "None");
|
||||
#endif
|
||||
|
||||
_language = LoadLanguagePreference(_language);
|
||||
_mLocalizationService.Initialize(_language);
|
||||
ApplyStartupTables(_startupTables);
|
||||
|
||||
if (_startupTableLocations != null && _startupTableLocations.Count > 0)
|
||||
{
|
||||
LoadStartupTablesAsync().Forget();
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyStartupTables(List<GameLocaizationTable> tables)
|
||||
{
|
||||
if (tables == null || tables.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool applied = false;
|
||||
for (int i = 0; i < tables.Count; i++)
|
||||
{
|
||||
GameLocaizationTable table = tables[i];
|
||||
if (table == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!applied)
|
||||
{
|
||||
_mLocalizationService.CoverAddLocalizationConfig(table);
|
||||
applied = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
_mLocalizationService.IncreAddLocalizationConfig(table);
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTaskVoid LoadStartupTablesAsync()
|
||||
{
|
||||
if (!AppServices.TryGet<IResourceService>(out var resourceService))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<GameLocaizationTable> loadedTables = new(_startupTableLocations.Count);
|
||||
for (int i = 0; i < _startupTableLocations.Count; i++)
|
||||
{
|
||||
string location = _startupTableLocations[i];
|
||||
if (string.IsNullOrEmpty(location))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameLocaizationTable table = await resourceService.LoadAssetAsync<GameLocaizationTable>(location, default, _resourcePackageName);
|
||||
if (table != null)
|
||||
{
|
||||
loadedTables.Add(table);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedTables.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_startupTables == null)
|
||||
{
|
||||
_startupTables = new List<GameLocaizationTable>(loadedTables.Count);
|
||||
}
|
||||
|
||||
for (int i = 0; i < loadedTables.Count; i++)
|
||||
{
|
||||
GameLocaizationTable table = loadedTables[i];
|
||||
if (_startupTables.Contains(table))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_startupTables.Add(table);
|
||||
_mLocalizationService.IncreAddLocalizationConfig(table);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace AlicizaX.Localization
|
||||
{
|
||||
@ -45,9 +43,53 @@ namespace AlicizaX.Localization
|
||||
#endif
|
||||
public List<LocalizationLanguage> Languages = new();
|
||||
|
||||
[NonSerialized] private Dictionary<string, LocalizationLanguage> _languageMap;
|
||||
[NonSerialized] private int _languageMapVersion = -1;
|
||||
|
||||
internal LocalizationLanguage GetLanguage(string languageCode)
|
||||
{
|
||||
return Languages.Find(t => t.LanguageName == languageCode);
|
||||
if (string.IsNullOrEmpty(languageCode) || Languages == null || Languages.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
EnsureLanguageMap();
|
||||
_languageMap.TryGetValue(languageCode, out LocalizationLanguage language);
|
||||
return language;
|
||||
}
|
||||
|
||||
public void InvalidateLanguageLookup()
|
||||
{
|
||||
_languageMapVersion = -1;
|
||||
}
|
||||
|
||||
private void EnsureLanguageMap()
|
||||
{
|
||||
int count = Languages?.Count ?? 0;
|
||||
if (_languageMap != null && _languageMapVersion == count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_languageMap ??= new Dictionary<string, LocalizationLanguage>(count, StringComparer.Ordinal);
|
||||
_languageMap.Clear();
|
||||
|
||||
if (Languages != null)
|
||||
{
|
||||
for (int i = 0; i < Languages.Count; i++)
|
||||
{
|
||||
LocalizationLanguage language = Languages[i];
|
||||
if (language == null || string.IsNullOrEmpty(language.LanguageName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_languageMap[language.LanguageName] = language;
|
||||
}
|
||||
}
|
||||
|
||||
_languageMapVersion = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,437 +1,447 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using AlicizaX;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace AlicizaX.Localization.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 本地化管理器接口。
|
||||
/// 本地化管理器接口。
|
||||
/// </summary>
|
||||
public interface ILocalizationService : IService
|
||||
{
|
||||
public string Language { get; }
|
||||
|
||||
void Initialize(string language);
|
||||
bool TryGetRawString(string key, out string value);
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString(string key);
|
||||
|
||||
void ChangedLanguage(string language);
|
||||
UniTask SwitchLanguageAsync(string language, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">字典参数的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="args">字典参数列表。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T">字典参数的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="args">字典参数列表。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString(string key, params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">字典参数的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg">字典参数。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T">字典参数的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg">字典参数。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T>(string key, T arg);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2>(string key, T1 arg1, T2 arg2);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3>(string key, T1 arg1, T2 arg2, T3 arg3);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <typeparam name="T14">字典参数 14 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <param name="arg14">字典参数 14。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <typeparam name="T14">字典参数 14 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <param name="arg14">字典参数 14。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <typeparam name="T14">字典参数 14 的类型。</typeparam>
|
||||
/// <typeparam name="T15">字典参数 15 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <param name="arg14">字典参数 14。</param>
|
||||
/// <param name="arg15">字典参数 15。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <typeparam name="T14">字典参数 14 的类型。</typeparam>
|
||||
/// <typeparam name="T15">字典参数 15 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <param name="arg14">字典参数 14。</param>
|
||||
/// <param name="arg15">字典参数 15。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// 根据字典主键获取字典内容字符串。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <typeparam name="T14">字典参数 14 的类型。</typeparam>
|
||||
/// <typeparam name="T15">字典参数 15 的类型。</typeparam>
|
||||
/// <typeparam name="T16">字典参数 16 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <param name="arg14">字典参数 14。</param>
|
||||
/// <param name="arg15">字典参数 15。</param>
|
||||
/// <param name="arg16">字典参数 16。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
/// <typeparam name="T1">字典参数 1 的类型。</typeparam>
|
||||
/// <typeparam name="T2">字典参数 2 的类型。</typeparam>
|
||||
/// <typeparam name="T3">字典参数 3 的类型。</typeparam>
|
||||
/// <typeparam name="T4">字典参数 4 的类型。</typeparam>
|
||||
/// <typeparam name="T5">字典参数 5 的类型。</typeparam>
|
||||
/// <typeparam name="T6">字典参数 6 的类型。</typeparam>
|
||||
/// <typeparam name="T7">字典参数 7 的类型。</typeparam>
|
||||
/// <typeparam name="T8">字典参数 8 的类型。</typeparam>
|
||||
/// <typeparam name="T9">字典参数 9 的类型。</typeparam>
|
||||
/// <typeparam name="T10">字典参数 10 的类型。</typeparam>
|
||||
/// <typeparam name="T11">字典参数 11 的类型。</typeparam>
|
||||
/// <typeparam name="T12">字典参数 12 的类型。</typeparam>
|
||||
/// <typeparam name="T13">字典参数 13 的类型。</typeparam>
|
||||
/// <typeparam name="T14">字典参数 14 的类型。</typeparam>
|
||||
/// <typeparam name="T15">字典参数 15 的类型。</typeparam>
|
||||
/// <typeparam name="T16">字典参数 16 的类型。</typeparam>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <param name="arg1">字典参数 1。</param>
|
||||
/// <param name="arg2">字典参数 2。</param>
|
||||
/// <param name="arg3">字典参数 3。</param>
|
||||
/// <param name="arg4">字典参数 4。</param>
|
||||
/// <param name="arg5">字典参数 5。</param>
|
||||
/// <param name="arg6">字典参数 6。</param>
|
||||
/// <param name="arg7">字典参数 7。</param>
|
||||
/// <param name="arg8">字典参数 8。</param>
|
||||
/// <param name="arg9">字典参数 9。</param>
|
||||
/// <param name="arg10">字典参数 10。</param>
|
||||
/// <param name="arg11">字典参数 11。</param>
|
||||
/// <param name="arg12">字典参数 12。</param>
|
||||
/// <param name="arg13">字典参数 13。</param>
|
||||
/// <param name="arg14">字典参数 14。</param>
|
||||
/// <param name="arg15">字典参数 15。</param>
|
||||
/// <param name="arg16">字典参数 16。</param>
|
||||
/// <returns>要获取的字典内容字符串。</returns>
|
||||
string GetString<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据字典主键获取字典值。
|
||||
/// 根据字典主键获取字典值。
|
||||
/// </summary>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <returns>字典值。</returns>
|
||||
/// <param name="key">字典主键。</param>
|
||||
/// <returns>字典值。</returns>
|
||||
string GetRawString(string key);
|
||||
|
||||
/// <summary>
|
||||
/// 增量增加多语言配置
|
||||
/// 增量增加多语言配置
|
||||
/// </summary>
|
||||
/// <param name="table"></param>
|
||||
void IncreAddLocalizationConfig(GameLocaizationTable table);
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖增加多语言配置
|
||||
/// 覆盖增加多语言配置
|
||||
/// </summary>
|
||||
/// <param name="table"></param>
|
||||
void CoverAddLocalizationConfig(GameLocaizationTable table);
|
||||
|
||||
/// <summary>
|
||||
/// 重新加载指定多语言表当前语言的数据。
|
||||
/// </summary>
|
||||
/// <param name="table">目标多语言表。</param>
|
||||
void ReloadLocalizationConfig(GameLocaizationTable table);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,11 +3,25 @@ using System.Collections.Generic;
|
||||
|
||||
namespace AlicizaX
|
||||
{
|
||||
public interface IProcedureService:IService, IServiceTickable
|
||||
public interface IProcedureService : IService, IServiceTickable
|
||||
{
|
||||
void InitializeProcedure(List<IProcedure> availableProcedures, Type defaultProcedureType);
|
||||
Type CurrentProcedureType { get; }
|
||||
void InitializeProcedure(IEnumerable<IProcedure> availableProcedures, Type defaultProcedureType);
|
||||
void ClearAllProcedures();
|
||||
bool SwitchProcedure<T>() where T : IProcedure;
|
||||
bool SwitchProcedure(Type procedureType);
|
||||
bool ContainsProcedure(Type procedureType);
|
||||
bool TrySwitchProcedure(Type procedureType);
|
||||
}
|
||||
|
||||
public static class ProcedureServiceExtensions
|
||||
{
|
||||
public static bool SwitchProcedure<T>(this IProcedureService procedureService) where T : IProcedure
|
||||
{
|
||||
return procedureService.TrySwitchProcedure(typeof(T));
|
||||
}
|
||||
|
||||
public static bool SwitchProcedure(this IProcedureService procedureService, Type procedureType)
|
||||
{
|
||||
return procedureService.TrySwitchProcedure(procedureType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,8 @@ namespace AlicizaX
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
AppServices.GetOrCreateScope<AppScope>().Register(new ProcedureService());
|
||||
AppServices.App.Register(new ProcedureService());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,113 +10,83 @@ namespace AlicizaX
|
||||
private IProcedure _currentProcedure;
|
||||
private IProcedure _defaultProcedure;
|
||||
|
||||
public Type CurrentProcedureType => _currentProcedure?.GetType();
|
||||
|
||||
public void InitializeProcedure(List<IProcedure> availableProcedures, Type defaultProcedureType)
|
||||
public void InitializeProcedure(IEnumerable<IProcedure> availableProcedures, Type defaultProcedureType)
|
||||
{
|
||||
_procedures.Clear();
|
||||
foreach (var procedure in availableProcedures)
|
||||
{
|
||||
if (procedure == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var type = procedure.GetType();
|
||||
_procedures[type] = procedure;
|
||||
procedure.ProcedureService = this;
|
||||
procedure.Init();
|
||||
}
|
||||
|
||||
if (_procedures.ContainsKey(defaultProcedureType))
|
||||
if (_procedures.TryGetValue(defaultProcedureType, out var defaultProcedure))
|
||||
{
|
||||
_defaultProcedure = _procedures[defaultProcedureType];
|
||||
SwitchProcedure(defaultProcedureType);
|
||||
_defaultProcedure = defaultProcedure;
|
||||
TrySwitchProcedure(defaultProcedureType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info($"默认流程 {defaultProcedureType.Name} 未注册!");
|
||||
Log.Info($"榛樿娴佺▼ {defaultProcedureType.Name} 鏈敞鍐?");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// 清除所有流程
|
||||
/// </summary>
|
||||
public void ClearAllProcedures()
|
||||
{
|
||||
if (_procedures != null)
|
||||
foreach (var procedure in _procedures.Values)
|
||||
{
|
||||
foreach (var procedure in _procedures.Values)
|
||||
{
|
||||
procedure.Destroy();
|
||||
}
|
||||
|
||||
_procedures.Clear();
|
||||
procedure.Destroy();
|
||||
}
|
||||
|
||||
_procedures.Clear();
|
||||
_currentProcedure = null;
|
||||
_defaultProcedure = null;
|
||||
}
|
||||
|
||||
public bool SwitchProcedure<T>() where T : IProcedure
|
||||
public bool ContainsProcedure(Type procedureType)
|
||||
{
|
||||
if (HasProcedure<T>())
|
||||
{
|
||||
return SwitchProcedure(typeof(T));
|
||||
}
|
||||
|
||||
if (_defaultProcedure != null)
|
||||
{
|
||||
Debug.LogWarning($"流程 {typeof(T).Name} 不存在,切换到默认流程");
|
||||
return SwitchToDefault();
|
||||
}
|
||||
|
||||
return false;
|
||||
return procedureType != null && _procedures.ContainsKey(procedureType);
|
||||
}
|
||||
|
||||
|
||||
public bool SwitchProcedure(Type procedureType)
|
||||
public bool TrySwitchProcedure(Type procedureType)
|
||||
{
|
||||
var nextProcedure = _procedures[procedureType];
|
||||
var lastProcedure = _currentProcedure;
|
||||
|
||||
if (lastProcedure == nextProcedure)
|
||||
return true;
|
||||
|
||||
if (lastProcedure != null)
|
||||
if (procedureType == null)
|
||||
{
|
||||
lastProcedure.Leave();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_procedures.TryGetValue(procedureType, out var nextProcedure))
|
||||
{
|
||||
if (_defaultProcedure == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"娴佺▼ {procedureType.Name} 涓嶅瓨鍦紝鍒囨崲鍒伴粯璁ゆ祦绋?");
|
||||
nextProcedure = _defaultProcedure;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(_currentProcedure, nextProcedure))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_currentProcedure?.Leave();
|
||||
nextProcedure.Enter();
|
||||
_currentProcedure = nextProcedure;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 切换到默认流程
|
||||
/// </summary>
|
||||
private bool SwitchToDefault()
|
||||
{
|
||||
if (_defaultProcedure != null)
|
||||
{
|
||||
return SwitchProcedure(_defaultProcedure.GetType());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在指定类型的流程
|
||||
/// </summary>
|
||||
private bool HasProcedure<T>() where T : IProcedure
|
||||
{
|
||||
return _procedures.ContainsKey(typeof(T));
|
||||
}
|
||||
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void OnDestroyService()
|
||||
@ -126,10 +96,7 @@ namespace AlicizaX
|
||||
|
||||
void IServiceTickable.Tick(float deltaTime)
|
||||
{
|
||||
if (_currentProcedure != null)
|
||||
{
|
||||
_currentProcedure.Update();
|
||||
}
|
||||
_currentProcedure?.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTaskVoid SetAssetByResources<T>(ISetAssetObject setAssetObject, CancellationToken cancellationToken) where T : UnityEngine.Object
|
||||
public async UniTask SetAssetByResources<T>(ISetAssetObject setAssetObject, CancellationToken cancellationToken) where T : UnityEngine.Object
|
||||
{
|
||||
var target = setAssetObject.TargetObject;
|
||||
var location = setAssetObject.Location;
|
||||
@ -176,6 +176,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
UnityEngine.Application.lowMemory -= OnLowMemory;
|
||||
ReleaseTrackedAssets();
|
||||
|
||||
foreach (var state in _loadingStates.Values)
|
||||
@ -186,4 +187,4 @@ namespace AlicizaX.Resource.Runtime
|
||||
_loadingStates.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,8 +23,6 @@ namespace AlicizaX.Resource.Runtime
|
||||
[SerializeField]
|
||||
private float checkCanReleaseInterval = 30f;
|
||||
|
||||
private float _checkCanReleaseTime = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// 对象池自动释放时间间隔。
|
||||
/// </summary>
|
||||
@ -37,6 +35,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
[SerializeField]
|
||||
private int maxProcessPerFrame = 50;
|
||||
|
||||
[SerializeField]
|
||||
private int releaseCheckThreshold = 16;
|
||||
|
||||
/// <summary>
|
||||
/// 当前正在处理的节点,用于分帧处理。
|
||||
/// </summary>
|
||||
@ -48,6 +49,8 @@ namespace AlicizaX.Resource.Runtime
|
||||
private LinkedList<LoadAssetObject> _loadAssetObjectsLinkedList;
|
||||
|
||||
private Dictionary<Object, LinkedListNode<LoadAssetObject>> _trackedAssetNodes;
|
||||
private bool _releaseRequested;
|
||||
private float _nextReleaseCheckTime = float.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// 散图集合对象池。
|
||||
@ -65,11 +68,18 @@ namespace AlicizaX.Resource.Runtime
|
||||
private IEnumerator Start()
|
||||
{
|
||||
Instance = this;
|
||||
enabled = false;
|
||||
Application.lowMemory += OnLowMemory;
|
||||
yield return new WaitForEndOfFrame();
|
||||
IObjectPoolService objectPoolComponent = AppServices.Require<IObjectPoolService>();
|
||||
_assetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool<AssetItemObject>(
|
||||
"SetAssetPool",
|
||||
autoReleaseInterval, 16, 60, 0);
|
||||
_assetItemPool = objectPoolComponent.CreatePool<AssetItemObject>(
|
||||
new ObjectPoolCreateOptions(
|
||||
name: "SetAssetPool",
|
||||
allowMultiSpawn: true,
|
||||
autoReleaseInterval: autoReleaseInterval,
|
||||
capacity: 16,
|
||||
expireTime: 60,
|
||||
priority: 0));
|
||||
_loadAssetObjectsLinkedList = new LinkedList<LoadAssetObject>();
|
||||
_trackedAssetNodes = new Dictionary<Object, LinkedListNode<LoadAssetObject>>(16);
|
||||
|
||||
@ -78,8 +88,13 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
private void Update()
|
||||
{
|
||||
_checkCanReleaseTime += Time.unscaledDeltaTime;
|
||||
if (_checkCanReleaseTime < (double)checkCanReleaseInterval)
|
||||
if (!_releaseRequested)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Time.unscaledTime < _nextReleaseCheckTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -96,7 +111,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
if (_loadAssetObjectsLinkedList == null || _loadAssetObjectsLinkedList.Count == 0)
|
||||
{
|
||||
_currentProcessNode = null;
|
||||
_checkCanReleaseTime = 0f;
|
||||
_releaseRequested = false;
|
||||
_nextReleaseCheckTime = float.MaxValue;
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -129,7 +146,13 @@ namespace AlicizaX.Resource.Runtime
|
||||
// 如果已经处理完所有节点,重置状态
|
||||
if (_currentProcessNode == null)
|
||||
{
|
||||
_checkCanReleaseTime = 0f;
|
||||
_releaseRequested = false;
|
||||
_nextReleaseCheckTime = float.MaxValue;
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScheduleReleaseSweep(checkCanReleaseInterval);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,6 +167,10 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
setAssetObject.SetAsset(assetObject);
|
||||
if (_loadAssetObjectsLinkedList.Count >= releaseCheckThreshold)
|
||||
{
|
||||
ScheduleReleaseSweep();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReplaceTrackedAsset(Object target)
|
||||
@ -188,6 +215,10 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
_loadAssetObjectsLinkedList?.Remove(node);
|
||||
if (_loadAssetObjectsLinkedList != null && _loadAssetObjectsLinkedList.Count > 0)
|
||||
{
|
||||
ScheduleReleaseSweep(checkCanReleaseInterval);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseTrackedAssets()
|
||||
@ -207,6 +238,22 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
_currentProcessNode = null;
|
||||
_trackedAssetNodes?.Clear();
|
||||
_releaseRequested = false;
|
||||
_nextReleaseCheckTime = float.MaxValue;
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
private void ScheduleReleaseSweep(float delay = 0f)
|
||||
{
|
||||
_releaseRequested = true;
|
||||
float dueTime = Time.unscaledTime + Math.Max(0f, delay);
|
||||
_nextReleaseCheckTime = Math.Min(_nextReleaseCheckTime, dueTime);
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
private void OnLowMemory()
|
||||
{
|
||||
ScheduleReleaseSweep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="loadAssetCallbacks">加载资源回调函数集。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
/// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
|
||||
void LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "");
|
||||
UniTask LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "");
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载资源。
|
||||
@ -162,7 +162,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="loadAssetCallbacks">加载资源回调函数集。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
/// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
|
||||
void LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "");
|
||||
UniTask LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "");
|
||||
|
||||
/// <summary>
|
||||
/// 同步加载资源。
|
||||
@ -190,7 +190,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="callback">回调函数。</param>
|
||||
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
|
||||
/// <typeparam name="T">要加载资源的类型。</typeparam>
|
||||
UniTaskVoid LoadAsset<T>(string location, Action<T> callback, string packageName = "") where T : UnityEngine.Object;
|
||||
UniTask LoadAsset<T>(string location, Action<T> callback, string packageName = "") where T : UnityEngine.Object;
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载资源。
|
||||
|
||||
@ -7,7 +7,7 @@ using YooAsset;
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源组件。
|
||||
/// 资源组件<EFBFBD>?
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class ResourceComponent : MonoBehaviour
|
||||
@ -41,24 +41,24 @@ namespace AlicizaX.Resource.Runtime
|
||||
[SerializeField] private string decryptionServices = "";
|
||||
|
||||
/// <summary>
|
||||
/// 自动释放资源引用计数为0的资源包
|
||||
/// 自动释放资源引用计数<EFBFBD>?的资源包
|
||||
/// </summary>
|
||||
[SerializeField] public bool autoUnloadBundleWhenUnused = false;
|
||||
|
||||
[SerializeField] private EPlayMode _playMode = EPlayMode.EditorSimulateMode;
|
||||
|
||||
/// <summary>
|
||||
/// 当前最新的包裹版本。
|
||||
/// 当前最新的包裹版本<EFBFBD>?
|
||||
/// </summary>
|
||||
public string PackageVersion { set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源包名称。
|
||||
/// 资源包名称<EFBFBD>?
|
||||
/// </summary>
|
||||
[SerializeField] private string packageName = "DefaultPackage";
|
||||
|
||||
/// <summary>
|
||||
/// 资源包名称。
|
||||
/// 资源包名称<EFBFBD>?
|
||||
/// </summary>
|
||||
public string PackageName
|
||||
{
|
||||
@ -75,7 +75,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
public int downloadingMaxNum = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置同时最大下载数目。
|
||||
/// 获取或设置同时最大下载数目<EFBFBD>?
|
||||
/// </summary>
|
||||
public int DownloadingMaxNum
|
||||
{
|
||||
@ -92,17 +92,17 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前资源适用的游戏版本号。
|
||||
/// 获取当前资源适用的游戏版本号<EFBFBD>?
|
||||
/// </summary>
|
||||
public string ApplicableGameVersion => _resourceService.ApplicableGameVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前内部资源版本号。
|
||||
/// 获取当前内部资源版本号<EFBFBD>?
|
||||
/// </summary>
|
||||
public int InternalResourceVersion => _resourceService.InternalResourceVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置无用资源释放的最小间隔时间,以秒为单位。
|
||||
/// 获取或设置无用资源释放的最小间隔时间,以秒为单位<EFBFBD>?
|
||||
/// </summary>
|
||||
public float MinUnloadUnusedAssetsInterval
|
||||
{
|
||||
@ -111,7 +111,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置无用资源释放的最大间隔时间,以秒为单位。
|
||||
/// 获取或设置无用资源释放的最大间隔时间,以秒为单位<EFBFBD>?
|
||||
/// </summary>
|
||||
public float MaxUnloadUnusedAssetsInterval
|
||||
{
|
||||
@ -120,7 +120,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用系统释放无用资源策略。
|
||||
/// 使用系统释放无用资源策略<EFBFBD>?
|
||||
/// </summary>
|
||||
public bool UseSystemUnloadUnusedAssets
|
||||
{
|
||||
@ -129,7 +129,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取无用资源释放的等待时长,以秒为单位。
|
||||
/// 获取无用资源释放的等待时长,以秒为单位<EFBFBD>?
|
||||
/// </summary>
|
||||
public float LastUnloadUnusedAssetsOperationElapseSeconds => _lastUnloadUnusedAssetsOperationElapseSeconds;
|
||||
|
||||
@ -142,7 +142,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
[SerializeField] private int assetPriority = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置资源对象池自动释放可释放对象的间隔秒数。
|
||||
/// 获取或设置资源对象池自动释放可释放对象的间隔秒数<EFBFBD>?
|
||||
/// </summary>
|
||||
public float AssetAutoReleaseInterval
|
||||
{
|
||||
@ -151,7 +151,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置资源对象池的容量。
|
||||
/// 获取或设置资源对象池的容量<EFBFBD>?
|
||||
/// </summary>
|
||||
public int AssetCapacity
|
||||
{
|
||||
@ -160,7 +160,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置资源对象池对象过期秒数。
|
||||
/// 获取或设置资源对象池对象过期秒数<EFBFBD>?
|
||||
/// </summary>
|
||||
public float AssetExpireTime
|
||||
{
|
||||
@ -169,7 +169,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置资源对象池的优先级。
|
||||
/// 获取或设置资源对象池的优先级<EFBFBD>?
|
||||
/// </summary>
|
||||
public int AssetPriority
|
||||
{
|
||||
@ -191,7 +191,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_resourceService = AppServices.GetOrCreateScope<AppScope>().Register(new ResourceService());
|
||||
_resourceService = AppServices.App.Register(new ResourceService());
|
||||
|
||||
Application.lowMemory += OnLowMemory;
|
||||
}
|
||||
@ -227,9 +227,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
#region 释放资源
|
||||
|
||||
/// <summary>
|
||||
/// 强制执行释放未被使用的资源。
|
||||
/// 强制执行释放未被使用的资源<EFBFBD>?
|
||||
/// </summary>
|
||||
/// <param name="performGCCollect">是否使用垃圾回收。</param>
|
||||
/// <param name="performGCCollect">是否使用垃圾回收<EFBFBD>?/param>
|
||||
public void ForceUnloadUnusedAssets(bool performGCCollect)
|
||||
{
|
||||
_forceUnloadUnusedAssets = true;
|
||||
|
||||
@ -61,7 +61,8 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="objectPoolModule">对象池管理器。</param>
|
||||
public void CreateAssetPool( )
|
||||
{
|
||||
_assetPool = Context.Require<IObjectPoolService>().CreateMultiSpawnObjectPool<AssetObject>("Asset Pool");
|
||||
_assetPool = Context.Require<IObjectPoolService>().CreatePool<AssetObject>(
|
||||
ObjectPoolCreateOptions.Multi("Asset Pool"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -652,7 +652,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="callback">回调函数。</param>
|
||||
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
|
||||
/// <typeparam name="T">要加载资源的类型。</typeparam>
|
||||
public async UniTaskVoid LoadAsset<T>(string location, Action<T> callback, string packageName = "") where T : UnityEngine.Object
|
||||
public async UniTask LoadAsset<T>(string location, Action<T> callback, string packageName = "") where T : UnityEngine.Object
|
||||
{
|
||||
if (string.IsNullOrEmpty(location))
|
||||
{
|
||||
@ -730,7 +730,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="loadAssetCallbacks">加载资源回调函数集。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
/// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
|
||||
public async void LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")
|
||||
public async UniTask LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(location))
|
||||
{
|
||||
@ -800,7 +800,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="loadAssetCallbacks">加载资源回调函数集。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
/// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
|
||||
public async void LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")
|
||||
public async UniTask LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(location))
|
||||
{
|
||||
|
||||
@ -1,41 +1,17 @@
|
||||
using System;
|
||||
using AlicizaX.Resource.Runtime;
|
||||
using AlicizaX;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.SceneManagement;
|
||||
using YooAsset;
|
||||
|
||||
namespace AlicizaX.Scene.Runtime
|
||||
{
|
||||
public interface ISceneService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前主场景名称。
|
||||
/// </summary>
|
||||
public string CurrentMainSceneName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 加载场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景的定位地址</param>
|
||||
/// <param name="sceneMode">场景加载模式</param>
|
||||
/// <param name="suspendLoad">加载完毕时是否主动挂起</param>
|
||||
/// <param name="priority">优先级</param>
|
||||
/// <param name="gcCollect">加载主场景是否回收垃圾。</param>
|
||||
/// <param name="progressCallBack">加载进度回调。</param>
|
||||
public UniTask<UnityEngine.SceneManagement.Scene> LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, uint priority = 100, bool gcCollect = true,
|
||||
Action<float> progressCallBack = null);
|
||||
|
||||
/// <summary>
|
||||
/// 加载场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景的定位地址</param>
|
||||
/// <param name="sceneMode">场景加载模式</param>
|
||||
/// <param name="suspendLoad">加载完毕时是否主动挂起</param>
|
||||
/// <param name="priority">优先级</param>
|
||||
/// <param name="callBack">加载回调。</param>
|
||||
/// <param name="gcCollect">加载主场景是否回收垃圾。</param>
|
||||
/// <param name="progressCallBack">加载进度回调。</param>
|
||||
public void LoadScene(string location,
|
||||
LoadSceneMode sceneMode = LoadSceneMode.Single,
|
||||
bool suspendLoad = false,
|
||||
@ -44,47 +20,25 @@ namespace AlicizaX.Scene.Runtime
|
||||
bool gcCollect = true,
|
||||
Action<float> progressCallBack = null);
|
||||
|
||||
/// <summary>
|
||||
/// 激活场景(当同时存在多个场景时用于切换激活场景)。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否操作成功。</returns>
|
||||
public bool ActivateScene(string location);
|
||||
|
||||
/// <summary>
|
||||
/// 解除场景加载挂起操作。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否操作成功。</returns>
|
||||
public bool UnSuspend(string location);
|
||||
|
||||
/// <summary>
|
||||
/// 是否为主场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否主场景。</returns>
|
||||
public bool IsMainScene(string location);
|
||||
|
||||
/// <summary>
|
||||
/// 异步卸载子场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <param name="progressCallBack">进度回调。</param>
|
||||
public UniTask<bool> UnloadAsync(string location, Action<float> progressCallBack = null);
|
||||
|
||||
/// <summary>
|
||||
/// 异步卸载子场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <param name="callBack">卸载完成回调。</param>
|
||||
/// <param name="progressCallBack">进度回调。</param>
|
||||
public void Unload(string location, Action callBack = null, Action<float> progressCallBack = null);
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否包含场景。</returns>
|
||||
public bool IsContainScene(string location);
|
||||
}
|
||||
|
||||
public interface ISceneStateService : IService
|
||||
{
|
||||
public string CurrentMainSceneName { get; }
|
||||
|
||||
public bool IsContainScene(string location);
|
||||
|
||||
public bool IsMainScene(string location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using AlicizaX;
|
||||
using UnityEngine;
|
||||
|
||||
@ -10,7 +9,12 @@ namespace AlicizaX.Scene.Runtime
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
AppServices.GetOrCreateScope<AppScope>().Register(new SceneService());
|
||||
if (!AppServices.App.TryGet<ISceneService>(out _))
|
||||
{
|
||||
AppServices.App.Register(new SceneService());
|
||||
}
|
||||
|
||||
AppServices.EnsureScene();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,56 +9,22 @@ namespace AlicizaX.Scene.Runtime
|
||||
{
|
||||
internal class SceneService : ServiceBase, ISceneService
|
||||
{
|
||||
private string _currentMainSceneName = string.Empty;
|
||||
|
||||
private SceneHandle _currentMainScene;
|
||||
|
||||
private readonly Dictionary<string, SceneHandle> _subScenes = new Dictionary<string, SceneHandle>();
|
||||
|
||||
private readonly HashSet<string> _handlingScene = new HashSet<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 当前主场景名称。
|
||||
/// </summary>
|
||||
public string CurrentMainSceneName => _currentMainSceneName;
|
||||
public string CurrentMainSceneName => EnsureSceneState().CurrentMainSceneName;
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
_currentMainScene = null;
|
||||
_currentMainSceneName = SceneManager.GetSceneByBuildIndex(0).name;
|
||||
var activeScene = SceneManager.GetActiveScene();
|
||||
EnsureSceneState().SetBootScene(activeScene.name);
|
||||
}
|
||||
|
||||
protected override void OnDestroyService()
|
||||
{
|
||||
var iter = _subScenes.Values.GetEnumerator();
|
||||
while (iter.MoveNext())
|
||||
{
|
||||
SceneHandle subScene = iter.Current;
|
||||
if (subScene != null)
|
||||
{
|
||||
subScene.UnloadAsync();
|
||||
}
|
||||
}
|
||||
|
||||
iter.Dispose();
|
||||
_subScenes.Clear();
|
||||
_handlingScene.Clear();
|
||||
_currentMainSceneName = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景的定位地址</param>
|
||||
/// <param name="sceneMode">场景加载模式</param>
|
||||
/// <param name="suspendLoad">加载完毕时是否主动挂起</param>
|
||||
/// <param name="priority">优先级</param>
|
||||
/// <param name="gcCollect">加载主场景是否回收垃圾。</param>
|
||||
/// <param name="progressCallBack">加载进度回调。</param>
|
||||
public async UniTask<UnityEngine.SceneManagement.Scene> LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, uint priority = 100, bool gcCollect = true, Action<float> progressCallBack = null)
|
||||
{
|
||||
if (!_handlingScene.Add(location))
|
||||
var sceneState = EnsureSceneState();
|
||||
if (!sceneState.TryBeginHandling(location))
|
||||
{
|
||||
Log.Error($"Could not load scene while loading. Scene: {location}");
|
||||
return default;
|
||||
@ -66,15 +32,13 @@ namespace AlicizaX.Scene.Runtime
|
||||
|
||||
if (sceneMode == LoadSceneMode.Additive)
|
||||
{
|
||||
if (_subScenes.TryGetValue(location, out SceneHandle subScene))
|
||||
if (sceneState.TryGetSubScene(location, out SceneHandle loadedSubScene))
|
||||
{
|
||||
throw new Exception($"Could not load subScene while already loaded. Scene: {location}");
|
||||
}
|
||||
|
||||
subScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
|
||||
//Fix 这里前置,subScene.IsDone在UnSupendLoad之后才会是true
|
||||
_subScenes.Add(location, subScene);
|
||||
var subScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
sceneState.AddSubScene(location, subScene);
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
@ -89,57 +53,43 @@ namespace AlicizaX.Scene.Runtime
|
||||
await subScene.ToUniTask();
|
||||
}
|
||||
|
||||
_handlingScene.Remove(location);
|
||||
|
||||
sceneState.EndHandling(location);
|
||||
return subScene.SceneObject;
|
||||
}
|
||||
|
||||
if (sceneState.CurrentMainSceneHandle is { IsDone: false })
|
||||
{
|
||||
throw new Exception($"Could not load MainScene while loading. CurrentMainScene: {sceneState.CurrentMainSceneName}.");
|
||||
}
|
||||
|
||||
sceneState = PrepareSceneStateForMainSceneLoad(location);
|
||||
var mainSceneHandle = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
while (!mainSceneHandle.IsDone && mainSceneHandle.IsValid)
|
||||
{
|
||||
progressCallBack.Invoke(mainSceneHandle.Progress);
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentMainScene is { IsDone: false })
|
||||
{
|
||||
throw new Exception($"Could not load MainScene while loading. CurrentMainScene: {_currentMainSceneName}.");
|
||||
}
|
||||
|
||||
_currentMainSceneName = location;
|
||||
|
||||
_currentMainScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
while (!_currentMainScene.IsDone && _currentMainScene.IsValid)
|
||||
{
|
||||
progressCallBack.Invoke(_currentMainScene.Progress);
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await _currentMainScene.ToUniTask();
|
||||
}
|
||||
|
||||
Context.Require<IResourceService>().ForceUnloadUnusedAssets(gcCollect);
|
||||
|
||||
_handlingScene.Remove(location);
|
||||
|
||||
return _currentMainScene.SceneObject;
|
||||
await mainSceneHandle.ToUniTask();
|
||||
}
|
||||
|
||||
sceneState.SetMainScene(location, mainSceneHandle);
|
||||
Context.Require<IResourceService>().ForceUnloadUnusedAssets(gcCollect);
|
||||
sceneState.EndHandling(location);
|
||||
return mainSceneHandle.SceneObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景的定位地址</param>
|
||||
/// <param name="sceneMode">场景加载模式</param>
|
||||
/// <param name="suspendLoad">加载完毕时是否主动挂起</param>
|
||||
/// <param name="priority">优先级</param>
|
||||
/// <param name="callBack">加载回调。</param>
|
||||
/// <param name="gcCollect">加载主场景是否回收垃圾。</param>
|
||||
/// <param name="progressCallBack">加载进度回调。</param>
|
||||
public void LoadScene(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, uint priority = 100,
|
||||
Action<UnityEngine.SceneManagement.Scene> callBack = null,
|
||||
bool gcCollect = true, Action<float> progressCallBack = null)
|
||||
{
|
||||
if (!_handlingScene.Add(location))
|
||||
var sceneState = EnsureSceneState();
|
||||
if (!sceneState.TryBeginHandling(location))
|
||||
{
|
||||
Log.Error($"Could not load scene while loading. Scene: {location}");
|
||||
return;
|
||||
@ -147,88 +97,60 @@ namespace AlicizaX.Scene.Runtime
|
||||
|
||||
if (sceneMode == LoadSceneMode.Additive)
|
||||
{
|
||||
if (_subScenes.TryGetValue(location, out SceneHandle subScene))
|
||||
if (sceneState.TryGetSubScene(location, out SceneHandle loadedSubScene))
|
||||
{
|
||||
Log.Warning($"Could not load subScene while already loaded. Scene: {location}");
|
||||
return;
|
||||
}
|
||||
|
||||
subScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
|
||||
var subScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
sceneState.AddSubScene(location, subScene);
|
||||
subScene.Completed += handle =>
|
||||
{
|
||||
_handlingScene.Remove(location);
|
||||
sceneState.EndHandling(location);
|
||||
callBack?.Invoke(handle.SceneObject);
|
||||
};
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
InvokeProgress(subScene, progressCallBack).Forget();
|
||||
InvokeSceneProgress(subScene, progressCallBack).Forget();
|
||||
}
|
||||
|
||||
_subScenes.Add(location, subScene);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentMainScene is { IsDone: false })
|
||||
{
|
||||
Log.Warning($"Could not load MainScene while loading. CurrentMainScene: {_currentMainSceneName}.");
|
||||
return;
|
||||
}
|
||||
|
||||
_currentMainSceneName = location;
|
||||
|
||||
_currentMainScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
|
||||
_currentMainScene.Completed += handle =>
|
||||
{
|
||||
_handlingScene.Remove(location);
|
||||
callBack?.Invoke(handle.SceneObject);
|
||||
};
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
InvokeProgress(_currentMainScene, progressCallBack).Forget();
|
||||
}
|
||||
|
||||
Context.Require<IResourceService>().ForceUnloadUnusedAssets(gcCollect);
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTaskVoid InvokeProgress(SceneHandle sceneHandle, Action<float> progress)
|
||||
{
|
||||
if (sceneHandle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (!sceneHandle.IsDone && sceneHandle.IsValid)
|
||||
if (sceneState.CurrentMainSceneHandle is { IsDone: false })
|
||||
{
|
||||
await UniTask.Yield();
|
||||
|
||||
progress?.Invoke(sceneHandle.Progress);
|
||||
Log.Warning($"Could not load MainScene while loading. CurrentMainScene: {sceneState.CurrentMainSceneName}.");
|
||||
return;
|
||||
}
|
||||
|
||||
sceneState = PrepareSceneStateForMainSceneLoad(location);
|
||||
var mainSceneHandle = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
|
||||
mainSceneHandle.Completed += handle =>
|
||||
{
|
||||
sceneState.SetMainScene(location, handle);
|
||||
sceneState.EndHandling(location);
|
||||
callBack?.Invoke(handle.SceneObject);
|
||||
};
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
InvokeSceneProgress(mainSceneHandle, progressCallBack).Forget();
|
||||
}
|
||||
|
||||
Context.Require<IResourceService>().ForceUnloadUnusedAssets(gcCollect);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激活场景(当同时存在多个场景时用于切换激活场景)。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否操作成功。</returns>
|
||||
public bool ActivateScene(string location)
|
||||
{
|
||||
if (_currentMainSceneName.Equals(location))
|
||||
var sceneState = EnsureSceneState();
|
||||
if (sceneState.CurrentMainSceneName.Equals(location))
|
||||
{
|
||||
if (_currentMainScene != null)
|
||||
{
|
||||
return _currentMainScene.ActivateScene();
|
||||
}
|
||||
|
||||
return false;
|
||||
return sceneState.CurrentMainSceneHandle != null && sceneState.CurrentMainSceneHandle.ActivateScene();
|
||||
}
|
||||
|
||||
_subScenes.TryGetValue(location, out SceneHandle subScene);
|
||||
if (subScene != null)
|
||||
if (sceneState.TryGetSubScene(location, out var subScene) && subScene != null)
|
||||
{
|
||||
return subScene.ActivateScene();
|
||||
}
|
||||
@ -237,25 +159,16 @@ namespace AlicizaX.Scene.Runtime
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解除场景加载挂起操作。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否操作成功。</returns>
|
||||
|
||||
public bool UnSuspend(string location)
|
||||
{
|
||||
if (_currentMainSceneName.Equals(location))
|
||||
var sceneState = EnsureSceneState();
|
||||
if (sceneState.CurrentMainSceneName.Equals(location))
|
||||
{
|
||||
if (_currentMainScene != null)
|
||||
{
|
||||
return _currentMainScene.UnSuspend();
|
||||
}
|
||||
|
||||
return false;
|
||||
return sceneState.CurrentMainSceneHandle != null && sceneState.CurrentMainSceneHandle.UnSuspend();
|
||||
}
|
||||
|
||||
_subScenes.TryGetValue(location, out SceneHandle subScene);
|
||||
if (subScene != null)
|
||||
if (sceneState.TryGetSubScene(location, out var subScene) && subScene != null)
|
||||
{
|
||||
return subScene.UnSuspend();
|
||||
}
|
||||
@ -264,34 +177,27 @@ namespace AlicizaX.Scene.Runtime
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否为主场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否主场景。</returns>
|
||||
public bool IsMainScene(string location)
|
||||
{
|
||||
// 获取当前激活的场景
|
||||
UnityEngine.SceneManagement.Scene currentScene = SceneManager.GetActiveScene();
|
||||
var sceneState = EnsureSceneState();
|
||||
var currentScene = SceneManager.GetActiveScene();
|
||||
|
||||
if (_currentMainSceneName.Equals(location))
|
||||
if (sceneState.CurrentMainSceneName.Equals(location))
|
||||
{
|
||||
if (_currentMainScene == null)
|
||||
if (sceneState.CurrentMainSceneHandle == null)
|
||||
{
|
||||
return false;
|
||||
return currentScene.name == location;
|
||||
}
|
||||
|
||||
// 判断当前场景是否是主场景
|
||||
if (currentScene.name == _currentMainScene.SceneName)
|
||||
if (currentScene.name == sceneState.CurrentMainSceneHandle.SceneName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return _currentMainScene.SceneName == currentScene.name;
|
||||
return sceneState.CurrentMainSceneHandle.SceneName == currentScene.name;
|
||||
}
|
||||
|
||||
// 判断当前场景是否是主场景
|
||||
if (currentScene.name == _currentMainScene?.SceneName)
|
||||
if (currentScene.name == sceneState.CurrentMainSceneHandle?.SceneName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -300,15 +206,10 @@ namespace AlicizaX.Scene.Runtime
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步卸载子场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <param name="progressCallBack">进度回调。</param>
|
||||
public async UniTask<bool> UnloadAsync(string location, Action<float> progressCallBack = null)
|
||||
{
|
||||
_subScenes.TryGetValue(location, out SceneHandle subScene);
|
||||
if (subScene != null)
|
||||
var sceneState = EnsureSceneState();
|
||||
if (sceneState.TryGetSubScene(location, out var subScene) && subScene != null)
|
||||
{
|
||||
if (subScene.SceneObject == default)
|
||||
{
|
||||
@ -316,14 +217,13 @@ namespace AlicizaX.Scene.Runtime
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_handlingScene.Add(location))
|
||||
if (!sceneState.TryBeginHandling(location))
|
||||
{
|
||||
Log.Warning($"Could not unload Scene while loading. Scene: {location}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var unloadOperation = subScene.UnloadAsync();
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
while (!unloadOperation.IsDone && unloadOperation.Status != EOperationStatus.Failed)
|
||||
@ -337,10 +237,8 @@ namespace AlicizaX.Scene.Runtime
|
||||
await unloadOperation.ToUniTask();
|
||||
}
|
||||
|
||||
_subScenes.Remove(location);
|
||||
|
||||
_handlingScene.Remove(location);
|
||||
|
||||
sceneState.RemoveSubScene(location);
|
||||
sceneState.EndHandling(location);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -348,16 +246,10 @@ namespace AlicizaX.Scene.Runtime
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步卸载子场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <param name="callBack">卸载完成回调。</param>
|
||||
/// <param name="progressCallBack">进度回调。</param>
|
||||
public void Unload(string location, Action callBack = null, Action<float> progressCallBack = null)
|
||||
{
|
||||
_subScenes.TryGetValue(location, out SceneHandle subScene);
|
||||
if (subScene != null)
|
||||
var sceneState = EnsureSceneState();
|
||||
if (sceneState.TryGetSubScene(location, out var subScene) && subScene != null)
|
||||
{
|
||||
if (subScene.SceneObject == default)
|
||||
{
|
||||
@ -365,23 +257,23 @@ namespace AlicizaX.Scene.Runtime
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_handlingScene.Add(location))
|
||||
if (!sceneState.TryBeginHandling(location))
|
||||
{
|
||||
Log.Warning($"Could not unload Scene while loading. Scene: {location}");
|
||||
return;
|
||||
}
|
||||
|
||||
subScene.UnloadAsync();
|
||||
subScene.UnloadAsync().Completed += @base =>
|
||||
var unloadOperation = subScene.UnloadAsync();
|
||||
unloadOperation.Completed += @base =>
|
||||
{
|
||||
_subScenes.Remove(location);
|
||||
_handlingScene.Remove(location);
|
||||
sceneState.RemoveSubScene(location);
|
||||
sceneState.EndHandling(location);
|
||||
callBack?.Invoke();
|
||||
};
|
||||
|
||||
if (progressCallBack != null)
|
||||
{
|
||||
InvokeProgress(subScene, progressCallBack).Forget();
|
||||
InvokeOperationProgress(unloadOperation, progressCallBack).Forget();
|
||||
}
|
||||
|
||||
return;
|
||||
@ -390,19 +282,140 @@ namespace AlicizaX.Scene.Runtime
|
||||
Log.Warning($"UnloadAsync invalid location:{location}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含场景。
|
||||
/// </summary>
|
||||
/// <param name="location">场景资源定位地址。</param>
|
||||
/// <returns>是否包含场景。</returns>
|
||||
public bool IsContainScene(string location)
|
||||
{
|
||||
if (_currentMainSceneName.Equals(location))
|
||||
return EnsureSceneState().IsContainScene(location);
|
||||
}
|
||||
|
||||
private SceneDomainStateService EnsureSceneState()
|
||||
{
|
||||
var sceneScope = Context.EnsureScene();
|
||||
if (!sceneScope.TryGet<SceneDomainStateService>(out var sceneState))
|
||||
{
|
||||
sceneState = sceneScope.Register(new SceneDomainStateService());
|
||||
}
|
||||
|
||||
return sceneState;
|
||||
}
|
||||
|
||||
private SceneDomainStateService PrepareSceneStateForMainSceneLoad(string location)
|
||||
{
|
||||
var sceneScope = Context.ResetScene();
|
||||
var sceneState = sceneScope.Register(new SceneDomainStateService());
|
||||
sceneState.MarkMainSceneLoading(location);
|
||||
return sceneState;
|
||||
}
|
||||
|
||||
private async UniTaskVoid InvokeSceneProgress(SceneHandle sceneHandle, Action<float> progress)
|
||||
{
|
||||
if (sceneHandle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (!sceneHandle.IsDone && sceneHandle.IsValid)
|
||||
{
|
||||
await UniTask.Yield();
|
||||
progress?.Invoke(sceneHandle.Progress);
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTaskVoid InvokeOperationProgress(AsyncOperationBase operation, Action<float> progress)
|
||||
{
|
||||
if (operation == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (!operation.IsDone && operation.Status != EOperationStatus.Failed)
|
||||
{
|
||||
await UniTask.Yield();
|
||||
progress?.Invoke(operation.Progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SceneDomainStateService : ServiceBase, ISceneStateService
|
||||
{
|
||||
private readonly Dictionary<string, SceneHandle> _subScenes = new Dictionary<string, SceneHandle>();
|
||||
private readonly HashSet<string> _handlingScenes = new HashSet<string>();
|
||||
|
||||
public string CurrentMainSceneName { get; private set; } = string.Empty;
|
||||
|
||||
public SceneHandle CurrentMainSceneHandle { get; private set; }
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnDestroyService()
|
||||
{
|
||||
foreach (var subScene in _subScenes.Values)
|
||||
{
|
||||
subScene?.UnloadAsync();
|
||||
}
|
||||
|
||||
_subScenes.Clear();
|
||||
_handlingScenes.Clear();
|
||||
CurrentMainSceneHandle = null;
|
||||
CurrentMainSceneName = string.Empty;
|
||||
}
|
||||
|
||||
public void SetBootScene(string sceneName)
|
||||
{
|
||||
CurrentMainSceneName = sceneName ?? string.Empty;
|
||||
CurrentMainSceneHandle = null;
|
||||
_subScenes.Clear();
|
||||
_handlingScenes.Clear();
|
||||
}
|
||||
|
||||
public void MarkMainSceneLoading(string sceneName)
|
||||
{
|
||||
CurrentMainSceneName = sceneName ?? string.Empty;
|
||||
CurrentMainSceneHandle = null;
|
||||
_handlingScenes.Clear();
|
||||
TryBeginHandling(sceneName);
|
||||
}
|
||||
|
||||
public void SetMainScene(string sceneName, SceneHandle sceneHandle)
|
||||
{
|
||||
CurrentMainSceneName = sceneName ?? string.Empty;
|
||||
CurrentMainSceneHandle = sceneHandle;
|
||||
}
|
||||
|
||||
public bool TryBeginHandling(string location)
|
||||
=> !string.IsNullOrEmpty(location) && _handlingScenes.Add(location);
|
||||
|
||||
public void EndHandling(string location)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(location))
|
||||
{
|
||||
_handlingScenes.Remove(location);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSubScene(string location, SceneHandle sceneHandle)
|
||||
{
|
||||
_subScenes[location] = sceneHandle;
|
||||
}
|
||||
|
||||
public bool TryGetSubScene(string location, out SceneHandle sceneHandle)
|
||||
=> _subScenes.TryGetValue(location, out sceneHandle);
|
||||
|
||||
public bool RemoveSubScene(string location)
|
||||
=> _subScenes.Remove(location);
|
||||
|
||||
public bool IsContainScene(string location)
|
||||
{
|
||||
if (CurrentMainSceneName.Equals(location))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return _subScenes.TryGetValue(location, out var _);
|
||||
return _subScenes.ContainsKey(location);
|
||||
}
|
||||
|
||||
public bool IsMainScene(string location)
|
||||
=> CurrentMainSceneName.Equals(location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,8 @@ namespace AlicizaX.Timer.Runtime
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
AppServices.GetOrCreateScope<AppScope>().Register(new TimerService());
|
||||
AppServices.App.Register(new TimerService());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ namespace AlicizaX.UI.Runtime
|
||||
public static class UIHolderFactory
|
||||
{
|
||||
private static IResourceService ResourceService => AppServices.Require<IResourceService>();
|
||||
private static bool AllowLegacyResourcesFallback => UnityEngine.Application.isEditor || UnityEngine.Debug.isDebugBuild;
|
||||
|
||||
public static async UniTask<T> CreateUIHolderAsync<T>(Transform parent) where T : UIHolderObjectBase
|
||||
{
|
||||
@ -41,14 +42,14 @@ namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
return resInfo.LoadType == EUIResLoadType.AssetBundle
|
||||
? await ResourceService.LoadGameObjectAsync(resInfo.Location, parent)
|
||||
: await InstantiateResourceAsync(resInfo.Location, parent);
|
||||
: await LoadResourceWithFallbackAsync(resInfo.Location, parent);
|
||||
}
|
||||
|
||||
internal static GameObject LoadUIResourcesSync(UIResRegistry.UIResInfo resInfo, Transform parent)
|
||||
{
|
||||
return resInfo.LoadType == EUIResLoadType.AssetBundle
|
||||
? ResourceService.LoadGameObject(resInfo.Location, parent)
|
||||
: InstantiateResourceSync(resInfo.Location, parent);
|
||||
: LoadResourceWithFallbackSync(resInfo.Location, parent);
|
||||
}
|
||||
|
||||
|
||||
@ -88,6 +89,58 @@ namespace AlicizaX.UI.Runtime
|
||||
return Object.Instantiate(prefab, parent);
|
||||
}
|
||||
|
||||
private static async UniTask<GameObject> LoadResourceWithFallbackAsync(string location, Transform parent)
|
||||
{
|
||||
try
|
||||
{
|
||||
var managedObject = await ResourceService.LoadGameObjectAsync(location, parent);
|
||||
if (managedObject != null)
|
||||
{
|
||||
return managedObject;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!AllowLegacyResourcesFallback)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AllowLegacyResourcesFallback)
|
||||
{
|
||||
throw new NullReferenceException($"UI resource load failed via IResourceService: {location}");
|
||||
}
|
||||
|
||||
return await InstantiateResourceAsync(location, parent);
|
||||
}
|
||||
|
||||
private static GameObject LoadResourceWithFallbackSync(string location, Transform parent)
|
||||
{
|
||||
try
|
||||
{
|
||||
var managedObject = ResourceService.LoadGameObject(location, parent);
|
||||
if (managedObject != null)
|
||||
{
|
||||
return managedObject;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!AllowLegacyResourcesFallback)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AllowLegacyResourcesFallback)
|
||||
{
|
||||
throw new NullReferenceException($"UI resource load failed via IResourceService: {location}");
|
||||
}
|
||||
|
||||
return InstantiateResourceSync(location, parent);
|
||||
}
|
||||
|
||||
private static void ValidateAndBind(UIMetadata meta, GameObject holderObject, UIBase owner)
|
||||
{
|
||||
if (!holderObject) throw new NullReferenceException($"UI resource load failed: {meta.ResInfo.Location}");
|
||||
|
||||
@ -13,7 +13,14 @@ namespace AlicizaX.UI.Runtime
|
||||
|
||||
static UIMetadataFactory()
|
||||
{
|
||||
m_UIMetadataPool = AppServices.Require<IObjectPoolService>().CreateSingleSpawnObjectPool<UIMetadataObject>("UI Metadata Pool", 60, 16, 60f, 0);
|
||||
m_UIMetadataPool = AppServices.Require<IObjectPoolService>().CreatePool<UIMetadataObject>(
|
||||
new ObjectPoolCreateOptions(
|
||||
name: "UI Metadata Pool",
|
||||
allowMultiSpawn: false,
|
||||
autoReleaseInterval: 60,
|
||||
capacity: 16,
|
||||
expireTime: 60f,
|
||||
priority: 0));
|
||||
}
|
||||
|
||||
internal static UIMetadata GetWindowMetadata<T>()
|
||||
|
||||
@ -7,17 +7,17 @@ using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
readonly struct LayerData
|
||||
sealed class LayerData
|
||||
{
|
||||
public readonly List<UIMetadata> OrderList; // 维护插入顺序
|
||||
public readonly HashSet<RuntimeTypeHandle> HandleSet; // O(1)存在性检查
|
||||
public readonly Dictionary<RuntimeTypeHandle, int> IndexMap; // O(1)索引查找
|
||||
public readonly List<UIMetadata> OrderList;
|
||||
public readonly Dictionary<RuntimeTypeHandle, int> IndexMap;
|
||||
public int LastFullscreenIndex;
|
||||
|
||||
public LayerData(int initialCapacity)
|
||||
{
|
||||
OrderList = new List<UIMetadata>(initialCapacity);
|
||||
HandleSet = new HashSet<RuntimeTypeHandle>();
|
||||
IndexMap = new Dictionary<RuntimeTypeHandle, int>(initialCapacity);
|
||||
LastFullscreenIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,9 +70,9 @@ namespace AlicizaX.UI.Runtime
|
||||
if (meta.State == UIState.Loaded || meta.State == UIState.Initialized)
|
||||
{
|
||||
meta.CancelAsyncOperations();
|
||||
Pop(meta);
|
||||
SortWindowVisible(meta.MetaInfo.UILayer);
|
||||
SortWindowDepth(meta.MetaInfo.UILayer);
|
||||
var popResult = Pop(meta);
|
||||
SortWindowVisible(meta.MetaInfo.UILayer, popResult.previousFullscreenIndex);
|
||||
SortWindowDepth(meta.MetaInfo.UILayer, popResult.removedIndex >= 0 ? popResult.removedIndex : 0);
|
||||
meta.View.Visible = false;
|
||||
CacheWindow(meta, force);
|
||||
return;
|
||||
@ -85,9 +85,9 @@ namespace AlicizaX.UI.Runtime
|
||||
return;
|
||||
}
|
||||
|
||||
Pop(meta);
|
||||
SortWindowVisible(meta.MetaInfo.UILayer);
|
||||
SortWindowDepth(meta.MetaInfo.UILayer);
|
||||
var closedPopResult = Pop(meta);
|
||||
SortWindowVisible(meta.MetaInfo.UILayer, closedPopResult.previousFullscreenIndex);
|
||||
SortWindowDepth(meta.MetaInfo.UILayer, closedPopResult.removedIndex >= 0 ? closedPopResult.removedIndex : 0);
|
||||
CacheWindow(meta, force);
|
||||
}
|
||||
|
||||
@ -132,35 +132,42 @@ namespace AlicizaX.UI.Runtime
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void Push(UIMetadata meta)
|
||||
{
|
||||
ref var layer = ref _openUI[meta.MetaInfo.UILayer];
|
||||
if (layer.HandleSet.Add(meta.MetaInfo.RuntimeTypeHandle))
|
||||
var layer = _openUI[meta.MetaInfo.UILayer];
|
||||
if (!layer.IndexMap.ContainsKey(meta.MetaInfo.RuntimeTypeHandle))
|
||||
{
|
||||
int index = layer.OrderList.Count;
|
||||
layer.OrderList.Add(meta);
|
||||
layer.IndexMap[meta.MetaInfo.RuntimeTypeHandle] = index;
|
||||
if (meta.MetaInfo.FullScreen)
|
||||
{
|
||||
layer.LastFullscreenIndex = index;
|
||||
}
|
||||
|
||||
UpdateLayerParent(meta);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void Pop(UIMetadata meta)
|
||||
private (int removedIndex, int previousFullscreenIndex) Pop(UIMetadata meta)
|
||||
{
|
||||
ref var layer = ref _openUI[meta.MetaInfo.UILayer];
|
||||
if (layer.HandleSet.Remove(meta.MetaInfo.RuntimeTypeHandle))
|
||||
var layer = _openUI[meta.MetaInfo.UILayer];
|
||||
int previousFullscreenIndex = layer.LastFullscreenIndex;
|
||||
if (layer.IndexMap.TryGetValue(meta.MetaInfo.RuntimeTypeHandle, out int index))
|
||||
{
|
||||
if (layer.IndexMap.TryGetValue(meta.MetaInfo.RuntimeTypeHandle, out int index))
|
||||
{
|
||||
layer.OrderList.RemoveAt(index);
|
||||
layer.IndexMap.Remove(meta.MetaInfo.RuntimeTypeHandle);
|
||||
layer.OrderList.RemoveAt(index);
|
||||
layer.IndexMap.Remove(meta.MetaInfo.RuntimeTypeHandle);
|
||||
|
||||
// Update indices for all elements after the removed one
|
||||
for (int i = index; i < layer.OrderList.Count; i++)
|
||||
{
|
||||
var m = layer.OrderList[i];
|
||||
layer.IndexMap[m.MetaInfo.RuntimeTypeHandle] = i;
|
||||
}
|
||||
for (int i = index; i < layer.OrderList.Count; i++)
|
||||
{
|
||||
var item = layer.OrderList[i];
|
||||
layer.IndexMap[item.MetaInfo.RuntimeTypeHandle] = i;
|
||||
}
|
||||
|
||||
UpdateFullscreenIndexAfterRemove(layer, meta, index);
|
||||
return (index, previousFullscreenIndex);
|
||||
}
|
||||
|
||||
return (-1, previousFullscreenIndex);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -176,7 +183,7 @@ namespace AlicizaX.UI.Runtime
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void MoveToTop(UIMetadata meta)
|
||||
{
|
||||
ref var layer = ref _openUI[meta.MetaInfo.UILayer];
|
||||
var layer = _openUI[meta.MetaInfo.UILayer];
|
||||
int lastIdx = layer.OrderList.Count - 1;
|
||||
|
||||
if (!layer.IndexMap.TryGetValue(meta.MetaInfo.RuntimeTypeHandle, out int currentIdx))
|
||||
@ -189,11 +196,12 @@ namespace AlicizaX.UI.Runtime
|
||||
|
||||
for (int i = currentIdx; i < lastIdx; i++)
|
||||
{
|
||||
var m = layer.OrderList[i];
|
||||
layer.IndexMap[m.MetaInfo.RuntimeTypeHandle] = i;
|
||||
var item = layer.OrderList[i];
|
||||
layer.IndexMap[item.MetaInfo.RuntimeTypeHandle] = i;
|
||||
}
|
||||
|
||||
layer.IndexMap[meta.MetaInfo.RuntimeTypeHandle] = lastIdx;
|
||||
UpdateFullscreenIndexAfterMove(layer, meta, currentIdx, lastIdx);
|
||||
|
||||
SortWindowDepth(meta.MetaInfo.UILayer, currentIdx);
|
||||
}
|
||||
@ -212,36 +220,40 @@ namespace AlicizaX.UI.Runtime
|
||||
await meta.View.InternalOpen(cancellationToken);
|
||||
}
|
||||
|
||||
private void SortWindowVisible(int layer)
|
||||
private void SortWindowVisible(int layer, int previousFullscreenIndex = int.MinValue)
|
||||
{
|
||||
var list = _openUI[layer].OrderList;
|
||||
var layerData = _openUI[layer];
|
||||
var list = layerData.OrderList;
|
||||
int count = list.Count;
|
||||
|
||||
int fullscreenIdx = -1;
|
||||
for (int i = count - 1; i >= 0; i--)
|
||||
int fullscreenIdx = layerData.LastFullscreenIndex;
|
||||
if (fullscreenIdx >= count || (fullscreenIdx >= 0 && !IsDisplayFullscreen(list[fullscreenIdx])))
|
||||
{
|
||||
var meta = list[i];
|
||||
if (meta.MetaInfo.FullScreen && UIStateMachine.IsDisplayActive(meta.State))
|
||||
{
|
||||
fullscreenIdx = i;
|
||||
break;
|
||||
}
|
||||
fullscreenIdx = FindLastFullscreenIndex(list, count - 1);
|
||||
layerData.LastFullscreenIndex = fullscreenIdx;
|
||||
}
|
||||
|
||||
if (fullscreenIdx == -1)
|
||||
int oldFullscreenIndex = previousFullscreenIndex == int.MinValue ? fullscreenIdx : previousFullscreenIndex;
|
||||
if (oldFullscreenIndex == fullscreenIdx)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
list[i].View.Visible = true;
|
||||
}
|
||||
ApplyVisibilityRange(list, fullscreenIdx >= 0 ? fullscreenIdx : 0, count, fullscreenIdx);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (oldFullscreenIndex == -1 && fullscreenIdx == -1)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
list[i].View.Visible = (i >= fullscreenIdx);
|
||||
}
|
||||
ApplyVisibilityRange(list, 0, count, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
int start = oldFullscreenIndex < 0 || fullscreenIdx < 0
|
||||
? 0
|
||||
: Math.Min(oldFullscreenIndex, fullscreenIdx);
|
||||
int endExclusive = oldFullscreenIndex < 0 || fullscreenIdx < 0
|
||||
? count
|
||||
: Math.Max(oldFullscreenIndex, fullscreenIdx) + 1;
|
||||
|
||||
ApplyVisibilityRange(list, start, endExclusive, fullscreenIdx);
|
||||
}
|
||||
|
||||
private void SortWindowDepth(int layer, int startIndex = 0)
|
||||
@ -259,5 +271,83 @@ namespace AlicizaX.UI.Runtime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDisplayFullscreen(UIMetadata meta)
|
||||
{
|
||||
return meta.MetaInfo.FullScreen && UIStateMachine.IsDisplayActive(meta.State);
|
||||
}
|
||||
|
||||
private static int FindLastFullscreenIndex(List<UIMetadata> list, int startIndex)
|
||||
{
|
||||
for (int i = Math.Min(startIndex, list.Count - 1); i >= 0; i--)
|
||||
{
|
||||
if (IsDisplayFullscreen(list[i]))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void ApplyVisibilityRange(List<UIMetadata> list, int startInclusive, int endExclusive, int fullscreenIdx)
|
||||
{
|
||||
if (startInclusive < 0)
|
||||
{
|
||||
startInclusive = 0;
|
||||
}
|
||||
|
||||
if (endExclusive > list.Count)
|
||||
{
|
||||
endExclusive = list.Count;
|
||||
}
|
||||
|
||||
bool showAll = fullscreenIdx < 0;
|
||||
for (int i = startInclusive; i < endExclusive; i++)
|
||||
{
|
||||
list[i].View.Visible = showAll || i >= fullscreenIdx;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateFullscreenIndexAfterRemove(LayerData layer, UIMetadata removedMeta, int removedIndex)
|
||||
{
|
||||
if (layer.OrderList.Count == 0)
|
||||
{
|
||||
layer.LastFullscreenIndex = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (removedMeta.MetaInfo.FullScreen && layer.LastFullscreenIndex == removedIndex)
|
||||
{
|
||||
layer.LastFullscreenIndex = FindLastFullscreenIndex(layer.OrderList, removedIndex - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (removedIndex < layer.LastFullscreenIndex)
|
||||
{
|
||||
layer.LastFullscreenIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateFullscreenIndexAfterMove(LayerData layer, UIMetadata meta, int fromIndex, int toIndex)
|
||||
{
|
||||
if (layer.LastFullscreenIndex == fromIndex)
|
||||
{
|
||||
layer.LastFullscreenIndex = toIndex;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!meta.MetaInfo.FullScreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (fromIndex < layer.LastFullscreenIndex)
|
||||
{
|
||||
layer.LastFullscreenIndex--;
|
||||
}
|
||||
|
||||
layer.LastFullscreenIndex = Math.Max(layer.LastFullscreenIndex, toIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,10 @@ namespace AlicizaX.UI.Runtime
|
||||
|
||||
Holder = holder;
|
||||
_canvas = Holder.transform.GetComponent<Canvas>();
|
||||
_canvas.overrideSorting = true;
|
||||
if (_canvas != null)
|
||||
{
|
||||
_canvas.overrideSorting = owner == null;
|
||||
}
|
||||
_raycaster = Holder.transform.GetComponent<GraphicRaycaster>();
|
||||
Holder.RectTransform.localPosition = Vector3.zero;
|
||||
Holder.RectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
@ -96,7 +99,7 @@ namespace AlicizaX.UI.Runtime
|
||||
StartAsyncLoading(typeHandle, userDatas).Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid StartAsyncLoading(RuntimeTypeHandle typeHandle, params System.Object[] userDatas)
|
||||
private async UniTask StartAsyncLoading(RuntimeTypeHandle typeHandle, params System.Object[] userDatas)
|
||||
{
|
||||
_loadingFlags[typeHandle] = true;
|
||||
|
||||
|
||||
@ -40,6 +40,10 @@ namespace AlicizaX.UI.Runtime
|
||||
Holder = holder;
|
||||
_parent = owner;
|
||||
_canvas = Holder.transform.GetComponent<Canvas>();
|
||||
if (_canvas != null)
|
||||
{
|
||||
_canvas.overrideSorting = false;
|
||||
}
|
||||
_raycaster = Holder.transform.GetComponent<GraphicRaycaster>();
|
||||
Depth = owner.Depth + 5;
|
||||
_state = UIState.Loaded;
|
||||
|
||||
@ -31,7 +31,10 @@ namespace AlicizaX.UI.Runtime
|
||||
throw new InvalidOperationException("UI already Created");
|
||||
Holder = holder;
|
||||
_canvas = Holder.transform.GetComponent<Canvas>();
|
||||
_canvas.overrideSorting = true;
|
||||
if (_canvas != null)
|
||||
{
|
||||
_canvas.overrideSorting = owner == null;
|
||||
}
|
||||
_raycaster = Holder.transform.GetComponent<GraphicRaycaster>();
|
||||
Holder.RectTransform.localPosition = Vector3.zero;
|
||||
Holder.RectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
|
||||
@ -29,16 +29,17 @@ namespace AlicizaX.UI.Runtime
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_uiService = AppServices.GetOrCreateScope<AppScope>().Register(new UIService());
|
||||
_uiService = AppServices.App.Register(new UIService());
|
||||
if (uiRoot == null)
|
||||
{
|
||||
throw new GameFrameworkException("UIRoot Prefab is invalid.");
|
||||
}
|
||||
|
||||
GameObject obj = Instantiate(uiRoot, Vector3.zero, Quaternion.identity);
|
||||
obj.name = "------UI Root------";
|
||||
_instanceRoot = obj.transform;
|
||||
Object.DontDestroyOnLoad(_instanceRoot);
|
||||
_uiService.Initialize(_instanceRoot,_isOrthographic);
|
||||
_uiService.Initialize(_instanceRoot, _isOrthographic);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
@ -50,9 +51,9 @@ namespace AlicizaX.UI.Runtime
|
||||
#region 设置安全区域
|
||||
|
||||
/// <summary>
|
||||
/// 设置屏幕安全区域(异形屏支持)。
|
||||
/// 应用屏幕安全区域,适配刘海屏等显示区域。
|
||||
/// </summary>
|
||||
/// <param name="safeRect">安全区域</param>
|
||||
/// <param name="safeRect">安全区域。</param>
|
||||
public void ApplyScreenSafeRect(Rect safeRect)
|
||||
{
|
||||
CanvasScaler scaler = _uiService.UICanvasRoot.GetComponent<CanvasScaler>();
|
||||
@ -73,31 +74,28 @@ namespace AlicizaX.UI.Runtime
|
||||
float offsetMaxX = scaler.referenceResolution.x - width - posX;
|
||||
float offsetMaxY = scaler.referenceResolution.y - height - posY;
|
||||
|
||||
// 注意:安全区坐标系的原点为左下角
|
||||
// 注意:安全区域坐标系原点为左下角。
|
||||
var rectTrans = _uiService.UICanvasRoot.transform as RectTransform;
|
||||
if (rectTrans != null)
|
||||
{
|
||||
rectTrans.offsetMin = new Vector2(posX, posY); //锚框状态下的屏幕左下角偏移向量
|
||||
rectTrans.offsetMax = new Vector2(-offsetMaxX, -offsetMaxY); //锚框状态下的屏幕右上角偏移向量
|
||||
rectTrans.offsetMin = new Vector2(posX, posY); // 锚点状态下的屏幕左下角偏移量。
|
||||
rectTrans.offsetMax = new Vector2(-offsetMaxX, -offsetMaxY); // 锚点状态下的屏幕右上角偏移量。
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模拟IPhoneX异形屏
|
||||
/// </summary>
|
||||
|
||||
public void SimulateIPhoneXNotchScreen()
|
||||
{
|
||||
Rect rect;
|
||||
if (Screen.height > Screen.width)
|
||||
{
|
||||
// 竖屏Portrait
|
||||
// 竖屏
|
||||
float deviceWidth = 1125;
|
||||
float deviceHeight = 2436;
|
||||
rect = new Rect(0f / deviceWidth, 102f / deviceHeight, 1125f / deviceWidth, 2202f / deviceHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 横屏Landscape
|
||||
// 横屏
|
||||
float deviceWidth = 2436;
|
||||
float deviceHeight = 1125;
|
||||
rect = new Rect(132f / deviceWidth, 63f / deviceHeight, 2172f / deviceWidth, 1062f / deviceHeight);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user