Conversation
Summary of ChangesHello, 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
🧠 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
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
/gemini review |
There was a problem hiding this comment.
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.
…gic into specific handlers
0e017fb to
16b178d
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces the impressive offline leveling feature, allowing players to continue grinding after they disconnect. The implementation is comprehensive, creating a 'ghost' player that mimics the MU Helper's behavior through a well-structured set of new classes. The use of a NullViewPlugInContainer to suppress network traffic is a clever approach. The login logic has been thoughtfully refactored to handle session handovers from offline players. Additionally, the new 'Refresh' and 'Duplicate' buttons in the admin panel are welcome usability improvements. The overall code quality is high, with good attention to details like concurrency and resource management. I have one minor suggestion to enhance robustness.
sven-n
left a comment
There was a problem hiding this comment.
Looks almost perfect now!
I didn't review the new LoginAction yet, I need a clear mind for that, hopefully tomorrow 😅
Thanks. It was basically a code extraction with the addition of this lines: The plugin was causing some persistence issues, so I deleted it and moved here. |
|
@gemini-code-assist can you take a closer look at the changes of LoginAction? |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive "Offline Leveling" feature, enabling player characters to continue progression while disconnected, managed by new AI components for combat, buffing, healing, item pickup, movement, and Zen consumption. Key changes include refactoring the login process to handle offline sessions, improving concurrency for player management with ConcurrentDictionary and TryAdd/TryRemove methods, and adjusting logging levels for item/money events to debug. The admin panel now features a refresh button, and the item editor has been enhanced with item duplication and improved item placement logic. A critical issue was identified where an exception during account data reloading after an offline session handover was not logged, which could mask underlying problems.
sven-n
left a comment
There was a problem hiding this comment.
Okay, I had to think a bit until I understood this new logic in the LoginAction. I'm sure it works and a lot of considerations went into it, but it should be improved. player.PersistenceContext.GetAccountByLoginNameAsync is now called twice when offline leveling is involved, and it can actually be a very resource intensive call on the database as it retrieves the whole account data with one big json query.
I think we need a new AccountState? AuthenticateAccountAsync(username, password) function on the persistence context which just retrieves the necessary data and returns just the account state, or null if password is wrong. The flag, that an account is a template shouldn't change between logins of an offline leveling player, imho. So, this information can be taken from the already online OfflineLevelingPlayer.
In the LoginAction we first call the new auth function, then
- If it's an offline leveling player, just load the full account again after the offline manager saved it, not before.
- If it's not an offline leveling player, load the account, right after that, of course.
Both can then be done overGetAccountByLoginNameAsync(userName)without checking the password again.
Can you change this, please? 😅
No problem, all improvement suggestions are welcome.
|
1. 🔴 Login server session leak on offline handover failure In TryEstablishSessionAsync(Player, string), when an offline session is active for a non-template account, TryLoginAsync(string, byte) registers the session on the login server before HandleOfflineSessionHandoverAsync(Player, string) is called. If the handover returns null (e.g., account reload fails), the method returns (false, null) but never calls LogOffAsync() — the account is permanently stuck as "connected" on the login server, blocking all future logins. 2. 🔴 Login server session leak when FinishLoginAsync(Player, string, Account) throws In LoginAsync(Player, string, string), after TryEstablishSessionAsync(Player, string) succeeds (which registers the session on the login server and advances the player state), FinishLoginAsync(Player, string, Account) is called without a try/catch. If it throws (e.g., ShowLoginResultAsync(LoginResult) or InvokeViewPlugInAsync<TViewPlugIn>(this IWorldObserver, Func<TViewPlugIn, ValueTask>) fails), the login server session is never cleaned up. 3. 🟡 TOCTOU race between IsActive(string) and TryGetPlayer(string, out OfflineLevelingPlayer?) IsActive(username) and TryGetPlayer(username, ...) are two separate calls on a ConcurrentDictionary. Between them, another thread could call StopAsync(), removing the entry. This means the code enters the offline branch but TryGetPlayer(string, out OfflineLevelingPlayer?) returns false, making isTemplateOffline = false. This is mostly benign — it just means a non-template login flow is used as fallback — but could cause a redundant StopAsync() call in HandleOfflineSessionHandoverAsync(Player, string) and an unnecessary TryLoginAsync(string, byte) call. A single TryGetPlayer(string, out OfflineLevelingPlayer?) call can replace both: 4. 🟡 Allowed not set to false on some failure paths On line 109, when player.GameContext is not IGameServerContext, the method returns (false, null) but Allowed is not set to false. When the Context is disposed, the state machine may still advance to Authenticated even though the login failed. Additional observation: catch in TryEstablishSessionAsync(Player, string) (line 158–163): If TryLoginAsync(string, byte) succeeded before the exception, the outer catch doesn't call LogOffAsync(). However, tracking whether the login server session was established within this broad catch would add significant complexity. The fix for issue MUnique#2 above covers the most likely post-login failure path (FinishLoginAsync(Player, string, Account)).
sven-n
left a comment
There was a problem hiding this comment.
Okay, I let claude review the LoginAction and it found some stuff - I committed the fixes, I'm clearly impressed...
Then I tested it and found some things:
- Undefined behavior: Should an active offlevel template account stay online when it connects again? I'd say yes, but what do you think? Currently, the offlevel template account is removed from the game when it logs in again.
- Bug?: The raven attack doesn't seem to be working during offlevel. Probably a missing initialization at
Player.PetCommandManagerwhen offline leveling is started. - Bug: When the offlevel player dies, it'll not respawn in the safezone and not removed from the
OfflineLevelingManager. It's stuck in the respawn logic, because the server expects aClientReadyAfterMapChangemessage from the client. TheOfflineLevelingPlayerclass should callPlayer.ClientReadyAfterMapChangeAsyncsomehow. Maybe also a specificIRespawnAfterDeathPlugIncould do that.
|
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:
Technical details:
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.