Skip to content

Feature/offlevel#710

Open
eduardosmaniotto wants to merge 20 commits intoMUnique:masterfrom
eduardosmaniotto:feature/offlevel
Open

Feature/offlevel#710
eduardosmaniotto wants to merge 20 commits intoMUnique:masterfrom
eduardosmaniotto:feature/offlevel

Conversation

@eduardosmaniotto
Copy link
Contributor

@eduardosmaniotto eduardosmaniotto commented Mar 13, 2026

Feature: Offline Leveling (/offlevel command)
Allows players to continue grinding after disconnecting. When a player types /offlevel, their character stays in the world as a ghost and automatically fights monsters using the existing MU Helper configuration.
How it works:

  1. Player types /offlevel chat command
  2. The real client disconnects (player can reconnect anytime)
  3. A ghost player spawns at the same location and continues fighting using MU Helper
  4. When the player logs back in, the ghost automatically stops
    Technical details:
  • No network traffic to offline player: View plugin calls meant FOR the offline player are suppressed via NullViewProxy
  • Visible to other players: Attack animations are intentionally broadcast so other players can see the ghost fighting
  • Persists XP: Uses the same persistence context for the ghost, ensuring XP is saved

Feature: Add a "Refresh" button to admin interface to reload updated entities from the database.

Feature: Add a "Duplicate" button to inventory in admin interface.

PS. This also contains fixes from previous PR #706
PS2. This PR will not include party support, otherwise it would be too much to review.

@gemini-code-assist
Copy link

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 introduces a significant new feature: offline leveling. Players can now use a chat command to leave their character actively grinding in the game world even after disconnecting, leveraging their MU Helper settings. This is achieved through a 'ghost' player system that handles combat, item pickup, and movement, while minimizing network overhead. The feature also includes automatic session termination upon player re-login and refactors MU Helper configurations for clarity. Additionally, a quality-of-life improvement for administrators has been added, allowing for easy duplication of items within the admin panel.

Highlights

  • Offline Leveling Feature: Introduced a new /offlevel command that allows players to disconnect their client while their character remains in the game world as a 'ghost' player, automatically fighting monsters using their existing MU Helper configuration. This ghost player is visible to others and persists XP gains.
  • Network Optimization for Ghost Players: Implemented a NullViewProxy mechanism to suppress all network traffic for offline leveling ghost players, ensuring efficient server resource usage while maintaining their presence in the game world.
  • Automated AI for Offline Leveling: Developed an OfflineLevelingIntelligence component that mimics the client-side MU Helper logic, enabling ghost players to perform attacks, use skills, manage health, pick up items, and regroup to their original position.
  • Seamless Re-login Integration: Added a plugin (OfflineLevelingStopOnLoginPlugIn) that automatically stops an active offline leveling session when the real player logs back into their account, allowing them to resume control of their character.
  • MU Helper Configuration Refactoring: Refactored MU Helper configuration classes, renaming MuHelperConfiguration to MuHelperServerConfiguration and introducing MuHelperPlayerConfiguration to better distinguish between server-side and player-specific settings.
  • Admin Panel Item Duplication: Enhanced the admin panel's item storage field with a new 'Duplicate' button, allowing administrators to easily create copies of existing items.

🧠 New Feature in Public Preview: You can now enable Memory 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.

