From e7ace27f322d32e949143e82b9b2e1100178262e Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 23:47:24 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`buffs-3?= =?UTF-8?q?`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @Zintixx. * https://github.com/AngeloTadeucci/Maple2/pull/427#issuecomment-2831599255 The following files were modified: * `Maple2.Database/Context/MetadataContext.cs` * `Maple2.File.Ingest/Mapper/AdditionalEffectMapper.cs` * `Maple2.File.Ingest/Mapper/SkillMapper.cs` * `Maple2.File.Ingest/MapperExtensions.cs` * `Maple2.Server.Core/Packets/RequestPacket.cs` * `Maple2.Server.Game/Commands/BuffCommand.cs` * `Maple2.Server.Game/Commands/KillCommand.cs` * `Maple2.Server.Game/Manager/AnimationManager.cs` * `Maple2.Server.Game/Manager/Config/BuffManager.cs` * `Maple2.Server.Game/Manager/Config/SkillManager.cs` * `Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs` * `Maple2.Server.Game/Manager/Field/FieldManager/IField.cs` * `Maple2.Server.Game/Manager/Items/InventoryManager.cs` * `Maple2.Server.Game/Model/Field/Actor/Actor.cs` * `Maple2.Server.Game/Model/Field/Actor/FieldActor.cs` * `Maple2.Server.Game/Model/Field/Actor/FieldPet.cs` * `Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs` * `Maple2.Server.Game/Model/Field/Actor/IActor.cs` * `Maple2.Server.Game/Model/Field/Buff.cs` * `Maple2.Server.Game/Model/Field/Entity/FieldSkill.cs` * `Maple2.Server.Game/Model/Skill/DamageRecord.cs` * `Maple2.Server.Game/Model/Skill/SkillRecord.cs` * `Maple2.Server.Game/PacketHandlers/EmoteHandler.cs` * `Maple2.Server.Game/PacketHandlers/InteractObjectHandler.cs` * `Maple2.Server.Game/PacketHandlers/SkillHandler.cs` * `Maple2.Server.Game/Packets/SkillDamagePacket.cs` * `Maple2.Server.Game/Packets/SkillUseFailedPacket.cs` * `Maple2.Server.Game/Session/GameSession.cs` * `Maple2.Server.Game/Util/SkillUtils.cs` --- Maple2.Database/Context/MetadataContext.cs | 5 +- .../Mapper/AdditionalEffectMapper.cs | 16 +++- Maple2.File.Ingest/Mapper/SkillMapper.cs | 11 ++- Maple2.File.Ingest/MapperExtensions.cs | 12 ++- Maple2.Server.Core/Packets/RequestPacket.cs | 10 ++- Maple2.Server.Game/Commands/BuffCommand.cs | 13 ++- Maple2.Server.Game/Commands/KillCommand.cs | 8 +- .../Manager/AnimationManager.cs | 14 ++- .../Manager/Config/BuffManager.cs | 50 ++++++++++- .../Manager/Config/SkillManager.cs | 5 +- .../Field/FieldManager/FieldManager.State.cs | 14 ++- .../Manager/Field/FieldManager/IField.cs | 52 ++++++++++-- .../Manager/Items/InventoryManager.cs | 6 +- Maple2.Server.Game/Model/Field/Actor/Actor.cs | 85 ++++++++++++++++++- .../Model/Field/Actor/FieldActor.cs | 12 ++- .../Model/Field/Actor/FieldPet.cs | 14 ++- .../Model/Field/Actor/FieldPlayer.cs | 42 ++++++++- .../Model/Field/Actor/IActor.cs | 69 +++++++++++++-- Maple2.Server.Game/Model/Field/Buff.cs | 36 +++++++- .../Model/Field/Entity/FieldSkill.cs | 26 +++++- .../Model/Skill/DamageRecord.cs | 8 +- Maple2.Server.Game/Model/Skill/SkillRecord.cs | 13 ++- .../PacketHandlers/EmoteHandler.cs | 5 +- .../PacketHandlers/InteractObjectHandler.cs | 5 +- .../PacketHandlers/SkillHandler.cs | 32 ++++++- .../Packets/SkillDamagePacket.cs | 17 +++- .../Packets/SkillUseFailedPacket.cs | 7 +- Maple2.Server.Game/Session/GameSession.cs | 5 +- Maple2.Server.Game/Util/SkillUtils.cs | 46 +++++++++- 29 files changed, 586 insertions(+), 52 deletions(-) diff --git a/Maple2.Database/Context/MetadataContext.cs b/Maple2.Database/Context/MetadataContext.cs index f906796fb..2f8b59651 100644 --- a/Maple2.Database/Context/MetadataContext.cs +++ b/Maple2.Database/Context/MetadataContext.cs @@ -1,4 +1,4 @@ -using Maple2.Database.Extensions; +using Maple2.Database.Extensions; using Maple2.Database.Model.Metadata; using Maple2.Model.Game.Field; using Maple2.Model.Metadata; @@ -59,6 +59,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(ConfigureFunctionCubeMetadata); } + /// + /// Configures the Entity Framework Core mapping for the AdditionalEffectMetadata entity, including table name, composite primary key, and JSON conversion for complex properties. + /// private static void ConfigureAdditionalEffectMetadata(EntityTypeBuilder builder) { builder.ToTable("additional-effect"); builder.HasKey(effect => new { effect.Id, effect.Level }); diff --git a/Maple2.File.Ingest/Mapper/AdditionalEffectMapper.cs b/Maple2.File.Ingest/Mapper/AdditionalEffectMapper.cs index 85e687abf..322c5a713 100644 --- a/Maple2.File.Ingest/Mapper/AdditionalEffectMapper.cs +++ b/Maple2.File.Ingest/Mapper/AdditionalEffectMapper.cs @@ -1,4 +1,4 @@ -using Maple2.File.IO; +using Maple2.File.IO; using Maple2.File.Parser; using Maple2.File.Parser.Xml.AdditionalEffect; using Maple2.Model.Enum; @@ -16,6 +16,10 @@ public AdditionalEffectMapper(M2dReader xmlReader) { parser = new AdditionalEffectParser(xmlReader); } + /// + /// Maps parsed additional effect data into strongly typed objects. + /// + /// An enumerable of representing all parsed additional effects. protected override IEnumerable Map() { foreach ((int id, IList datas) in parser.Parse()) { foreach (AdditionalEffectData data in datas) { @@ -231,6 +235,11 @@ private static AdditionalEffectMetadataStatus Convert(StatusProperty status, Off NotKill: dotDamage.notKill); } + /// + /// Converts a to a if the buff ID is positive; otherwise returns null. + /// + /// The DOT buff property to convert. + /// A instance if valid; otherwise, null. private static AdditionalEffectMetadataDot.DotBuff? Convert(DotBuffProperty? dotBuff) { if (dotBuff is not { buffID: > 0 }) { return null; @@ -239,6 +248,11 @@ private static AdditionalEffectMetadataStatus Convert(StatusProperty status, Off return new AdditionalEffectMetadataDot.DotBuff(Target: (SkillTargetType) dotBuff.target, Id: dotBuff.buffID, Level: dotBuff.buffLevel); } + /// + /// Converts a to an if shield values are positive; otherwise returns null. + /// + /// The shield property to convert. + /// An if applicable; otherwise, null. private static AdditionalEffectMetadataShield? Convert(ShieldProperty shield) { if (shield is { hpValue: <= 0, hpByTargetMaxHP: <= 0 }) { return null; diff --git a/Maple2.File.Ingest/Mapper/SkillMapper.cs b/Maple2.File.Ingest/Mapper/SkillMapper.cs index bb36817e9..fe73e02d2 100644 --- a/Maple2.File.Ingest/Mapper/SkillMapper.cs +++ b/Maple2.File.Ingest/Mapper/SkillMapper.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using Maple2.File.IO; using Maple2.File.Parser; using Maple2.File.Parser.Xml.Skill; @@ -14,6 +14,10 @@ public SkillMapper(M2dReader xmlReader) { parser = new SkillParser(xmlReader); } + /// + /// Maps parsed skill XML data into structured objects, transforming raw skill definitions into strongly typed metadata for further processing. + /// + /// An enumerable sequence of representing all valid skills parsed from the source data. protected override IEnumerable Map() { foreach ((int id, string name, SkillData data) in parser.Parse()) { if (data.basic == null) continue; // Old_JobChange_01 @@ -133,6 +137,11 @@ protected override IEnumerable Map() { } } + /// + /// Converts a object into a , mapping region type strings to values and transferring relevant range properties. + /// + /// The region skill data to convert. + /// A representing the region's metadata. private static SkillMetadataRange Convert(RegionSkill region) { return new SkillMetadataRange( Type: region.rangeType switch { diff --git a/Maple2.File.Ingest/MapperExtensions.cs b/Maple2.File.Ingest/MapperExtensions.cs index 7db71d85b..67e06444b 100644 --- a/Maple2.File.Ingest/MapperExtensions.cs +++ b/Maple2.File.Ingest/MapperExtensions.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using System.Diagnostics; using System.Reflection; using Maple2.File.Ingest.Utils; @@ -227,6 +227,11 @@ public static byte OptionIndex(this SpecialAttribute attribute) { }; } + /// + /// Converts a instance into a , mapping its properties to either a splash or condition effect and assembling the associated skills. + /// + /// The trigger skill data to convert. + /// A representing the trigger's effect, including splash or condition details and linked skills. public static SkillEffectMetadata Convert(this TriggerSkill trigger) { SkillEffectMetadataCondition? condition = null; SkillEffectMetadataSplash? splash = null; @@ -316,6 +321,11 @@ public static SkillMetadataAutoTargeting Convert(this AutoTargeting autoTargetin UseMove: autoTargeting.autoTargetUseMove); } + /// + /// Converts a parsed XML skill begin condition into a strongly typed metadata object for use in Maple2 game logic. + /// + /// The XML-parsed skill begin condition to convert. + /// A instance containing mapped level, gender, mesos, stats, map and skill requirements, job codes, probability, cooldowns, durations, state flags, dungeon group types, weapon requirements, and subconditions for target, owner, and caster. public static BeginCondition Convert(this Maple2.File.Parser.Xml.Skill.BeginCondition beginCondition) { return new BeginCondition( Level: beginCondition.level, diff --git a/Maple2.Server.Core/Packets/RequestPacket.cs b/Maple2.Server.Core/Packets/RequestPacket.cs index 676f16604..392426a98 100644 --- a/Maple2.Server.Core/Packets/RequestPacket.cs +++ b/Maple2.Server.Core/Packets/RequestPacket.cs @@ -1,4 +1,4 @@ -using Maple2.PacketLib.Tools; +using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; namespace Maple2.Server.Core.Packets; @@ -8,10 +8,18 @@ public static ByteWriter Login() { return Packet.Of(SendOp.RequestLogin); } + /// + /// Creates a packet for requesting a session key from the server. + /// + /// A containing the key request packet. public static ByteWriter Key() { return Packet.Of(SendOp.RequestKey); } + /// + /// Creates a heartbeat request packet containing the current system tick count. + /// + /// A ByteWriter representing the heartbeat request packet. public static ByteWriter Heartbeat() { var pWriter = Packet.Of(SendOp.RequestHeartbeat); pWriter.WriteInt(Environment.TickCount); diff --git a/Maple2.Server.Game/Commands/BuffCommand.cs b/Maple2.Server.Game/Commands/BuffCommand.cs index f444ae7ae..38ff6a57c 100644 --- a/Maple2.Server.Game/Commands/BuffCommand.cs +++ b/Maple2.Server.Game/Commands/BuffCommand.cs @@ -1,4 +1,4 @@ -using System.CommandLine; +using System.CommandLine; using System.CommandLine.Invocation; using System.CommandLine.IO; using Maple2.Database.Storage; @@ -40,6 +40,17 @@ public BuffCommand(GameSession session, SkillMetadataStorage skillStorage) : bas this.SetHandler(Handle, id, level, stack, duration, all, target, remove); } + /// + /// Processes the "buff" command to add or remove a specified buff on one or more players in the current field. + /// + /// The command invocation context. + /// The ID of the buff to add or remove. + /// The level of the buff. + /// The number of buff stacks to apply. + /// The duration of the buff in seconds, or -1 for default duration. + /// If true, applies the operation to all players in the field. + /// The name of the target player to affect, or empty to target the command issuer. + /// If true, removes the buff instead of adding it. private void Handle(InvocationContext ctx, int buffId, int level, int stack, int duration, bool all, string target, bool remove) { try { if (!skillStorage.TryGetEffect(buffId, (short) level, out AdditionalEffectMetadata? _)) { diff --git a/Maple2.Server.Game/Commands/KillCommand.cs b/Maple2.Server.Game/Commands/KillCommand.cs index 115dde772..a2dc5eceb 100644 --- a/Maple2.Server.Game/Commands/KillCommand.cs +++ b/Maple2.Server.Game/Commands/KillCommand.cs @@ -1,4 +1,4 @@ -using System.CommandLine; +using System.CommandLine; using System.CommandLine.Invocation; using System.CommandLine.IO; using System.Numerics; @@ -141,6 +141,12 @@ private void Handle(InvocationContext ctx, string name) { } } + /// + /// Instantly kills the specified NPC by applying damage equal to its current health and broadcasts the resulting updates to the field. + /// + /// The game session performing the kill action. + /// The NPC to be killed. + /// The skill metadata used to generate the damage record. private static void Kill(GameSession session, FieldNpc npc, SkillMetadata skill) { var damageRecord = new DamageRecord(skill, skill.Data.Motions[0].Attacks[0]) { CasterId = session.Player.ObjectId, diff --git a/Maple2.Server.Game/Manager/AnimationManager.cs b/Maple2.Server.Game/Manager/AnimationManager.cs index d92dd0741..e96ba960b 100644 --- a/Maple2.Server.Game/Manager/AnimationManager.cs +++ b/Maple2.Server.Game/Manager/AnimationManager.cs @@ -1,4 +1,4 @@ -using Maple2.Model.Enum; +using Maple2.Model.Enum; using Maple2.Model.Metadata; using Maple2.Server.Core.Packets; using Maple2.Server.Game.Model; @@ -199,7 +199,10 @@ public void CancelSequence() { /// /// Updates the animation state based on the current tick count. /// - /// The current server tick count + /// + /// Updates the animation state for the actor based on the current server tick, processing keyframe events, handling looping, and resetting sequences as needed. + /// + /// The current server tick count. public void Update(long tickCount) { // Skip update if no animation metadata is available if (RigMetadata is null) { @@ -349,7 +352,12 @@ public float GetSequenceSegmentTime(string keyframe1, string keyframe2) { /// /// The current sequence time /// The keyframe that was hit - /// The current animation speed + /// + /// Handles a keyframe event during an animation sequence, triggering actor callbacks and updating loop or end timing based on the keyframe type. + /// + /// The current normalized time within the animation sequence. + /// The animation keyframe being processed. + /// The current animation speed. private void HitKeyframe(float sequenceTime, AnimationKey key, float speed) { isHandlingKeyframe = true; diff --git a/Maple2.Server.Game/Manager/Config/BuffManager.cs b/Maple2.Server.Game/Manager/Config/BuffManager.cs index 238ca02f9..4e7bbe7cf 100644 --- a/Maple2.Server.Game/Manager/Config/BuffManager.cs +++ b/Maple2.Server.Game/Manager/Config/BuffManager.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Numerics; using Maple2.Model.Enum; using Maple2.Model.Game; @@ -61,6 +61,9 @@ public void Clear() { } } + /// + /// Applies entrance buffs and refreshes premium club buffs for the actor when entering a field. + /// public void LoadFieldBuffs() { // Lapenshards // Game Events @@ -71,6 +74,18 @@ public void LoadFieldBuffs() { } } + /// + /// Adds a buff to the specified owner, handling stacking, duration, cooldowns, group conflicts, and effect application. + /// + /// The actor applying the buff. + /// The actor receiving the buff. + /// The buff's skill or effect ID. + /// The level of the buff. + /// The tick count when the buff starts. + /// The number of stacks to apply (clamped to the buff's maximum). + /// The duration of the buff in milliseconds. If negative, uses the default duration. + /// Whether to broadcast the buff addition to the field. + /// The event condition type triggering the buff application. public void AddBuff(IActor caster, IActor owner, int id, short level, long startTick, int stacks = 0, int durationMs = -1, bool notifyField = true, EventConditionType type = EventConditionType.Activate) { if (!owner.Field.SkillMetadata.TryGetEffect(id, level, out AdditionalEffectMetadata? additionalEffect)) { logger.Error("Invalid buff: {SkillId},{Level}", id, level); @@ -310,6 +325,11 @@ public float TotalCompulsionRate(CompulsionEventType type, int skillId = 0) { nestedCompulsionDic.Values.Where(compulsion => compulsion.SkillIds.Contains(skillId)).Sum(compulsion => compulsion.Rate); } + /// + /// Returns the resistance value for the specified attribute, or 0 if not present. + /// + /// The attribute for which to retrieve resistance. + /// The resistance value for the given attribute, or 0 if none is set. public float GetResistance(BasicAttribute attribute) { if (Resistances.TryGetValue(attribute, out float value)) { return value; @@ -318,6 +338,13 @@ public float GetResistance(BasicAttribute attribute) { return 0; } + /// + /// Calculates the total invoke value and rate for a specified invoke effect type, filtered by skill ID or skill group. + /// + /// The type of invoke effect to aggregate. + /// The skill ID to match against invoke effects. + /// Optional skill group IDs to match against invoke effects. + /// A tuple containing the total invoke value (as an integer) and the total invoke rate (as a float). public (int, float) GetInvokeValues(InvokeEffectType invokeType, int skillId, params int[] skillGroup) { if (!Invokes.TryGetValue(invokeType, out var nestedInvokeDic)) return (0, 0f); @@ -335,6 +362,9 @@ public float GetResistance(BasicAttribute attribute) { return ((int) value, rate); } + /// + /// Sets the shield health for a buff based on its metadata, using either a fixed value or a percentage of the actor's maximum health. + /// private void SetShield(Buff buff) { if (buff.Metadata.Shield == null) { return; @@ -369,6 +399,9 @@ private void SetMount(Buff buff) { } } + /// + /// Applies update effects from the buff, including canceling specified buffs and resetting skill cooldowns for the actor. + /// private void SetUpdates(Buff buff) { if (buff.Metadata.Update.Cancel != null) { CancelBuffs(buff, buff.Metadata.Update.Cancel); @@ -381,6 +414,15 @@ private void SetUpdates(Buff buff) { } } } + /// + /// Triggers an event for all enabled buffs, causing the owner to apply each buff's effects for the specified event type. + /// + /// The actor who initiated the event. + /// The actor who owns the buffs. + /// The target actor affected by the event. + /// The event condition type that determines which effects to apply. + /// Optional skill ID associated with the event. + /// Optional buff ID associated with the event. public void TriggerEvent(IActor caster, IActor owner, IActor target, EventConditionType type, int skillId = 0, int buffId = 0) { foreach (Buff buff in EnumerateBuffs()) { if (!buff.Enabled) { @@ -520,6 +562,12 @@ public void Remove(params (int id, int casterId)[] buffIds) { } } + /// + /// Removes all buffs with the specified ID and caster ID from the actor, updates resistances, handles related effects, and refreshes stats if necessary. + /// + /// The buff ID to remove. + /// The object ID of the caster whose buffs should be removed. + /// True if the removal process completes. public bool Remove(int id, int casterId) { //TODO: Check if buff is removable/should be removed bool refreshStats = false; diff --git a/Maple2.Server.Game/Manager/Config/SkillManager.cs b/Maple2.Server.Game/Manager/Config/SkillManager.cs index a49a6149f..90e11a7ae 100644 --- a/Maple2.Server.Game/Manager/Config/SkillManager.cs +++ b/Maple2.Server.Game/Manager/Config/SkillManager.cs @@ -1,4 +1,4 @@ -using Maple2.Database.Storage; +using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; @@ -30,6 +30,9 @@ public void LoadSkillBook() { session.Send(SkillBookPacket.Load(SkillBook)); } + /// + /// Applies all passive skill effects that target the player, updating active buffs based on the player's learned passive skills. + /// public void UpdatePassiveBuffs(bool notifyField = true) { // TODO: Only remove buffs that have been unlearned. /*foreach (Buff buff in session.Player.Buffs.Buffs.Values) { diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index 4a264738e..5eaf7d29f 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Numerics; @@ -437,6 +437,10 @@ public void AddSkill(IActor caster, SkillEffectMetadata effect, Vector3[] points } } + /// + /// Adds splash skill effects from a skill record, calculating effect positions based on cube magic paths if applicable. + /// + /// The skill record containing caster, position, rotation, and attack metadata. public void AddSkill(SkillRecord record) { SkillMetadataAttack attack = record.Attack; if (!TableMetadata.MagicPathTable.Entries.TryGetValue(attack.CubeMagicPathId, out IReadOnlyList? cubeMagicPaths)) { @@ -474,6 +478,14 @@ public void AddSkill(SkillRecord record) { } } + /// + /// Returns a filtered collection of actors within the specified prisms, based on the target type and limit. + /// + /// The prisms used to filter actors by location or area. + /// The type of targets to select (e.g., friendly players, hostile mobs, or hungry mobs). + /// The maximum number of actors to return. + /// An optional collection of actors to exclude from the results. + /// An enumerable of actors matching the criteria, or an empty collection if the target type is unhandled. public IEnumerable GetTargets(Prism[] prisms, ApplyTargetType targetType, int limit, ICollection? ignore = null) { switch (targetType) { case ApplyTargetType.Friendly: diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/IField.cs b/Maple2.Server.Game/Manager/Field/FieldManager/IField.cs index c0aa4075e..c8324c7c1 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/IField.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/IField.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Numerics; using Maple2.Database.Storage; @@ -59,13 +59,49 @@ public interface IField : IDisposable { public long FieldTick { get; } public virtual void Init() { } - public void AddSkill(SkillMetadata metadata, int interval, in Vector3 position, in Vector3 rotation = default); - public void AddSkill(SkillRecord record); - public void AddSkill(IActor caster, SkillEffectMetadata effect, Vector3[] points, in Vector3 rotation = default); - public IEnumerable GetTargets(Prism[] prisms, ApplyTargetType targetType, int limit, ICollection? ignore = null); - public void RemoveSkill(int objectId); - public void Broadcast(ByteWriter packet, GameSession? sender = null); - public void BroadcastAiMessage(ByteWriter packet); + /// +/// Adds a skill effect to the field at the specified position and rotation, with a given interval. +/// +/// Metadata describing the skill to add. +/// The interval, in milliseconds, for the skill's effect or duration. +/// The world position where the skill effect is placed. +/// The rotation of the skill effect. Defaults to no rotation if not specified. +public void AddSkill(SkillMetadata metadata, int interval, in Vector3 position, in Vector3 rotation = default); + /// +/// Adds a skill to the field using the specified skill record. +/// +/// The skill record containing information about the skill to add. +public void AddSkill(SkillRecord record); + /// +/// Adds a skill effect to the field, originating from the specified caster, using the given effect metadata, points, and rotation. +/// +/// The actor casting the skill. +/// Metadata describing the skill effect to apply. +/// An array of points defining the effect's area or trajectory. +/// The rotation to apply to the skill effect. Defaults to no rotation. +public void AddSkill(IActor caster, SkillEffectMetadata effect, Vector3[] points, in Vector3 rotation = default); + /// +/// Returns a collection of actors within the specified prisms that match the given target type, up to the specified limit. +/// +/// Geometric prisms used to define the target search area. +/// The type of targets to include (e.g., enemies, allies). +/// The maximum number of actors to return. +/// Optional collection of actors to exclude from the results. +/// An enumerable of actors matching the criteria. +public IEnumerable GetTargets(Prism[] prisms, ApplyTargetType targetType, int limit, ICollection? ignore = null); + /// +/// Removes a skill effect or instance from the field by its object ID. +/// +/// The unique identifier of the skill to remove. +public void RemoveSkill(int objectId); + /// +/// Sends a packet to all players in the field, optionally excluding the specified sender. +/// +public void Broadcast(ByteWriter packet, GameSession? sender = null); + /// +/// Broadcasts an AI-related message packet to all relevant entities in the field. +/// +public void BroadcastAiMessage(ByteWriter packet); public void BroadcastAiType(GameSession requester); public void SetRoomTimer(RoomTimerType type, int duration); //TODO: MOVE THIS TO RANDOM ONLY diff --git a/Maple2.Server.Game/Manager/Items/InventoryManager.cs b/Maple2.Server.Game/Manager/Items/InventoryManager.cs index bd7672667..b40c56903 100644 --- a/Maple2.Server.Game/Manager/Items/InventoryManager.cs +++ b/Maple2.Server.Game/Manager/Items/InventoryManager.cs @@ -1,4 +1,4 @@ -using System.Collections.Immutable; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using Maple2.Database.Storage; using Maple2.Model; @@ -253,6 +253,10 @@ public bool Add(Item add, bool notifyNew = false, bool commit = false) { } } + /// + /// Adds the specified currency or stat amount to the player's session based on the item's ID. + /// + /// The item representing the currency or stat to add, with its amount. private void AddCurrency(Item add) { switch (add.Id) { case 90000001 or 90000002 or 90000003: diff --git a/Maple2.Server.Game/Model/Field/Actor/Actor.cs b/Maple2.Server.Game/Model/Field/Actor/Actor.cs index b18655053..a5904141a 100644 --- a/Maple2.Server.Game/Model/Field/Actor/Actor.cs +++ b/Maple2.Server.Game/Model/Field/Actor/Actor.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics; using System.Numerics; using Maple2.Model.Enum; @@ -56,6 +56,13 @@ public virtual Vector3 Rotation { /// public (Vector3 Position, long LastTick, long Duration) PositionTick { get; set; } + /// + /// Initializes a new instance of the class with the specified field, object ID, value, and NPC metadata. + /// + /// The field manager responsible for this actor's environment. + /// The unique identifier for the actor. + /// The value or entity represented by this actor. + /// Metadata storage for NPC-related data. protected Actor(FieldManager field, int objectId, T value, NpcMetadataStorage npcMetadata) { Field = field; ObjectId = objectId; @@ -71,6 +78,9 @@ protected Actor(FieldManager field, int objectId, T value, NpcMetadataStorage np ActiveSkills = new SkillQueue(); } + /// + /// Releases resources used by the actor. + /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); @@ -78,6 +88,17 @@ public void Dispose() { protected virtual void Dispose(bool disposing) { } + /// + /// Applies a skill effect from a caster to an owner, adding one or more buffs based on the effect's conditions. + /// + /// The actor applying the effect. + /// The actor receiving the effect. + /// The skill effect metadata describing the buffs to apply. + /// The game tick when the effect starts. + /// The event condition type triggering the effect. + /// The skill ID associated with the effect. + /// The buff ID associated with the effect. + /// Whether to notify the field of the buff application. public virtual void ApplyEffect(IActor caster, IActor owner, SkillEffectMetadata effect, long startTick, EventConditionType type = EventConditionType.Activate, int skillId = 0, int buffId = 0, bool notifyField = true) { Debug.Assert(effect.Condition != null); @@ -91,6 +112,9 @@ public virtual void ApplyEffect(IActor caster, IActor owner, SkillEffectMetadata } } + /// + /// Applies damage from a caster to this actor using the provided damage record and attack metadata, updating health, tracking damage sources, and triggering relevant buff events based on damage type. + /// public virtual void ApplyDamage(IActor caster, DamageRecord damage, SkillMetadataAttack attack) { var targetRecord = new DamageRecordTarget(this) { Position = caster.Position, @@ -147,6 +171,10 @@ public virtual void ApplyDamage(IActor caster, DamageRecord damage, SkillMetadat } } + /// + /// Applies a reflect effect to the target actor if the reflect buff is active and within its usage limits. + /// + /// The actor to receive the reflected effect. public virtual void Reflect(IActor target) { if (Buffs.Reflect == null || Buffs.Reflect.Counter >= Buffs.Reflect.Metadata.Count) { return; @@ -166,6 +194,9 @@ public virtual void Reflect(IActor target) { // TODO: Reflect should also amend the target's damage record from Reflect.ReflectValues and ReflectRates } + /// + /// Executes an attack on multiple targets, applying damage, broadcasting the results, and triggering associated skill effects. + /// public virtual void TargetAttack(SkillRecord record) { if (record.Targets.Count == 0) { return; @@ -198,6 +229,14 @@ public virtual void TargetAttack(SkillRecord record) { }*/ } + /// + /// Resolves and returns the appropriate actor based on the specified skill target type. + /// + /// The type of target to resolve (e.g., owner, caster, target, etc.). + /// The actor casting the skill. + /// The primary target actor. + /// The owner actor, if applicable. + /// The actor corresponding to the given target type. public virtual IActor GetTarget(SkillTargetType targetType, IActor caster, IActor target, IActor owner) { return targetType switch { SkillTargetType.Owner => owner, @@ -209,6 +248,14 @@ public virtual IActor GetTarget(SkillTargetType targetType, IActor caster, IActo }; } + /// + /// Resolves and returns the owner actor based on the specified skill target type. + /// + /// The type of skill target to resolve. + /// The actor casting the skill. + /// The primary target actor. + /// The owner actor, if applicable. + /// The resolved owner actor according to the target type. public IActor GetOwner(SkillTargetType targetType, IActor caster, IActor target, IActor owner) { return targetType switch { SkillTargetType.Owner => owner, @@ -222,7 +269,16 @@ public IActor GetOwner(SkillTargetType targetType, IActor caster, IActor target, /// /// Filter effects before applying. This is needed instead of applying as iterating to ensure the current state of the actor is used. + /// + /// Applies skill effects to target actors based on specified conditions and event type. /// + /// Array of skill effect metadata to evaluate and apply. + /// The actor casting the skill. + /// The owner actor for effect resolution. + /// The event condition type that triggers effect application. + /// The skill ID associated with the effect, if applicable. + /// The buff ID associated with the effect, if applicable. + /// Target actors to evaluate for effect application. public virtual void ApplyEffects(SkillEffectMetadata[] effects, IActor caster, IActor owner, EventConditionType type = EventConditionType.Activate, int skillId = 0, int buffId = 0, params IActor[] targets) { var appliedEffects = new List<(IActor Owner, IActor Caster, SkillEffectMetadata Effect)>(); long startTick = Field.FieldTick; @@ -250,7 +306,13 @@ public virtual void ApplyEffects(SkillEffectMetadata[] effects, IActor caster, I /// /// /// - /// + /// + /// Applies skill effects to targets based on damage dealt, ensuring effects are only applied if the target received damage from the skill. + /// + /// The skill effects to apply. + /// The actor casting the skill. + /// The damage record containing attack and target information. + /// The actors to potentially receive effects. public virtual void ApplyEffects(SkillEffectMetadata[] effects, IActor caster, DamageRecord record, params IActor[] targets) { // Skill does no damage, apply effects regardless if (record.AttackMetadata.Damage.Count == 0) { @@ -283,6 +345,10 @@ bool DealtDamage(IActor target) { } } + /// + /// Updates the actor's state for the current tick, handling death, position tracking, animation, and buffs. + /// + /// The current server tick count. public virtual void Update(long tickCount) { if (IsDead) return; @@ -304,6 +370,14 @@ public virtual void Update(long tickCount) { public virtual void KeyframeEvent(string keyName) { } + /// + /// Attempts to cast a skill by its ID and level, creating and broadcasting a skill record if valid. + /// + /// The skill's unique identifier. + /// The level of the skill to cast. + /// Optional unique identifier for the skill instance. + /// Optional motion point for the skill animation. + /// The created if the skill is valid and motion point is set; otherwise, null. public virtual SkillRecord? CastSkill(int id, short level, long uid = 0, byte motionPoint = 0) { if (!Field.SkillMetadata.TryGet(id, level, out SkillMetadata? metadata)) { Logger.Error("Invalid skill use: {SkillId},{Level}", id, level); @@ -325,13 +399,20 @@ public virtual void KeyframeEvent(string keyName) { } return record; } + /// + /// Invoked when the actor dies, triggering all buffs' OnDeath events for this actor. + /// protected virtual void OnDeath() { Buffs.TriggerEvent(this, this, this, EventConditionType.OnDeath); } /// /// Consumes needed stats to cast skill. + /// + /// Determines whether the actor can consume the required resources to cast the specified skill. /// + /// The skill record representing the skill to be cast. + /// True if the skill can be cast; otherwise, false. public virtual bool SkillCastConsume(SkillRecord record) { return true; } diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldActor.cs b/Maple2.Server.Game/Model/Field/Actor/FieldActor.cs index 1f993f222..2d9242a57 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldActor.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldActor.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Maple2.Model.Enum; using Maple2.Server.Game.Manager.Config; using Maple2.Server.Game.Manager.Field; @@ -30,6 +30,11 @@ internal sealed class FieldActor : IActor { public SkillState SkillState { get; init; } public SkillQueue ActiveSkills { get; init; } + /// + /// Initializes a new instance of the class, setting up its field association, metadata, stats, buffs, transform, animation manager, skill state, and active skills queue. + /// + /// The field manager that owns this actor. + /// The metadata storage for NPCs associated with this actor. public FieldActor(FieldManager field, NpcMetadataStorage npcMetadata) { Field = field; Stats = new StatsManager(this); @@ -41,5 +46,8 @@ public FieldActor(FieldManager field, NpcMetadataStorage npcMetadata) { ActiveSkills = new SkillQueue(); } - public void Update(long tickCount) { } + /// +/// Performs no operation during the update cycle for this actor. +/// +public void Update(long tickCount) { } } diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs index db7fd3d18..fd582d5c0 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs @@ -1,4 +1,4 @@ -using DotRecast.Detour.Crowd; +using DotRecast.Detour.Crowd; using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Game; @@ -56,6 +56,12 @@ public override void Update(long tickCount) { } } + /// + /// Applies taming-related damage to the pet based on the attack, handling taming progress, trap effects, and item drops upon successful taming or forced taming. + /// + /// The actor attempting to tame or damage the pet. + /// The damage record to update with the result of the attack. + /// The attack metadata, which must include pet taming data. public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetadataAttack attack) { if (attack.Pet == null) { return; @@ -86,7 +92,11 @@ public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetada damage.Targets.TryAdd(ObjectId, targetRecord); } - protected override void Remove(int delay) => Field.RemovePet(ObjectId, delay); + /// +/// Removes the pet from the field after the specified delay. +/// +/// The delay in milliseconds before removal. +protected override void Remove(int delay) => Field.RemovePet(ObjectId, delay); public void UpdateSkin(int skinId) { SkinId = skinId > 0 ? skinId : Value.Id; diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs index bbca1d7fa..83abd673c 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Maple2.Model.Enum; using Maple2.Model.Error; using Maple2.Model.Game; @@ -92,6 +92,11 @@ public AdminPermissions AdminPermissions { private readonly EventQueue scheduler; + /// + /// Initializes a new instance of the class, setting up player state, regeneration tracking, event scheduling, and animation references for the associated game session. + /// + /// The game session associated with the player. + /// The player entity represented by this field actor. public FieldPlayer(GameSession session, Player player) : base(session.Field, player.ObjectId, player, session.NpcMetadata) { Session = session; Animation = Session.Animation; @@ -138,6 +143,9 @@ public bool DebugAi { } } + /// + /// Updates the player's state for the current tick, handling state broadcasts, death and revival logic, battle state timeout, stat regeneration, and game event updates. + /// public override void Update(long tickCount) { base.Update(tickCount); @@ -201,6 +209,10 @@ public override void Update(long tickCount) { Session.GameEvent.Update(tickCount); } + /// + /// Synchronizes the player's state with incoming state data, updating position, rotation, state, and substate, and triggers relevant condition updates based on movement and activity. + /// + /// The state synchronization data containing the player's latest position, rotation, state, and substate. public void OnStateSync(StateSync stateSync) { if (Position != stateSync.Position) { Flag |= PlayerObjectFlag.Position; @@ -408,7 +420,10 @@ public void RecoverHp(int amount) { /// /// Consumes health and starts regen if not already started. /// - /// + /// + /// Reduces the player's health by the specified amount and broadcasts the updated health to the session and field. + /// + /// The amount of health to consume. Must be positive. public void ConsumeHp(int amount) { if (amount <= 0) { return; @@ -456,7 +471,10 @@ public void RecoverSp(int amount) { /// /// Consumes spirit and starts regen if not already started. /// - /// + /// + /// Reduces the player's spirit by the specified amount and broadcasts the updated value to the field. + /// + /// The amount of spirit to consume. public void ConsumeSp(int amount) { if (amount <= 0) { return; @@ -493,7 +511,11 @@ public void RecoverStamina(int amount) { /// Consumes stamina. /// /// The amount - /// If regen shouldn't be started + /// + /// Reduces the player's stamina by the specified amount and broadcasts the updated value to the field. + /// + /// The amount of stamina to consume. + /// If true, prevents stamina regeneration from starting after consumption. public void ConsumeStamina(int amount, bool noRegen = false) { if (amount <= 0) { return; @@ -510,6 +532,9 @@ public void ConsumeStamina(int amount, bool noRegen = false) { Field.Broadcast(StatsPacket.Update(this, BasicAttribute.Stamina)); } + /// + /// Ensures that health, spirit, and stamina regeneration tracking is active if the player's current values are below their maximum. + /// public void CheckRegen() { // Health var health = Stats.Values[BasicAttribute.Health]; @@ -550,6 +575,10 @@ public void MoveToPortal(FieldPortal portal) { Session.Send(PortalPacket.MoveByPortal(this, portal.Position, portal.Rotation)); } + /// + /// Applies fall damage to the player based on the distance fallen, reducing health and broadcasting updates. + /// + /// The distance the player has fallen. public void FallDamage(float distance) { double distanceScalingFactor = 0.04813; // base distance scaling factor double hpRatioExponent = 1.087; // HP ratio exponent for diminishing returns @@ -575,6 +604,11 @@ public void FallDamage(float distance) { } } + /// + /// Consumes the required resources for casting a skill, including mesos, spirit, stamina, health percentage, and items, applying any relevant buffs or reductions. + /// + /// The skill record containing metadata and item usage information. + /// True if all required resources are successfully consumed; otherwise, false. public override bool SkillCastConsume(SkillRecord record) { if (!base.SkillCastConsume(record)) { return false; diff --git a/Maple2.Server.Game/Model/Field/Actor/IActor.cs b/Maple2.Server.Game/Model/Field/Actor/IActor.cs index 9efa39a53..298ef5f56 100644 --- a/Maple2.Server.Game/Model/Field/Actor/IActor.cs +++ b/Maple2.Server.Game/Model/Field/Actor/IActor.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Metadata; @@ -22,14 +22,67 @@ public interface IActor : IFieldEntity { public bool IsDead { get; } public IPrism Shape { get; } public SkillQueue ActiveSkills { get; init; } - public virtual void ApplyEffects(SkillEffectMetadata[] effects, IActor caster, IActor owner, EventConditionType type = EventConditionType.Activate, int skillId = 0, int buffId = 0, params IActor[] targets) { } - public virtual void ApplyEffects(SkillEffectMetadata[] effects, IActor caster, DamageRecord record, params IActor[] targets) { } - public virtual void ApplyEffect(IActor caster, IActor owner, SkillEffectMetadata effect, long startTick, EventConditionType type = EventConditionType.Activate, int skillId = 0, int buffId = 0, bool notifyField = true) { } - public virtual void ApplyDamage(IActor caster, DamageRecord damage, SkillMetadataAttack attack) { } - public virtual IActor GetTarget(SkillTargetType targetType, IActor caster, IActor target, IActor owner) { return this; } - public virtual IActor GetOwner(SkillTargetType targetType, IActor caster, IActor target, IActor owner) { return this; } + /// +/// Applies multiple skill effects to this actor, with optional context for caster, owner, event condition, skill and buff identifiers, and target actors. +/// +/// The array of skill effects to apply. +/// The actor casting the effects. +/// The owner actor associated with the effects. +/// The event condition type triggering the effects. +/// The skill identifier associated with the effects. +/// The buff identifier associated with the effects. +/// Optional target actors to which the effects are applied. +public virtual void ApplyEffects(SkillEffectMetadata[] effects, IActor caster, IActor owner, EventConditionType type = EventConditionType.Activate, int skillId = 0, int buffId = 0, params IActor[] targets) { } + /// +/// Applies multiple skill effects to the actor using the provided damage record and optional target actors. +/// +/// An array of skill effect metadata to apply. +/// The actor casting the effects. +/// The damage record associated with the effects. +/// Optional target actors to receive the effects. +public virtual void ApplyEffects(SkillEffectMetadata[] effects, IActor caster, DamageRecord record, params IActor[] targets) { } + /// +/// Applies a single skill effect to the actor, specifying the caster, owner, effect metadata, timing, and related identifiers. +/// +/// The actor applying the effect. +/// The owner of the effect, if different from the caster. +/// Metadata describing the skill effect to apply. +/// The game tick when the effect starts. +/// The event condition type triggering the effect. +/// The ID of the skill associated with the effect. +/// The ID of the buff associated with the effect. +/// Whether to notify the field of the effect application. +public virtual void ApplyEffect(IActor caster, IActor owner, SkillEffectMetadata effect, long startTick, EventConditionType type = EventConditionType.Activate, int skillId = 0, int buffId = 0, bool notifyField = true) { } + /// +/// Applies damage to the actor based on the provided damage record and attack metadata. +/// +/// The actor inflicting the damage. +/// Details of the damage to apply. +/// Metadata describing the attack causing the damage. +public virtual void ApplyDamage(IActor caster, DamageRecord damage, SkillMetadataAttack attack) { } + /// +/// Resolves and returns the target actor for a skill based on the specified target type and context. +/// +/// The type of target selection for the skill. +/// The actor casting the skill. +/// The initially intended target actor. +/// The owner actor, if applicable. +/// The resolved target actor. Default implementation returns the current actor instance. +public virtual IActor GetTarget(SkillTargetType targetType, IActor caster, IActor target, IActor owner) { return this; } + /// +/// Resolves and returns the owner actor for a skill action based on the specified target type and context. +/// +/// The type of skill target to consider when determining the owner. +/// The actor casting the skill. +/// The intended target actor. +/// The actor designated as the owner in the skill context. +/// The resolved owner actor for the skill action. By default, returns the current actor instance. +public virtual IActor GetOwner(SkillTargetType targetType, IActor caster, IActor target, IActor owner) { return this; } - public virtual void TargetAttack(SkillRecord record) { } + /// +/// Processes an attack on a target using the specified skill record. +/// +public virtual void TargetAttack(SkillRecord record) { } public virtual SkillRecord? CastSkill(int id, short level, long uid = 0, byte motionPoint = 0) { return null; } public virtual void KeyframeEvent(string keyName) { } diff --git a/Maple2.Server.Game/Model/Field/Buff.cs b/Maple2.Server.Game/Model/Field/Buff.cs index 3db857a2c..93adb71b8 100644 --- a/Maple2.Server.Game/Model/Field/Buff.cs +++ b/Maple2.Server.Game/Model/Field/Buff.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Maple2.Model.Enum; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; @@ -39,6 +39,16 @@ public class Buff : IUpdatable, IByteSerializable { private readonly ILogger logger = Log.ForContext(); + /// + /// Initializes a new Buff instance with specified metadata, actors, timing, and initial stack count. + /// + /// The metadata describing the buff's properties and behavior. + /// The unique identifier for this buff instance. + /// The actor who applied the buff. + /// The actor receiving the buff. + /// The game tick when the buff starts. + /// The game tick when the buff ends. + /// The initial number of stacks for the buff. public Buff(AdditionalEffectMetadata metadata, int objectId, IActor caster, IActor owner, long startTick, long endTick, int stacks) { Metadata = metadata; ObjectId = objectId; @@ -68,6 +78,11 @@ public void ResetActor(IActor actor) { } } + /// + /// Updates the buff's end tick if the provided value differs from the current end tick. + /// + /// The new end tick value to set. + /// True if the end tick was updated; otherwise, false. public bool UpdateEndTime(long endTick) { if (endTick == EndTick) { return false; @@ -76,6 +91,12 @@ public bool UpdateEndTime(long endTick) { return true; } + /// + /// Adjusts the buff's stack count by the specified amount, within allowed limits. + /// + /// The number of stacks to add (positive) or remove (negative). No change occurs if zero. + /// If true, suppresses the event when maximum stacks are reached. + /// True if the stack count changed; otherwise, false. public bool Stack(int amount = 1, bool silent = false) { if (amount == 0) { return false; @@ -103,6 +124,10 @@ public void RemoveStack(int amount = 1) { } } + /// + /// Updates the buff's state based on the current tick, handling activation, distance-based removal, expiration, enabled state, and periodic effect procs. + /// + /// The current game tick count. public virtual void Update(long tickCount) { if (!activated) { if (Metadata.Update.Cancel != null) { @@ -162,6 +187,9 @@ public void Disable() { } public void Enable() => Enabled = true; + /// + /// Executes the periodic effects of the buff, including recovery, damage, buff application, cancellation, duration modification, skill effects, and splash effects. Updates the next scheduled proc tick and disables further procs if the buff has expired. + /// private void Proc() { ProcCount++; @@ -179,6 +207,9 @@ private void Proc() { } } + /// + /// Applies splash skill effects from the buff's metadata to the owner's current position in the field. + /// private void ApplySplash() { foreach (SkillEffectMetadata effect in Metadata.Skills) { if (effect.Splash != null) { @@ -247,6 +278,9 @@ private void ApplyDotDamage() { } } + /// + /// Applies a damage-over-time (DoT) buff to either the owner or caster, based on the buff's target configuration. + /// private void ApplyDotBuff() { if (Metadata.Dot.Buff == null) { return; diff --git a/Maple2.Server.Game/Model/Field/Entity/FieldSkill.cs b/Maple2.Server.Game/Model/Field/Entity/FieldSkill.cs index b0d38a66d..fc088f899 100644 --- a/Maple2.Server.Game/Model/Field/Entity/FieldSkill.cs +++ b/Maple2.Server.Game/Model/Field/Entity/FieldSkill.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Maple2.Model.Enum; using Maple2.Model.Metadata; using Maple2.Server.Game.Manager.Field; @@ -24,6 +24,12 @@ public class FieldSkill : FieldEntity { private readonly ILogger logger = Log.ForContext(); + /// + /// Initializes a new field skill with indefinite activations, setting its caster, effect area, and activation interval. + /// + /// The actor who casts the skill. + /// The number of field ticks between each skill activation. + /// The 3D points defining the skill's area of effect. public FieldSkill(FieldManager field, int objectId, IActor caster, SkillMetadata value, int interval, params Vector3[] points) : base(field, objectId, value) { Caster = caster; @@ -33,6 +39,15 @@ public FieldSkill(FieldManager field, int objectId, IActor caster, NextTick = Field.FieldTick + interval; } + /// + /// Initializes a field skill entity with a specified number of activations and splash effect parameters. + /// + /// Unique identifier for the skill entity. + /// The actor who cast the skill. + /// Metadata describing the skill's properties and behavior. + /// Number of times the skill effect will trigger. + /// Splash effect metadata controlling timing, activation, and area properties. + /// Points defining the area of effect for the skill. public FieldSkill(FieldManager field, int objectId, IActor caster, SkillMetadata value, int fireCount, SkillEffectMetadataSplash splash, params Vector3[] points) : base(field, objectId, value) { Caster = caster; @@ -55,6 +70,10 @@ public FieldSkill(FieldManager field, int objectId, IActor caster, } } + /// + /// Processes the skill's activation and effect logic for the current game tick, including target acquisition, damage application, effect propagation, and lifecycle management. + /// + /// The current field tick count. public override void Update(long tickCount) { if (!Enabled) { Field.RemoveSkill(ObjectId); @@ -207,6 +226,11 @@ public override void Update(long tickCount) { } } + /// + /// Applies the skill effects defined in the attack to the specified targets using the caster as the source. + /// + /// The attack metadata containing the skill effects to apply. + /// The actors to which the effects will be applied. private void ApplyEffect(SkillMetadataAttack attack, params IActor[] targets) { Caster.ApplyEffects(attack.Skills, Caster, Caster, skillId: Value.Id, targets: targets); } diff --git a/Maple2.Server.Game/Model/Skill/DamageRecord.cs b/Maple2.Server.Game/Model/Skill/DamageRecord.cs index a28578aab..83a316250 100644 --- a/Maple2.Server.Game/Model/Skill/DamageRecord.cs +++ b/Maple2.Server.Game/Model/Skill/DamageRecord.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Numerics; using Maple2.Model.Enum; using Maple2.Model.Metadata; @@ -22,7 +22,11 @@ public class DamageRecord { public Vector3 Position; public Vector3 Direction; - public readonly ConcurrentDictionary Targets; // Target's ObjectId as key + public readonly ConcurrentDictionary Targets; /// + /// Initializes a new damage record for a skill attack, setting up associated metadata, properties, and an empty target dictionary keyed by target ObjectId. + /// + /// Metadata describing the skill used in the attack. + /// Metadata for the specific attack instance. public DamageRecord(SkillMetadata skillMetadata, SkillMetadataAttack attackMetadata) { SkillMetadata = skillMetadata; diff --git a/Maple2.Server.Game/Model/Skill/SkillRecord.cs b/Maple2.Server.Game/Model/Skill/SkillRecord.cs index 936528459..f46c02dde 100644 --- a/Maple2.Server.Game/Model/Skill/SkillRecord.cs +++ b/Maple2.Server.Game/Model/Skill/SkillRecord.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Numerics; using Maple2.Model.Metadata; @@ -34,6 +34,12 @@ public class SkillRecord { public ConcurrentDictionary Targets; + /// + /// Initializes a new instance of the class for a specific skill cast by an actor. + /// + /// The metadata describing the skill. + /// A unique identifier for this skill cast instance. + /// The actor who is casting the skill. public SkillRecord(SkillMetadata metadata, long castUid, IActor caster) { Metadata = metadata; CastUid = castUid; @@ -41,6 +47,11 @@ public SkillRecord(SkillMetadata metadata, long castUid, IActor caster) { Targets = []; } + /// + /// Attempts to set the current motion point index for the skill if the specified value is within the valid range. + /// + /// The motion point index to set. + /// True if the motion point was set successfully; otherwise, false. public bool TrySetMotionPoint(byte motionPoint) { if (Metadata.Data.Motions.Length <= motionPoint) { return false; diff --git a/Maple2.Server.Game/PacketHandlers/EmoteHandler.cs b/Maple2.Server.Game/PacketHandlers/EmoteHandler.cs index a3e504e48..aa6c689fb 100644 --- a/Maple2.Server.Game/PacketHandlers/EmoteHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/EmoteHandler.cs @@ -1,4 +1,4 @@ -using Maple2.Model; +using Maple2.Model; using Maple2.Model.Enum; using Maple2.Model.Error; using Maple2.Model.Game; @@ -55,6 +55,9 @@ private void HandleLearn(GameSession session, IByteReader packet) { session.Send(EmotePacket.Learn(new Emote(emoteId))); } + /// + /// Processes a request to use an emote, updating the player's condition and triggering related buff events if the emote is unlocked. + /// private void HandleUse(GameSession session, IByteReader packet) { int emoteId = packet.ReadInt(); string aniKey = packet.ReadUnicodeString(); diff --git a/Maple2.Server.Game/PacketHandlers/InteractObjectHandler.cs b/Maple2.Server.Game/PacketHandlers/InteractObjectHandler.cs index f34b1785f..acac4a2a3 100644 --- a/Maple2.Server.Game/PacketHandlers/InteractObjectHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/InteractObjectHandler.cs @@ -1,4 +1,4 @@ -using Maple2.Model.Enum; +using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; @@ -38,6 +38,9 @@ private void HandleStart(GameSession session, IByteReader packet) { } } + /// + /// Handles the completion of an object interaction by processing rewards, triggering events, and applying effects based on the interactable object's type and properties. + /// private void HandleEnd(GameSession session, IByteReader packet) { string entityId = packet.ReadString(); diff --git a/Maple2.Server.Game/PacketHandlers/SkillHandler.cs b/Maple2.Server.Game/PacketHandlers/SkillHandler.cs index 04d109132..401598723 100644 --- a/Maple2.Server.Game/PacketHandlers/SkillHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/SkillHandler.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Game; @@ -71,6 +71,12 @@ public override void Handle(GameSession session, IByteReader packet) { } } + /// + /// Processes a skill use request from the client, validating the skill, consuming resources, updating player state, and broadcasting the skill activation to the field. + /// + /// + /// If the player is holding a LiftupWeapon skill, only that skill can be used until released. The method validates the skill and motion point, attempts to play the skill animation, consumes required resources, and applies skill effects. It updates the player's battle state, adds the skill to active skills, broadcasts relevant packets, and saves the skill cooldown. + /// private void HandleUse(GameSession session, IByteReader packet) { long skillUid = packet.ReadLong(); int serverTick = packet.ReadInt(); @@ -144,6 +150,12 @@ private void HandleUse(GameSession session, IByteReader packet) { session.Config.SaveSkillCooldown(metadata, startTick); } + /// + /// Processes a point-based skill attack, updating the skill record and broadcasting damage to targets in the field. + /// + /// + /// The packet containing the skill UID, attack point, position, direction, target information, and iteration data. + /// private void HandlePoint(GameSession session, IByteReader packet) { long skillUid = packet.ReadLong(); SkillRecord? record = session.Player.ActiveSkills.Get(skillUid); @@ -195,6 +207,12 @@ private void HandlePoint(GameSession session, IByteReader packet) { } } + /// + /// Processes a skill attack targeting specific entities, validating targets and attack points, and dispatching the attack based on the skill's target type. + /// + /// + /// The packet containing skill UID, target information, impact positions, direction, attack point, and target IDs. + /// private void HandleTarget(GameSession session, IByteReader packet) { if (session.Field == null) { return; @@ -264,6 +282,9 @@ private void HandleTarget(GameSession session, IByteReader packet) { session.Player.TargetAttack(record); } + /// + /// Handles a splash (area-of-effect) skill attack by validating the skill and attack point, reading position and rotation, and registering the skill in the field. + /// private void HandleSplash(GameSession session, IByteReader packet) { long skillUid = packet.ReadLong(); SkillRecord? record = session.Player.ActiveSkills.Get(skillUid); @@ -298,6 +319,9 @@ private void HandleSplash(GameSession session, IByteReader packet) { session.Field?.AddSkill(record); } + /// + /// Synchronizes the state of an active skill with the client, updating its motion point, position, direction, and animation sequence. + /// private void HandleSync(GameSession session, IByteReader packet) { long skillUid = packet.ReadLong(); SkillRecord? record = session.Player.ActiveSkills.Get(skillUid); @@ -346,6 +370,9 @@ private void HandleSync(GameSession session, IByteReader packet) { session.Animation.TryPlaySequence(motion.SequenceName, motion.SequenceSpeed, AnimationType.Skill, record.Metadata); } + /// + /// Synchronizes the server tick for an active skill and ensures the player's animation sequence matches the skill's motion. + /// private void HandleTickSync(GameSession session, IByteReader packet) { long skillUid = packet.ReadLong(); SkillRecord? record = session.Player.ActiveSkills.Get(skillUid); @@ -371,6 +398,9 @@ private void HandleTickSync(GameSession session, IByteReader packet) { session.Player.Animation.SetLoopSequence(true, true); } + /// + /// Cancels an active skill for the player and broadcasts the cancellation to the field. + /// private void HandleCancel(GameSession session, IByteReader packet) { long skillUid = packet.ReadLong(); SkillRecord? record = session.Player.ActiveSkills.Get(skillUid); diff --git a/Maple2.Server.Game/Packets/SkillDamagePacket.cs b/Maple2.Server.Game/Packets/SkillDamagePacket.cs index e7f79fea7..281491a3c 100644 --- a/Maple2.Server.Game/Packets/SkillDamagePacket.cs +++ b/Maple2.Server.Game/Packets/SkillDamagePacket.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Maple2.Model.Common; using Maple2.Model.Enum; using Maple2.PacketLib.Tools; @@ -43,6 +43,11 @@ public static ByteWriter Target(SkillRecord record, ICollection ta return pWriter; } + /// + /// Constructs a skill damage packet containing information about the caster, skill, impacted targets, and their respective damage details. + /// + /// The damage record containing skill, caster, and target damage information. + /// A ByteWriter representing the serialized skill damage packet. public static ByteWriter Damage(DamageRecord record) { var pWriter = Packet.Of(SendOp.SkillDamage); pWriter.Write(Command.Damage); @@ -90,6 +95,11 @@ public static ByteWriter Heal(HealDamageRecord record, bool animate = true) { return pWriter; } + /// + /// Constructs a packet representing regional skill damage, including affected targets and their damage details. + /// + /// The damage record containing skill, caster, owner, attack point, and target information. + /// A containing the serialized regional damage packet. public static ByteWriter Region(DamageRecord record) { var pWriter = Packet.Of(SendOp.SkillDamage); pWriter.Write(Command.Region); @@ -113,6 +123,11 @@ public static ByteWriter Region(DamageRecord record) { return pWriter; } + /// + /// Constructs a packet representing tile-based skill damage, including affected targets and their respective damage details. + /// + /// The damage record containing skill and target information for the tile-based attack. + /// A ByteWriter containing the serialized tile damage packet. public static ByteWriter Tile(DamageRecord record) { var pWriter = Packet.Of(SendOp.SkillDamage); pWriter.Write(Command.Tile); diff --git a/Maple2.Server.Game/Packets/SkillUseFailedPacket.cs b/Maple2.Server.Game/Packets/SkillUseFailedPacket.cs index a948d25ae..bb7195108 100644 --- a/Maple2.Server.Game/Packets/SkillUseFailedPacket.cs +++ b/Maple2.Server.Game/Packets/SkillUseFailedPacket.cs @@ -1,4 +1,4 @@ -using Maple2.PacketLib.Tools; +using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; using Maple2.Server.Core.Packets; using Maple2.Server.Game.Model.Skill; @@ -11,6 +11,11 @@ private enum Command : byte { Unknown = 6, } + /// + /// Constructs a packet indicating that a skill use attempt has failed, serializing relevant information from the provided skill record. + /// + /// The skill record containing details of the failed skill use attempt. + /// A containing the serialized failure packet. public static ByteWriter Fail(SkillRecord record) { var pWriter = Packet.Of(SendOp.SkillUseFailed); pWriter.Write(Command.Fail); diff --git a/Maple2.Server.Game/Session/GameSession.cs b/Maple2.Server.Game/Session/GameSession.cs index ebd0b5605..e003a74f4 100644 --- a/Maple2.Server.Game/Session/GameSession.cs +++ b/Maple2.Server.Game/Session/GameSession.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Sockets; @@ -336,6 +336,9 @@ public bool EnterServer(long accountId, Guid machineId, MigrateInResponse migrat return true; } + /// + /// Cleans up player state and resources when leaving the current field, including clearing staging arrays, disposing held objects, and removing the player from the field. + /// private void LeaveField() { Array.Clear(ItemLockStaging); Array.Clear(DismantleStaging); diff --git a/Maple2.Server.Game/Util/SkillUtils.cs b/Maple2.Server.Game/Util/SkillUtils.cs index 7ebde4a34..3ea4f285c 100644 --- a/Maple2.Server.Game/Util/SkillUtils.cs +++ b/Maple2.Server.Game/Util/SkillUtils.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Maple2.Model; using Maple2.Model.Enum; using Maple2.Model.Game; @@ -10,6 +10,14 @@ namespace Maple2.Server.Game.Util; public static class SkillUtils { + /// + /// Constructs a representing the effective area of a skill based on its range type, position, and angle. + /// + /// The skill range metadata specifying the region type and dimensions. + /// The origin position for the prism, using the XY coordinates for the base. + /// The orientation angle applied to directional shapes. + /// A corresponding to the specified skill region and parameters. + /// Thrown if the skill region type is invalid. public static Prism GetPrism(this SkillMetadataRange range, in Vector3 position, float angle) { if (range.Type == SkillRegion.None) { return new Prism(IPolygon.Null, 0, 0); @@ -27,6 +35,13 @@ public static Prism GetPrism(this SkillMetadataRange range, in Vector3 position, return new Prism(polygon, position.Z, range.Height + range.RangeAdd.Z); } + /// + /// Returns up to a specified number of unique, non-dead entities whose shapes intersect with the given prism. + /// + /// The type of entities to filter, implementing . + /// The collection of entities to filter. + /// The maximum number of entities to return. Defaults to 10. + /// An enumerable of entities intersecting the prism, without duplicates or dead entities. public static IEnumerable Filter(this Prism prism, IEnumerable entities, int limit = 10) where T : IActor { HashSet addedActorObjectIds = []; foreach (T entity in entities) { @@ -51,6 +66,15 @@ public static IEnumerable Filter(this Prism prism, IEnumerable entities } } + /// + /// Filters and yields up to a specified number of unique, non-dead entities that intersect with any of the given prisms, optionally excluding entities in the ignore collection. + /// + /// The type of entity, constrained to IActor. + /// An array of prisms to test for intersection. + /// The collection of entities to filter. + /// The maximum number of entities to yield. + /// An optional collection of entities to exclude from the results. + /// An enumerable of entities intersecting any prism, up to the specified limit, with duplicates and dead entities excluded. public static IEnumerable Filter(this Prism[] prisms, IEnumerable entities, int limit = 10, ICollection? ignore = null) where T : IActor { HashSet addedActorObjectIds = []; foreach (T entity in entities) { @@ -80,6 +104,17 @@ public static IEnumerable Filter(this Prism[] prisms, IEnumerable entit } } + /// + /// Determines whether a is satisfied for the given caster, owner, and target actors in the specified event context. + /// + /// The condition to evaluate. + /// The actor attempting to trigger the condition. + /// The owner actor relevant to the condition. + /// The target actor relevant to the condition. + /// The event type context for the condition check. + /// The skill ID associated with the event, if any. + /// The buff ID associated with the event, if any. + /// true if all condition requirements are met for the provided actors and event context; otherwise, false. public static bool Check(this BeginCondition condition, IActor caster, IActor owner, IActor target, EventConditionType eventType = EventConditionType.Activate, int eventSkillId = 0, int eventBuffId = 0) { if (caster is FieldPlayer player) { if (condition is not { Probability: 1 } && condition.Probability < Random.Shared.NextDouble()) { @@ -152,6 +187,15 @@ public static bool Check(this BeginCondition condition, IActor caster, IActor ow return condition.Caster.Check(caster, eventType, eventSkillId, eventBuffId) && condition.Owner.Check(owner, eventType, eventSkillId, eventBuffId) && condition.Target.Check(target, eventType, eventSkillId, eventBuffId); } + /// + /// Determines whether a target actor satisfies the specified constraints for a given event context. + /// + /// The condition to evaluate; returns true if null. + /// The actor being checked. + /// The event type to match against the condition. + /// The skill ID associated with the event. + /// The buff ID associated with the event. + /// True if the target meets all condition requirements; otherwise, false. private static bool Check(this BeginConditionTarget? condition, IActor target, EventConditionType eventType = EventConditionType.Activate, int eventSkillId = 0, int eventBuffId = 0) { if (condition == null) { return true;