From 9903a104d5ef3dd67f3aa8db5d864977c375e30e Mon Sep 17 00:00:00 2001 From: Kaioru Date: Wed, 15 Nov 2023 18:41:36 +0800 Subject: [PATCH] Add lazy loading for skill level info --- .../Skills/Templates/SkillTemplate.cs | 27 ++++++++++++------- .../Skills/Templates/SkillTemplateLevel.cs | 2 ++ .../Templates/SkillTemplateLevelCommon.cs | 2 ++ .../Templates/TemplateCollection.cs | 19 +++++++++++++ .../Templates/TemplateCollectionProvider.cs | 20 ++++++++++++++ .../Templates/TemplateManager.cs | 16 +++++------ .../Skills/Templates/ISkillTemplate.cs | 2 +- .../Skills/Templates/ISkillTemplateLevel.cs | 3 ++- .../Edelstein.Protocol.Utilities.csproj | 1 - .../Templates/ITemplateCollection.cs | 11 ++++++++ .../Templates/ITemplateManager.cs | 4 +-- .../Templates/ITemplateProvider.cs | 4 ++- 12 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProvider.cs create mode 100644 src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs diff --git a/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplate.cs b/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplate.cs index e0f4602f4..2ef585a5f 100644 --- a/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplate.cs +++ b/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplate.cs @@ -1,6 +1,8 @@ using System.Collections.Frozen; using Duey.Abstractions; +using Edelstein.Common.Utilities.Templates; using Edelstein.Protocol.Gameplay.Models.Characters.Skills.Templates; +using Edelstein.Protocol.Utilities.Templates; namespace Edelstein.Common.Gameplay.Models.Characters.Skills.Templates; @@ -8,7 +10,7 @@ public class SkillTemplate : ISkillTemplate { public int ID { get; } - public ISkillTemplateLevel? this[int level] => Levels.TryGetValue(level, out var result) ? result : null; + public ISkillTemplateLevel? this[int level] => Levels.Retrieve(level).Result; public short MaxLevel { get; } @@ -24,7 +26,7 @@ public class SkillTemplate : ISkillTemplate public ICollection PsdSkill { get; } public IDictionary ReqSkill { get; } - public IDictionary Levels { get; } + public ITemplateCollection Levels { get; } public SkillTemplate(int id, IDataNode node) { @@ -76,22 +78,29 @@ public SkillTemplate(int id, IDataNode node) if (maxLevelStr != null) maxLevel = Convert.ToInt32(maxLevelStr); - Levels = Enumerable + Levels = new TemplateCollectionProvider(Enumerable .Range(1, maxLevel + (IsCombatOrders ? 2 : 0)) .ToFrozenDictionary( i => i, - i => (ISkillTemplateLevel)new SkillTemplateLevelCommon(i, common.Cache()) - ); + i => (ITemplateProvider)new TemplateProviderLazy( + i, + () => new SkillTemplateLevelCommon(i, common.Cache()) + ) + )); MaxLevel = (short)maxLevel; } else { var level = node.ResolvePath("level"); - Levels = level?.Children.ToFrozenDictionary( - c => Convert.ToInt32(c.Name), - c => (ISkillTemplateLevel)new SkillTemplateLevel(Convert.ToInt32(c.Name), c.Cache()) - ) ?? FrozenDictionary.Empty; + Levels = new TemplateCollectionProvider( + level?.Children.ToFrozenDictionary( + c => Convert.ToInt32(c.Name), + c => (ITemplateProvider)new TemplateProviderEager( + Convert.ToInt32(c.Name), + new SkillTemplateLevel(Convert.ToInt32(c.Name), c.Cache())) + ) ?? FrozenDictionary>.Empty + ); MaxLevel = (short)(Levels?.Count ?? 0); } } diff --git a/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevel.cs b/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevel.cs index 50c27d99a..612cc1186 100644 --- a/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevel.cs +++ b/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevel.cs @@ -7,6 +7,8 @@ namespace Edelstein.Common.Gameplay.Models.Characters.Skills.Templates; public class SkillTemplateLevel : ISkillTemplateLevel { + public int ID => Level; + public int Level { get; } public short HP { get; } diff --git a/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevelCommon.cs b/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevelCommon.cs index 1fbe8a58e..cf6f230df 100644 --- a/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevelCommon.cs +++ b/src/common/Edelstein.Common.Gameplay/Models/Characters/Skills/Templates/SkillTemplateLevelCommon.cs @@ -8,6 +8,8 @@ namespace Edelstein.Common.Gameplay.Models.Characters.Skills.Templates; public class SkillTemplateLevelCommon : ISkillTemplateLevel { + public int ID => Level; + public int Level { get; } public short HP { get; } diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs new file mode 100644 index 000000000..d79f8c108 --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs @@ -0,0 +1,19 @@ +using System.Collections.Immutable; +using Edelstein.Protocol.Utilities.Templates; + +namespace Edelstein.Common.Utilities.Templates; + +public class TemplateCollection( + IReadOnlyDictionary templates +) : + ITemplateCollection + where TTemplate : ITemplate +{ + public int Count => templates.Count; + + public Task Retrieve(int key) + => Task.FromResult(templates.TryGetValue(key, out var result) ? result : default); + + public Task> RetrieveAll() + => Task.FromResult>(templates.Values.ToImmutableArray()); +} diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProvider.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProvider.cs new file mode 100644 index 000000000..bcef5337b --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProvider.cs @@ -0,0 +1,20 @@ +using System.Collections.Frozen; +using System.Collections.Immutable; +using Edelstein.Protocol.Utilities.Templates; + +namespace Edelstein.Common.Utilities.Templates; + +public class TemplateCollectionProvider( + IReadOnlyDictionary> providers +) : + ITemplateCollection + where TTemplate : ITemplate +{ + public int Count => providers.Count; + + public async Task Retrieve(int key) + => providers.TryGetValue(key, out var provider) ? await provider.Provide() : default; + + public async Task> RetrieveAll() + => await Task.WhenAll(providers.Values.Select(p => p.Provide())); +} diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs index 1836b8e0f..97124f29d 100644 --- a/src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs @@ -3,24 +3,24 @@ namespace Edelstein.Common.Utilities.Templates; -public class TemplateManager : ITemplateManager where TTemplate : ITemplate +public class TemplateManager : + ITemplateManager + where TTemplate : ITemplate { - private readonly IDictionary> _providers; + private readonly IDictionary> _providers = new Dictionary>(); private FrozenDictionary>? _providersFrozen; - public TemplateManager() => _providers = new Dictionary>(); - public int Count => (_providersFrozen ?? _providers).Count; - + public async Task Retrieve(int key) => (_providersFrozen ?? _providers).TryGetValue(key, out var provider) ? await provider.Provide() : default; - public Task> Insert(ITemplateProvider entry) => - Task.FromResult((_providersFrozen ?? _providers)[entry.ID] = entry); - public async Task> RetrieveAll() => await Task.WhenAll((_providersFrozen ?? _providers).Values.Select(p => p.Provide())); + public Task> Insert(ITemplateProvider entry) => + Task.FromResult((_providersFrozen ?? _providers)[entry.ID] = entry); + public void Freeze() { _providersFrozen = _providers.ToFrozenDictionary(); diff --git a/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplate.cs b/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplate.cs index 2dfbd37f1..348347787 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplate.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplate.cs @@ -20,5 +20,5 @@ public interface ISkillTemplate : ITemplate ICollection PsdSkill { get; } IDictionary ReqSkill { get; } - IDictionary Levels { get; } + ITemplateCollection Levels { get; } } diff --git a/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplateLevel.cs b/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplateLevel.cs index f0405224d..2003877aa 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplateLevel.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay/Models/Characters/Skills/Templates/ISkillTemplateLevel.cs @@ -1,8 +1,9 @@ using Edelstein.Protocol.Utilities.Spatial; +using Edelstein.Protocol.Utilities.Templates; namespace Edelstein.Protocol.Gameplay.Models.Characters.Skills.Templates; -public interface ISkillTemplateLevel +public interface ISkillTemplateLevel : ITemplate { int Level { get; } diff --git a/src/protocol/Edelstein.Protocol.Utilities/Edelstein.Protocol.Utilities.csproj b/src/protocol/Edelstein.Protocol.Utilities/Edelstein.Protocol.Utilities.csproj index ddf1fff78..edcc66c61 100644 --- a/src/protocol/Edelstein.Protocol.Utilities/Edelstein.Protocol.Utilities.csproj +++ b/src/protocol/Edelstein.Protocol.Utilities/Edelstein.Protocol.Utilities.csproj @@ -4,7 +4,6 @@ - diff --git a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs new file mode 100644 index 000000000..df9674448 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs @@ -0,0 +1,11 @@ +using Edelstein.Protocol.Utilities.Repositories.Methods; + +namespace Edelstein.Protocol.Utilities.Templates; + +public interface ITemplateCollection : + IRepositoryMethodRetrieve, + IRepositoryMethodRetrieveAll + where TTemplate : ITemplate +{ + int Count { get; } +} diff --git a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs index a7d439dc0..e5e1700c4 100644 --- a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs +++ b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs @@ -3,11 +3,9 @@ namespace Edelstein.Protocol.Utilities.Templates; public interface ITemplateManager : - IRepositoryMethodRetrieve, - IRepositoryMethodRetrieveAll, + ITemplateCollection, IRepositoryMethodInsert>, IRepositoryMethodFreeze where TTemplate : ITemplate { - int Count { get; } } diff --git a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateProvider.cs b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateProvider.cs index 347503072..b26d2de03 100644 --- a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateProvider.cs +++ b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateProvider.cs @@ -2,7 +2,9 @@ namespace Edelstein.Protocol.Utilities.Templates; -public interface ITemplateProvider : IIdentifiable where TTemplate : ITemplate +public interface ITemplateProvider : + IIdentifiable + where TTemplate : ITemplate { Task Provide(); }