Changelog
  • src/AttributeSystem/StatAttribute.cs
    • Updated null-conditional operator for Definition.MaximumValue.HasValue check.
  • src/GameLogic/DroppedItem.cs
    • Changed item pickup log level from Information to Debug.
  • src/GameLogic/DroppedMoney.cs
    • Changed money pickup log level from Information to Debug.
  • src/GameLogic/GameContext.cs
    • Added OfflineLevelingManager property to manage offline leveling sessions.
  • src/GameLogic/GameMap.cs
    • Added GetDropsInRange method to retrieve dropped items and money within a specified range.
  • src/GameLogic/IGameContext.cs
    • Added OfflineLevelingManager property to the game context interface.
  • src/GameLogic/MuHelper/MuHelper.cs
    • Updated _configuration type from MuHelperConfiguration to MuHelperServerConfiguration.
  • src/GameLogic/MuHelper/MuHelperConfiguration.cs
    • Renamed MuHelperConfiguration.cs to MuHelperServerConfiguration.cs.
  • src/GameLogic/MuHelper/MuHelperFeaturePlugIn.cs
    • Updated configuration type from MuHelperConfiguration to MuHelperServerConfiguration.
  • src/GameLogic/MuHelper/MuHelperPlayerConfiguration.cs
    • Added new file defining the deserialized structure for player-specific MU Helper configurations.
  • src/GameLogic/OfflineLeveling/NullViewPlugInContainer.cs
    • Added new file for a view plugin container that creates NullViewProxy instances to suppress network traffic.
  • src/GameLogic/OfflineLeveling/NullViewProxy.cs
    • Added new file for a dynamic proxy that returns default values for method calls, effectively nullifying view plugin operations.
  • src/GameLogic/OfflineLeveling/OfflineLevelingIntelligence.cs
    • Added new file implementing the AI logic for offline leveling ghost players, including combat, healing, item pickup, and movement.
  • src/GameLogic/OfflineLeveling/OfflineLevelingManager.cs
    • Added new file to track and manage active offline leveling player instances.
  • src/GameLogic/OfflineLeveling/OfflineLevelingPlayer.cs
    • Added new file defining the OfflineLevelingPlayer class, representing a ghost player for offline leveling.
  • src/GameLogic/OfflineLeveling/OfflineLevelingStopOnLoginPlugIn.cs
    • Added new file for a plugin that stops an active offline leveling session when the associated account logs in.
  • src/GameLogic/Player.cs
    • Added SuppressDisconnectedEvent method to prevent event firing during offline leveling setup.
    • Removed trailing newline at the end of the file.
  • src/GameLogic/PlugIns/ChatCommands/Arguments/OfflineLevelingChatCommandPlugIn.cs
    • Added new file for the /offlevel chat command, enabling players to start offline leveling.
  • src/GameLogic/Properties/PlayerMessage.Designer.cs
    • Added new localized strings for offline leveling messages.
  • src/GameLogic/Properties/PlayerMessage.resx
    • Added new resource entries for offline leveling messages.
  • src/GameLogic/Properties/PlugInResources.Designer.cs
    • Added new localized strings for offline leveling plugin names and descriptions.
  • src/GameLogic/Properties/PlugInResources.resx
    • Added new resource entries for offline leveling plugin names and descriptions.
  • src/Persistence/Initialization/Updates/AddOfflineLevelingPlugIn.cs
    • Added new file to register the offline leveling chat command and stop-on-login plugins during database initialization.
  • src/Persistence/Initialization/Updates/UpdateVersion.cs
    • Added AddOfflineLeveling entry to the UpdateVersion enum.
  • src/Startup/Dockerfile
    • Added icu-libs installation and DOTNET_SYSTEM_GLOBALIZATION_INVARIANT environment variable for globalization support.
    • Refined Dockerfile build and publish steps, including better handling of project files and log directory creation.
  • src/Web/Shared/Components/Form/ItemStorageField.razor
    • Added a 'Duplicate' button to the item storage field in the admin panel.
  • src/Web/Shared/Components/Form/ValueListWrapper.cs
    • Modified Remove and RemoveAt methods to correctly handle item removal and index updates within the wrapper.
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 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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

@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 a significant new feature: offline leveling. The implementation is comprehensive, covering the AI for the offline character, state management, and integration with existing systems. The use of DispatchProxy to suppress network views is a clever approach. Additionally, the PR includes some refactoring and a new item duplication feature in the admin UI. My review identified a few areas for improvement: a minor file header inconsistency, a maintainability issue with a hardcoded string for skill identification, and a potential bug in the new item duplication logic that could lead to data issues. I've provided suggestions for each of these points.

@eduardosmaniotto eduardosmaniotto marked this pull request as draft March 13, 2026 15:24
@eduardosmaniotto eduardosmaniotto marked this pull request as ready for review March 14, 2026 00:40
@eduardosmaniotto eduardosmaniotto marked this pull request as draft March 14, 2026 00:40
Copy link

@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 a significant new feature: offline leveling. The implementation is comprehensive, including a ghost player entity, a server-side AI to control it, and plugins to manage its lifecycle. The approach to suppress network traffic for the ghost player using a null-view proxy is clever. Additionally, the PR includes UI enhancements like a 'Duplicate' button for items in the admin interface. While the core feature implementation is solid, I've identified a critical bug in the new 'Duplicate' item functionality that could lead to data corruption, along with a couple of medium-severity maintainability concerns in the new code that would be beneficial to address.

@eduardosmaniotto eduardosmaniotto marked this pull request as ready for review March 14, 2026 03:05
Copy link

@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 significant 'Offline Leveling' feature, allowing players to continue grinding after disconnecting. The implementation is comprehensive, including the AI for the offline player, management of sessions, and seamless integration with the login process. The use of a DispatchProxy to suppress network traffic for offline players is a clever approach. Additionally, the PR adds a 'Duplicate' item feature in the admin panel's inventory editor and a 'Refresh' button on edit pages. Several smaller refactorings improve code style and robustness. My review includes a couple of suggestions to enhance maintainability by refactoring large classes and better separating business logic from UI components. Overall, this is a solid contribution with well-executed features.

@eduardosmaniotto
Copy link
Contributor Author

/gemini review

Copy link

