Skip to content

Apply monster attribute changes instantly on the game server#785

Open
sven-n wants to merge 2 commits into
masterfrom
apply-monster-attribute-changes-instantly
Open

Apply monster attribute changes instantly on the game server#785
sven-n wants to merge 2 commits into
masterfrom
apply-monster-attribute-changes-instantly

Conversation

@sven-n
Copy link
Copy Markdown
Member

@sven-n sven-n commented May 27, 2026

Summary

Closes #784.

Changing a monster's attributes (e.g. via the admin panel) previously had no effect until a server restart, because MonsterAttributeHolder snapshots the monster's stats from its MonsterDefinition at construction time into a static cache and never refreshed them.

This change hooks into the existing ConfigurationChangeMediator: whenever a MonsterAttribute is added/removed/modified, the infrastructure publishes a parent-level change for its MonsterDefinition. Each spawned attackable NPC now registers for those changes and reloads its cached stat attributes in place — no re-spawn, so health and position are preserved.

Changes

  • MonsterAttributeHolder: added ApplyChanges(), which rebuilds the stat dictionary from the (already updated in place) MonsterDefinition.Attributes, refreshes the shared static cache, and atomically swaps in the new dictionary.
  • AttackableNpcBase: added ReloadAttributes() forwarding to the holder.
  • MapInitializer.RegisterForConfigChanges: each spawned attackable NPC registers for changes to its MonsterDefinition; the registration is disposed alongside the NPC in all existing teardown paths.

Known limitation

Stats that currently have a per-instance composable element applied (e.g. an active magic effect, or the disabled-by-default MonsterAttributeScaler) won't reflect a base-value change until that element is removed/re-added, since composable attributes snapshot their base at add time. This matches existing system behavior.

Test plan

  • New unit tests in MonsterAttributeReloadTests cover changing an existing attribute value and adding a new attribute; both confirm the value takes effect after ReloadAttributes().
  • Manual verification: edit a monster's attribute in the admin panel on a running server and confirm immediate effect.

🤖 Generated with Claude Code

Register spawned attackable NPCs for changes of their MonsterDefinition
via the ConfigurationChangeMediator and reload the cached stat attributes
of the MonsterAttributeHolder in place, so configuration changes to
monster attributes take effect without restarting the server.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enables real-time updates for monster attributes on the game server. By introducing a reload mechanism that refreshes cached stat attributes in-place, administrators can now modify monster configurations via the admin panel and see those changes reflected immediately on existing spawned NPCs, preserving their current state such as health and position.

Highlights

  • Dynamic Attribute Updates: Implemented a mechanism to allow monster attribute changes to take effect immediately on running servers without requiring a restart or re-spawn.
  • Configuration Integration: Integrated with the ConfigurationChangeMediator to trigger attribute reloads whenever a MonsterDefinition is modified.
  • Testing: Added new unit tests in MonsterAttributeReloadTests to verify that attribute value changes and new attribute additions are correctly applied to active monster instances.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the ability to dynamically reload monster attributes from their configuration definitions without needing to respawn them. It adds an ApplyChanges method to MonsterAttributeHolder, registers configuration change listeners in MapInitializer, and includes unit tests to verify the behavior. The review feedback highlights a potential memory leak where configuration change registrations may not be disposed of if an NPC is disposed outside of mediator callbacks, suggesting a registration disposal mechanism on the NPC. Additionally, a performance optimization is recommended in MonsterAttributeHolder to prevent redundant dictionary rebuilds when multiple instances of the same monster apply changes simultaneously.

Comment thread src/GameLogic/MapInitializer.cs Outdated
Comment thread src/GameLogic/NPC/AttackableNpcBase.cs
Comment thread src/GameLogic/Attributes/MonsterAttributeHolder.cs
Let the NPC own the MonsterDefinition change registration so it is
disposed when the NPC is disposed (e.g. dying non-respawning monster,
map cleanup), preventing a memory leak. Also skip redundant stat
dictionary rebuilds when multiple instances of the same monster apply
the same change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sven-n
Copy link
Copy Markdown
Member Author

sven-n commented May 27, 2026

Thanks for the review! Addressed all three findings in 030bd55:

  • Memory leak (high): The MonsterDefinition change registration is now owned by the NPC. AttackableNpcBase gained a RegisterDisposable(IDisposable) method and disposes its registrations in Dispose(bool) (reliably invoked from both Dispose() and DisposeAsync()), so it's cleaned up even when the NPC is disposed outside the mediator callbacks (dying non-respawning/wandering monster, map cleanup, shutdown). The manual disposal calls in the spawn-area callbacks were removed since the NPC's disposal handles it (the mediator's disposable is idempotent).
  • Redundant rebuilds (medium): ApplyChanges() now checks the shared cache first; the first instance of a monster type rebuilds the stat dictionary and the rest just adopt it.
  • Added a test verifying all spawned instances of the same definition pick up a change (covers the optimization path). All tests pass.

@sven-n
Copy link
Copy Markdown
Member Author

sven-n commented May 27, 2026

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the ability to dynamically reload monster attributes from configuration changes without requiring a server restart or monster respawn. It updates MonsterAttributeHolder to allow modifying its stat attributes, registers spawned monsters for configuration changes in MapInitializer, and ensures that these registrations are properly disposed of in AttackableNpcBase. Additionally, a comprehensive set of unit tests has been added in MonsterAttributeReloadTests.cs to verify this behavior. There are no review comments, so no further feedback is provided.

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.

Apply changes to monster attributes instantly on the game server

1 participant