From 8ab46d37e63a6537d6a4f3ccd429a84a97cc9aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Thu, 5 Jan 2023 21:31:21 +0100 Subject: [PATCH] feat(game): put friends, group, inventory, skills in Game instead of Character --- .../Data/Characters/Character.cs | 20 --- Core/NosSmooth.Game/Game.cs | 161 +++++++++++++++++- Core/NosSmooth.Game/GameSemaphoreType.cs | 31 +++- Core/NosSmooth.Game/NosSmooth.Game.csproj | 1 - .../Characters/CharacterInitResponder.cs | 36 +++- .../Characters/SkillResponder.cs | 30 ++-- .../Entities/AoeSkillUsedResponder.cs | 2 +- .../Entities/SkillUsedResponder.cs | 15 +- .../Operations/UsePrimarySkillOperation.cs | 7 +- .../Techniques/SimpleAttackTechnique.cs | 2 +- 10 files changed, 239 insertions(+), 66 deletions(-) diff --git a/Core/NosSmooth.Game/Data/Characters/Character.cs b/Core/NosSmooth.Game/Data/Characters/Character.cs index 682a94230a062cd9b1484d8dd6a4035a0d2c5eb3..f688d8e0cc759d46bb3f92935e2a33c304056277 100644 --- a/Core/NosSmooth.Game/Data/Characters/Character.cs +++ b/Core/NosSmooth.Game/Data/Characters/Character.cs @@ -16,26 +16,6 @@ namespace NosSmooth.Game.Data.Characters; /// public class Character : Player { - /// - /// Gets or sets the inventory of the character. - /// - public Inventory.Inventory? Inventory { get; set; } - - /// - /// Get or sets the friends of the character. - /// - public IReadOnlyList? Friends { get; set; } - - /// - /// Gets or sets the skills of the player. - /// - public Skills? Skills { get; set; } - - /// - /// Gets or sets the group the player is in. - /// - public Group? Group { get; set; } - /// /// Gets or sets the c skill points. /// diff --git a/Core/NosSmooth.Game/Game.cs b/Core/NosSmooth.Game/Game.cs index d93e37aaf05af775c0f3e8db90f91034d6090634..06ef675cbe5f02b16b582fdc816f59b42d232958 100644 --- a/Core/NosSmooth.Game/Game.cs +++ b/Core/NosSmooth.Game/Game.cs @@ -7,8 +7,11 @@ using Microsoft.Extensions.Options; using NosSmooth.Core.Stateful; using NosSmooth.Game.Data.Characters; +using NosSmooth.Game.Data.Chat; +using NosSmooth.Game.Data.Inventory; using NosSmooth.Game.Data.Maps; using NosSmooth.Game.Data.Raids; +using NosSmooth.Game.Data.Social; namespace NosSmooth.Game; @@ -40,6 +43,31 @@ public class Game : IStatefulEntity /// public Character? Character { get; internal set; } + /// + /// Gets or sets the inventory of the character. + /// + public Inventory? Inventory { get; internal set; } + + /// + /// Get or sets the friends of the character. + /// + public IReadOnlyList? Friends { get; internal set; } + + /// + /// Gets or sets the skills of the player. + /// + public Skills? Skills { get; internal set; } + + /// + /// Gets or sets the family. + /// + public Family? Family { get; internal set; } + + /// + /// Gets or sets the group the player is in. + /// + public Group? Group { get; internal set; } + /// /// Gets the current map of the client. /// @@ -49,10 +77,7 @@ public class Game : IStatefulEntity public Map? CurrentMap { get => _currentMap; - internal set - { - _currentMap = value; - } + internal set { _currentMap = value; } } /// @@ -63,6 +88,134 @@ public class Game : IStatefulEntity /// public Raid? CurrentRaid { get; internal set; } + /// + /// Creates the skills if they are null, or updates the current skills. + /// + /// The function for creating the skills. + /// The function for updating the skills. + /// Whether to release the semaphore used for changing the skills. + /// The cancellation token for cancelling the operation. + /// The updated skills. + internal async Task CreateOrUpdateSkillsAsync + ( + Func create, + Func update, + bool releaseSemaphore = true, + CancellationToken ct = default + ) + { + return await CreateOrUpdateAsync + ( + GameSemaphoreType.Skills, + () => Skills, + s => Skills = s, + create, + update, + releaseSemaphore, + ct + ); + } + + /// + /// Creates the inventory if it is null, or updates the current inventory. + /// + /// The function for creating the inventory. + /// The function for updating the inventory. + /// Whether to release the semaphore used for changing the inventory. + /// The cancellation token for cancelling the operation. + /// The updated inventory. + internal async Task CreateOrUpdateInventoryAsync + ( + Func create, + Func update, + bool releaseSemaphore = true, + CancellationToken ct = default + ) + { + return await CreateOrUpdateAsync + ( + GameSemaphoreType.Inventory, + () => Inventory, + i => Inventory = i, + create, + update, + releaseSemaphore, + ct + ); + } + + /// + /// Creates the family if it is null, or updates the current family. + /// + /// The function for creating the family. + /// The function for updating the family. + /// Whether to release the semaphore used for changing the family. + /// The cancellation token for cancelling the operation. + /// The updated family. + internal async Task CreateOrUpdateFamilyAsync + ( + Func create, + Func update, + bool releaseSemaphore = true, + CancellationToken ct = default + ) + { + var family = await CreateOrUpdateAsync + ( + GameSemaphoreType.Family, + () => Family, + c => Family = c, + create, + update, + releaseSemaphore, + ct + ); + + await CreateOrUpdateCharacterAsync + ( + () => new Character + { + Family = family + }, + c => + { + c.Family = family; + return c; + }, + ct: ct + ); + + return family; + } + + /// + /// Creates the group if it is null, or updates the current group. + /// + /// The function for creating the group. + /// The function for updating the group. + /// Whether to release the semaphore used for changing the group. + /// The cancellation token for cancelling the operation. + /// The updated group. + internal async Task CreateOrUpdateGroupAsync + ( + Func create, + Func update, + bool releaseSemaphore = true, + CancellationToken ct = default + ) + { + return await CreateOrUpdateAsync + ( + GameSemaphoreType.Group, + () => Group, + c => Group = c, + create, + update, + releaseSemaphore, + ct + ); + } + /// /// Creates the character if it is null, or updates the current character. /// diff --git a/Core/NosSmooth.Game/GameSemaphoreType.cs b/Core/NosSmooth.Game/GameSemaphoreType.cs index 672da3572a7f2c1508db575cffdf2d8d99bfac8c..0cb141f02b9bd2feac4042a94e46184d3132fc6c 100644 --- a/Core/NosSmooth.Game/GameSemaphoreType.cs +++ b/Core/NosSmooth.Game/GameSemaphoreType.cs @@ -12,17 +12,42 @@ namespace NosSmooth.Game; public enum GameSemaphoreType { /// - /// The semaphore for the character. + /// The semaphore for character. /// Character, /// - /// The semaphore for the map. + /// The semaphore for inventory. + /// + Inventory, + + /// + /// The semaphore for friends. + /// + Friends, + + /// + /// The semaphore for family. + /// + Family, + + /// + /// The semaphore for group. + /// + Group, + + /// + /// The semaphore for skills. + /// + Skills, + + /// + /// The semaphore for map. /// Map, /// - /// The semaphore for the raid. + /// The semaphore for raid. /// Raid } \ No newline at end of file diff --git a/Core/NosSmooth.Game/NosSmooth.Game.csproj b/Core/NosSmooth.Game/NosSmooth.Game.csproj index c53eb6d90d36b070a26a5bff6a2ebb47bb059755..dc2368f96c339fa889c6f52aa629e070c27fd0c4 100644 --- a/Core/NosSmooth.Game/NosSmooth.Game.csproj +++ b/Core/NosSmooth.Game/NosSmooth.Game.csproj @@ -18,7 +18,6 @@ Create Character in At responder if needed. - diff --git a/Core/NosSmooth.Game/PacketHandlers/Characters/CharacterInitResponder.cs b/Core/NosSmooth.Game/PacketHandlers/Characters/CharacterInitResponder.cs index 3869db988f3d4dbadae577e7f9f3746d58a1c6f6..6f1888f1dd4cc6bd2eed3a8371467e192d1f9886 100644 --- a/Core/NosSmooth.Game/PacketHandlers/Characters/CharacterInitResponder.cs +++ b/Core/NosSmooth.Game/PacketHandlers/Characters/CharacterInitResponder.cs @@ -44,8 +44,6 @@ public class CharacterInitResponder : IPacketResponder, IPacketResp ( () => new Character { - Family = new Family(packet.FamilyId, null, packet.FamilyName, packet.FamilyLevel, null), - Group = new Group(packet.GroupId, default, default), Id = packet.CharacterId, Name = packet.Name, Authority = packet.Authority, @@ -69,22 +67,46 @@ public class CharacterInitResponder : IPacketResponder, IPacketResp character.Class = packet.Class; character.Icon = packet.Icon; character.Compliment = packet.Compliment; - character.Group = (character.Group ?? new Group(packet.GroupId, null, null)) with - { - Id = packet.GroupId - }; character.Morph = (character.Morph ?? new Morph(packet.MorphVNum, packet.MorphUpgrade)) with { VNum = packet.MorphVNum, Upgrade = packet.MorphUpgrade }; character.ArenaWinner = packet.ArenaWinner; character.IsInvisible = packet.IsInvisible; - character.Family = new Family(packet.FamilyId, null, packet.FamilyName, packet.FamilyLevel, null); return character; }, ct: ct ); + await _game.CreateOrUpdateGroupAsync + ( + () => new Group(packet.GroupId, null, null), + g => g with + { + Id = packet.GroupId + }, + ct: ct + ); + + await _game.CreateOrUpdateFamilyAsync + ( + () => new Family + ( + packet.FamilyId, + null, + packet.FamilyName, + packet.FamilyLevel, + null + ), + f => f with + { + Id = packet.FamilyId, + Name = packet.FamilyName, + Level = packet.FamilyLevel + }, + ct: ct + ); + if (character != oldCharacter) { return await _eventDispatcher.DispatchEvent(new ReceivedCharacterDataEvent(character), ct); diff --git a/Core/NosSmooth.Game/PacketHandlers/Characters/SkillResponder.cs b/Core/NosSmooth.Game/PacketHandlers/Characters/SkillResponder.cs index 7718ec3faa9eb0e476ee69a93f858a0d4f060251..1b70b8f3e3a298742df79409dc38a03b62100793 100644 --- a/Core/NosSmooth.Game/PacketHandlers/Characters/SkillResponder.cs +++ b/Core/NosSmooth.Game/PacketHandlers/Characters/SkillResponder.cs @@ -55,24 +55,24 @@ public class SkillResponder : IPacketResponder Skill primarySkill, secondarySkill; - var character = _game.Character; + var skills = _game.Skills; - if (character is not null && packet.PrimarySkillVNum == character.Skills?.PrimarySkill.SkillVNum) + if (packet.PrimarySkillVNum == skills?.PrimarySkill.SkillVNum) { - primarySkill = character.Skills.PrimarySkill; + primarySkill = skills.PrimarySkill; } else { primarySkill = await CreateSkill(packet.PrimarySkillVNum, default); } - if (character is not null && packet.PrimarySkillVNum == packet.SecondarySkillVNum) + if (packet.PrimarySkillVNum == packet.SecondarySkillVNum) { secondarySkill = primarySkill; } - else if (character is not null && packet.SecondarySkillVNum == character.Skills?.SecondarySkill.SkillVNum) + else if (packet.SecondarySkillVNum == skills?.SecondarySkill.SkillVNum) { - secondarySkill = character.Skills.SecondarySkill; + secondarySkill = skills.SecondarySkill; } else { @@ -80,13 +80,13 @@ public class SkillResponder : IPacketResponder } var skillsFromPacket = packet.SkillSubPackets?.Select(x => x.SkillVNum).ToList() ?? new List(); - var skillsFromCharacter = character?.Skills is null + var skillsFromCharacter = skills is null ? new List() - : character.Skills.OtherSkills.Select(x => x.SkillVNum).ToList(); + : skills.OtherSkills.Select(x => x.SkillVNum).ToList(); var newSkills = skillsFromPacket.Except(skillsFromCharacter); var oldSkills = skillsFromCharacter.Except(skillsFromPacket); - var otherSkillsFromCharacter = new List(character?.Skills?.OtherSkills ?? new Skill[] { }); + var otherSkillsFromCharacter = new List(skills?.OtherSkills ?? new Skill[] { }); otherSkillsFromCharacter.RemoveAll(x => oldSkills.Contains(x.SkillVNum)); foreach (var newSkill in newSkills) @@ -94,16 +94,12 @@ public class SkillResponder : IPacketResponder otherSkillsFromCharacter.Add(await CreateSkill(newSkill, default)); } - var skills = new Skills(primarySkill, secondarySkill, otherSkillsFromCharacter); + skills = new Skills(primarySkill, secondarySkill, otherSkillsFromCharacter); - await _game.CreateOrUpdateCharacterAsync + await _game.CreateOrUpdateSkillsAsync ( - () => new Character { Skills = skills }, - c => - { - c.Skills = skills; - return c; - }, + () => skills, + _ => skills, ct: ct ); diff --git a/Core/NosSmooth.Game/PacketHandlers/Entities/AoeSkillUsedResponder.cs b/Core/NosSmooth.Game/PacketHandlers/Entities/AoeSkillUsedResponder.cs index 1a37280dfe3eda93839cd7d3aae0754aac2dc19f..a580a612a25dd3a46cfa996cf35b6efc36b75973 100644 --- a/Core/NosSmooth.Game/PacketHandlers/Entities/AoeSkillUsedResponder.cs +++ b/Core/NosSmooth.Game/PacketHandlers/Entities/AoeSkillUsedResponder.cs @@ -63,7 +63,7 @@ public class AoeSkillUsedResponder : IPacketResponder if (caster is Character character) { - var skillResult = character.Skills?.TryGetSkillByVNum(packet.SkillVNum); + var skillResult = _game.Skills?.TryGetSkillByVNum(packet.SkillVNum); if (skillResult?.IsSuccess ?? false) { skillEntity = skillResult.Value.Entity; diff --git a/Core/NosSmooth.Game/PacketHandlers/Entities/SkillUsedResponder.cs b/Core/NosSmooth.Game/PacketHandlers/Entities/SkillUsedResponder.cs index 8a514c43e83327b6db21d78a8e59063a6a4f493b..6e3edebd2783231878e9e5b658f2b40fe269a3e8 100644 --- a/Core/NosSmooth.Game/PacketHandlers/Entities/SkillUsedResponder.cs +++ b/Core/NosSmooth.Game/PacketHandlers/Entities/SkillUsedResponder.cs @@ -82,9 +82,10 @@ public class SkillUsedResponder : IPacketResponder, IPacketResponder, IPacketResponder Respond(PacketEventArgs packetArgs, CancellationToken ct = default) { var packet = packetArgs.Packet; - var character = _game.Character; - if (character is not null && character.Skills is not null) + var skills = _game.Skills; + if (skills is not null) { - var skillResult = character.Skills.TryGetSkillByCastId(packet.SkillId); + var skillResult = skills.TryGetSkillByCastId(packet.SkillId); if (skillResult.IsDefined(out var skillEntity)) { skillEntity.IsOnCooldown = false; - await _eventDispatcher.DispatchEvent(new SkillReadyEvent(skillEntity, skillEntity.SkillVNum), ct); } + + await _eventDispatcher.DispatchEvent + (new SkillReadyEvent(skillEntity, skillEntity?.SkillVNum ?? packet.SkillId), ct); } else { diff --git a/Extensions/NosSmooth.Extensions.Combat/Operations/UsePrimarySkillOperation.cs b/Extensions/NosSmooth.Extensions.Combat/Operations/UsePrimarySkillOperation.cs index 3541006d25672d16288836bf293a57eb5fcb2c20..4d3894122e6ce99d932085374c9e0222dd22cfcb 100644 --- a/Extensions/NosSmooth.Extensions.Combat/Operations/UsePrimarySkillOperation.cs +++ b/Extensions/NosSmooth.Extensions.Combat/Operations/UsePrimarySkillOperation.cs @@ -65,13 +65,8 @@ public record UsePrimarySkillOperation(ILivingEntity Target) : ICombatOperation private Result GetPrimarySkill(ICombatState combatState) { - var character = combatState.Game.Character; - if (character is null) - { - return new CharacterNotInitializedError(); - } + var skills = combatState.Game.Skills; - var skills = character.Skills; if (skills is null) { return new CharacterNotInitializedError("Skills"); diff --git a/Extensions/NosSmooth.Extensions.Combat/Techniques/SimpleAttackTechnique.cs b/Extensions/NosSmooth.Extensions.Combat/Techniques/SimpleAttackTechnique.cs index 498ddb8df2f1cc20b3d78cbe59ecb3dabdb17b14..9d1d9a05671b2ebfdff138918b81182683e8dd26 100644 --- a/Extensions/NosSmooth.Extensions.Combat/Techniques/SimpleAttackTechnique.cs +++ b/Extensions/NosSmooth.Extensions.Combat/Techniques/SimpleAttackTechnique.cs @@ -87,7 +87,7 @@ public class SimpleAttackTechnique : ICombatTechnique if (_currentSkill is null) { - var skills = character.Skills; + var skills = state.Game.Skills; if (skills is null) { return new CharacterNotInitializedError("Skills");