@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 a significant new feature: offline leveling. The implementation is well-structured, creating a 'ghost' player driven by a server-side AI that mimics the MU Helper functionality. The use of a null-view proxy to suppress network traffic is a clever approach. The supporting changes, such as the admin panel refresh and duplicate item buttons, are also well-implemented. I've found one potential issue regarding the game's economy that should be considered.

@eduardosmaniotto eduardosmaniotto marked this pull request as draft March 14, 2026 04:32
@eduardosmaniotto eduardosmaniotto marked this pull request as ready for review March 14, 2026 20:23
Copy link

@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 a significant and well-implemented offline leveling feature, allowing players to continue progressing while disconnected. The implementation is robust, using a 'ghost' player with suppressed network views and a modular AI system for combat, buffing, and other actions. The addition of 'Refresh' and 'Duplicate' buttons to the admin panel are also valuable usability improvements. The code is generally of high quality with good structure and modern C# practices. I have one minor suggestion regarding a hardcoded future date in an update plugin.

public override bool IsMandatory => true;

/// <inheritdoc />
public override DateTime CreatedAt => new(2025, 3, 11, 12, 0, 0, DateTimeKind.Utc);

Choose a reason for hiding this comment

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

medium

The CreatedAt date is set to a future date (March 11, 2025). This seems like a placeholder or a mistake. Update versions should be timestamped with their actual creation date to ensure they are applied in the correct order. Please change this to reflect the actual creation date of this update.

Copy link
Member

Choose a reason for hiding this comment

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

Haha, well we're in 2026, though 😉 Please adjust it if this update plugin is really needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ops, I didn't notice the year 😅

@eduardosmaniotto eduardosmaniotto marked this pull request as draft March 14, 2026 22:41
@eduardosmaniotto eduardosmaniotto marked this pull request as ready for review March 15, 2026 17:26
Copy link

@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 significant 'Offline Leveling' feature, allowing players to continue progressing while disconnected. The implementation is well-structured, separating concerns into various handlers for combat, buffs, movement, and item management. The use of a 'ghost' player with a NullViewProxy to suppress network traffic is a clever and effective approach.

In addition to the main feature, the PR includes several valuable improvements:

  • A 'Refresh' button in the admin panel to reload data.
  • A 'Duplicate' button in the inventory editor for easier item management.
  • Refinements to the Dockerfile for better layer caching and configuration.
  • A bug fix in ValueListWrapper for safer item removal.

I have one suggestion for improving code clarity and safety in StatAttribute.cs by using a more modern C# pattern. Overall, this is a high-quality contribution with substantial new functionality and thoughtful improvements.

/// Configuration for the <see cref="MuHelper"/>.
/// </summary>
public class MuHelperConfiguration
public class MuHelperServerConfiguration
Copy link
Member

Choose a reason for hiding this comment

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

Keep the old name, please

public T? GetPlugIn<T>()
where T : class, IViewPlugIn
{
return System.Reflection.DispatchProxy.Create<T, NullViewProxy>();
Copy link
Member

Choose a reason for hiding this comment

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

Would returning null work here? Then we wouldn't need the NullViewProxy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tested with null and it works, I'll remove the Proxy.

/// </summary>
/// <returns>The size of the inventory.</returns>
public byte GetInventorySize()
public byte InventorySize
Copy link
Member

Choose a reason for hiding this comment

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

Please move this property up to the other properties (SA1201)

public override bool IsMandatory => true;

/// <inheritdoc />
public override DateTime CreatedAt => new(2025, 3, 11, 12, 0, 0, DateTimeKind.Utc);
Copy link
Member

Choose a reason for hiding this comment

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

Haha, well we're in 2026, though 😉 Please adjust it if this update plugin is really needed.

Copy link
Member

Choose a reason for hiding this comment

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

Is this really needed?
As far as I remember, missing plugin configurations are added automatically on server start at
MUnique.OpenMU.Startup.Program.PlugInConfigurationsFactory.

Copy link
Contributor Author

@eduardosmaniotto eduardosmaniotto Mar 15, 2026

Choose a reason for hiding this comment

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

I was thinking about that, but this way it's possible to persist the disabled plugin in case the admin doesn´t want to enable offlevel. Does that make sense?

/// <summary>
/// The version of the <see cref="AddOfflineLevelingPlugIn"/>.
/// </summary>
AddOfflineLeveling = 68,
Copy link
Member

Choose a reason for hiding this comment

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

Remove, if plugin is not required.


// StartAsync handles everything: login-server logoff, suppress event,
// disconnect real player, then spawn the ghost.
if (!await manager.StartAsync(player, loginName).ConfigureAwait(false))
Copy link
Member

Choose a reason for hiding this comment

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

You could deserialize the mu helper settings here and pass them as arguments to the manager.

Copy link
Member

Choose a reason for hiding this comment

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

I suggest some changes to this class:

  • Rename to MuHelperSettings
  • Move the serializer logic to a separate class into the GameServer project. The serialization should not be part of GameLogic.

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.

2 participants