Skip to content

Trying to simplify taunts in Gramiel#87

Open
DreadedSlug wants to merge 4 commits intoauqw:Skuafrom
DreadedSlug:gramUp
Open

Trying to simplify taunts in Gramiel#87
DreadedSlug wants to merge 4 commits intoauqw:Skuafrom
DreadedSlug:gramUp

Conversation

@DreadedSlug
Copy link
Contributor

@DreadedSlug DreadedSlug commented Feb 20, 2026

Summary by Sourcery

Simplify and centralize taunt handling for Gramiel by delegating taunt execution to shared utilities and improving packet-based warning processing and logging.

Enhancements:

  • Delegate taunt execution to a shared Ultra.UseTaunt helper instead of inline retry loops for both crystal and Gramiel taunts.
  • Refine Gramiel warning packet listener to be async, safer against nulls, and more robust with detailed logging and exception handling.
  • Introduce a dedicated HandleCrystalWarning async method with debounce logic and role-based taunt assignment using an atomic taunt counter.
  • Ensure a random class is equipped before synchronizing Gramiel classes to improve preparation behavior.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 20, 2026

Reviewer's Guide

Refactors Gramiel taunt handling to centralize taunt execution in Ultra.UseTaunt, introduces async packet handling with debounced crystal warning processing, switches logging to standardized Bot.Log messages, and adds a random class re-equip step before class sync.

Sequence diagram for debounced crystal taunt handling

sequenceDiagram
    participant Server
    participant GramielMessageListener
    participant HandleCrystalWarning
    participant Ultra
    participant Bot

    Server->>GramielMessageListener: Packet(params.type=json, dataObj.cmd=ct)
    GramielMessageListener->>GramielMessageListener: Validate packet and anims
    GramielMessageListener->>GramielMessageListener: Detect defense shattering attack message
    GramielMessageListener->>Bot: Log [GRAMIEL] Crystal warning packet received
    GramielMessageListener->>+HandleCrystalWarning: await HandleCrystalWarning()

    HandleCrystalWarning->>HandleCrystalWarning: Compute timeSinceLastWarning
    alt Warning within 500ms
        HandleCrystalWarning->>Bot: Log debounce and ignore
        HandleCrystalWarning-->>GramielMessageListener: Task completed
    else First or valid warning
        HandleCrystalWarning->>HandleCrystalWarning: Update lastTauntWarningTime
        HandleCrystalWarning->>HandleCrystalWarning: Interlocked.Increment(tauntCounter)
        HandleCrystalWarning->>Bot: Log warning number and role
        alt This player should taunt
            HandleCrystalWarning->>HandleCrystalWarning: Set shouldExecuteTaunt = true
            HandleCrystalWarning->>Bot: Log MY TURN
        else Other player should taunt
            HandleCrystalWarning->>Bot: Log Not my turn
        end
        HandleCrystalWarning-->>GramielMessageListener: Task completed
    end

    loop Attack loop
        participant AttackWithPriority
        AttackWithPriority->>AttackWithPriority: Check shouldExecuteTaunt
        alt shouldExecuteTaunt == true
            AttackWithPriority->>AttackWithPriority: shouldExecuteTaunt = false
            AttackWithPriority->>Bot: Log executing taunt
            AttackWithPriority->>Ultra: UseTaunt(crystalMapId)
            Ultra-->>AttackWithPriority: Taunt executed
            AttackWithPriority->>Bot: Log taunt landed
            AttackWithPriority-->>AttackWithPriority: Return from attack branch
        else No scheduled taunt
            AttackWithPriority->>AttackWithPriority: Normal attack logic
        end
    end
Loading

Sequence diagram for Gramiel timed taunt using Ultra.UseTaunt

sequenceDiagram
    participant AttackWithPriority
    participant Core
    participant Ultra
    participant Bot

    loop Attack loop
        AttackWithPriority->>AttackWithPriority: Compute currentTime and tauntOffsetSeconds
        AttackWithPriority->>AttackWithPriority: Determine inTauntWindow and noFocusAura
        alt inTauntWindow and noFocusAura
            AttackWithPriority->>Bot: Log Gramiel taunt window
            AttackWithPriority->>Ultra: UseTaunt(gramielMapId)
            Ultra-->>AttackWithPriority: Taunt executed
            AttackWithPriority->>Bot: Logger Gramiel taunt landed
            AttackWithPriority->>Core: EnableSkills()
            AttackWithPriority->>Bot: Sleep(300)
        else Outside taunt window
            AttackWithPriority->>AttackWithPriority: Continue normal rotation
        end
    end
Loading

Class diagram for updated UltraGramiel taunt logic

classDiagram
    class UltraGramiel {
        +bool shouldExecuteTaunt
        +int tauntCounter
        +bool isT1Taunter
        +int crystalMapId
        +int gramielMapId
        +DateTime lastTauntWarningTime
        +void Prep(bool skipEnhancements)
        +void AttackWithPriority()
        +async void GramielMessageListener(dynamic packet)
        +async Task HandleCrystalWarning()
    }

    class UltraService {
        +void UseTaunt(int targetMapId)
    }

    class BotService {
        +void Log(string message)
        +bool ShouldExit
        +PlayerService Player
        +TargetService Target
        +SkillService Skills
        +CombatService Combat
        +void Sleep(int milliseconds)
    }

    class CoreService {
        +void EquipRandomClassAndReequip()
        +void EnableSkills()
    }

    class PlayerService {
        +bool Alive
        +bool HasTarget
    }

    class TargetService {
        +Aura[] Auras
    }

    class Aura {
        +string Name
    }

    UltraGramiel --> UltraService : uses
    UltraGramiel --> BotService : logs_and_game_state
    UltraGramiel --> CoreService : class_and_skill_control
    BotService --> PlayerService : exposes
    BotService --> TargetService : exposes
    TargetService --> Aura : contains

    class UltraPrepFlow {
        +void Prep(bool skipEnhancements)
    }

    UltraPrepFlow --> UltraGramiel : configures
    UltraPrepFlow --> CoreService : EquipRandomClassAndReequip
    UltraPrepFlow --> UltraService : EquipClassSync
Loading

File-Level Changes

Change Details Files
Centralize taunt execution logic into Ultra.UseTaunt and simplify in-fight taunt handling.
  • Replace inline taunt execution loop on the crystal with a call to Ultra.UseTaunt(crystalMapId) and add Bot.Log messages before and after execution
  • Replace inline taunt execution loop for Gramiel with Ultra.UseTaunt(gramielMapId) and simplified success logging
  • Remove manual skill disabling/enabling and aura polling from AttackWithPriority taunt paths, delegating that responsibility to Ultra.UseTaunt
Ultras/UltraGramiel.cs
Introduce asynchronous, debounced processing of Gramiel crystal warning packets and thread-safe taunt assignment.
  • Change GramielMessageListener to async void, add early-return guards on packet structure, and wrap processing in a try/catch that logs exceptions via Bot.Log
  • Extract crystal warning handling into new async Task HandleCrystalWarning method with 500ms debounce, thread-safe tauntCounter increment via Interlocked.Increment, and role-based taunt assignment based on T1/T2
  • Replace shared state mutation in GramielMessageListener with calls to HandleCrystalWarning and add detailed Bot.Log traces for warnings, debounce behavior, and taunt decisions
Ultras/UltraGramiel.cs
Minor behavior and logging adjustments around combat setup and taunt flow.
  • Add Core.EquipRandomClassAndReequip() before Ultra.EquipClassSync in Prep to randomize and then re-equip classes
  • Standardize taunt-related logging to Bot.Log with [GRAMIEL] prefix in several paths
  • Tighten null checks on packet and anim message fields when inspecting anims for boss messages
Ultras/UltraGramiel.cs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • HandleCrystalWarning is marked async but only awaits Task.CompletedTask; consider making it synchronous (or return Task and actually await something) to avoid the overhead and confusion of a no-op async method.
  • shouldExecuteTaunt is now being set from an async packet listener and read in the main combat loop without any synchronization; consider marking it volatile or using a thread-safe pattern to avoid missed or reordered updates.
  • Logging now mixes Bot.Log and C.Logger within the same flow; consider standardizing on one logging mechanism for consistency and easier filtering of Gramiel-related messages.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- HandleCrystalWarning is marked async but only awaits Task.CompletedTask; consider making it synchronous (or return Task and actually await something) to avoid the overhead and confusion of a no-op async method.
- shouldExecuteTaunt is now being set from an async packet listener and read in the main combat loop without any synchronization; consider marking it volatile or using a thread-safe pattern to avoid missed or reordered updates.
- Logging now mixes Bot.Log and C.Logger within the same flow; consider standardizing on one logging mechanism for consistency and easier filtering of Gramiel-related messages.

## Individual Comments

### Comment 1
<location> `Ultras/UltraGramiel.cs:583-592` </location>
<code_context>
+    private async void GramielMessageListener(dynamic packet)
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Consider returning Task from GramielMessageListener instead of using async void.

Because this method now awaits another async method, using `async void` makes errors unobservable and the listener non-awaitable. Prefer `private async Task GramielMessageListener(dynamic packet)` and update the subscription so callers can await or handle failures. If the event handler must be `void`, use a thin `void` wrapper that calls an `async Task` method and intentionally ignores the returned task.

Suggested implementation:

```csharp
    // Packet Handler for Gramiel Warning Messages
    private async Task GramielMessageListener(dynamic packet)

```

You will also need to update the subscription / event wiring that calls `GramielMessageListener`:

1. If the event handler can be `Func<dynamic, Task>` (or similar), pass `GramielMessageListener` directly so the caller can await it or handle failures.
2. If the event requires a `void` handler (e.g., `Action<dynamic>`), introduce a thin wrapper:

   ```csharp
   private void GramielMessageListenerWrapper(dynamic packet)
   {
       _ = GramielMessageListener(packet); // intentionally fire-and-forget; consider logging unobserved exceptions
   }
   ```

   and subscribe `GramielMessageListenerWrapper` to the event instead of `GramielMessageListener`.

3. Ensure `using System.Threading.Tasks;` is present at the top of the file if not already imported.
</issue_to_address>

### Comment 2
<location> `Ultras/UltraGramiel.cs:655` </location>
<code_context>
+            Bot.Log($"[GRAMIEL] HandleCrystalWarning exception: {ex.Message}");
+        }
+        
+        await Task.CompletedTask;
     }

</code_context>

<issue_to_address>
**nitpick:** The final `await Task.CompletedTask` in HandleCrystalWarning is redundant.

Since the method has no real asynchronous work, the `async`/`await` pattern only adds overhead. Consider removing `async`/`await` and returning a plain `Task` (or `void` if appropriate), rather than using a dummy await.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant