Skip to content

Fix LoginSession not disposing - #430

Merged
AngeloTadeucci merged 9 commits into
masterfrom
dev
Apr 28, 2025
Merged

Fix LoginSession not disposing#430
AngeloTadeucci merged 9 commits into
masterfrom
dev

Conversation

@AngeloTadeucci

@AngeloTadeucci AngeloTadeucci commented Apr 27, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added heartbeat and disconnect support to channel, world, and login services, enabling improved session and latency management.
    • Introduced new gRPC methods and message types for heartbeat and disconnect operations.
    • Added packet handlers for processing heartbeat responses and quit requests on both game and login servers.
    • Added latency tracking fields to session classes and a maximum allowed latency constant.
    • Implemented periodic heartbeat checks from the world server to login and channel services.
  • Bug Fixes

    • Improved online status detection and default channel assignment for player characters.
  • Refactor

    • Streamlined login handling logic and session management for better reliability and clarity.
    • Updated protobuf definitions and service interfaces to support new operations.
    • Enhanced startup configuration for the login server with gRPC and health checks.
  • Chores

    • Removed unused imports and performed minor code formatting improvements.

@coderabbitai

coderabbitai Bot commented Apr 27, 2025

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@AngeloTadeucci has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 18 minutes and 23 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 7981eff and d9a284d.

📒 Files selected for processing (1)
  • Maple2.Server.World/WorldServer.cs (3 hunks)

Walkthrough

This set of changes introduces heartbeat and disconnect mechanisms across the login, world, and channel services, involving updates to protobuf definitions, service implementations, and session management. Several new gRPC methods and message types are defined and implemented, allowing for heartbeat monitoring and explicit disconnection of sessions. The login and world servers are refactored to use these new RPCs, and session classes are updated to track tick and latency metrics. Additionally, a new packet handler ensures that login sessions are properly disposed of when a quit request is received in the character selection screen. Supporting changes include refactoring the startup logic for the login server and adjustments to player/channel state tracking.

Changes

File(s) Change Summary
Maple2.Server.Core/proto/channel/channel.proto, Maple2.Server.Core/proto/world/world.proto, Maple2.Server.Core/proto/login/login.proto, Maple2.Server.Core/proto/common.proto, Maple2.Server.Core/proto/sync.proto Added new RPC methods (Disconnect, Heartbeat, AccountInfo) and new message types for heartbeat/disconnect; updated request/response fields; introduced login service proto.
Maple2.Server.Game/Service/ChannelService.Sync.cs, Maple2.Server.Game/Service/ChannelService.Heartbeat.cs, Maple2.Server.Game/PacketHandlers/ResponseHeartbeatHandler.cs Added/implemented heartbeat and disconnect gRPC methods; added heartbeat response packet handler.
Maple2.Server.Game/Session/GameSession.cs, Maple2.Server.Login/Session/LoginSession.cs Added tick/latency tracking fields; updated channel state handling and initialization logic.
Maple2.Server.Login/PacketHandlers/LoginHandler.cs, Maple2.Server.Login/PacketHandlers/QuitHandler.cs, Maple2.Server.Login/PacketHandlers/ResponseHeartbeatHandler.cs Refactored login handling to use new disconnect logic; added quit handler to dispose sessions; added heartbeat response handler.
Maple2.Server.Login/Service/LoginService.cs, Maple2.Server.Login/Service/LoginService.Heartbeat.cs Introduced partial login gRPC service and implemented heartbeat method.
Maple2.Server.Login/LoginServer.cs Added method to retrieve all login sessions.
Maple2.Server.Login/Program.cs Refactored startup to use ASP.NET Core WebApplication and gRPC.
Maple2.Server.World/Service/WorldService.Sync.cs, Maple2.Server.World/Containers/PlayerInfoLookup.cs Added/updated account info and disconnect RPC methods; improved player lookup and online player retrieval.
Maple2.Server.World/WorldServer.cs, Maple2.Server.World/Program.cs Added heartbeat thread for periodic health checks; registered login gRPC client.
Maple2.Model/Game/User/PlayerInfo.cs Changed default and logic for channel/online properties.
Maple2.Model/Metadata/Constants.cs, Maple2.Server.Core/Constants/Target.cs Added new constants for latency and gRPC port.
Maple2.Server.Core/Network/Session.cs Removed unused using directives.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant LoginService
    participant WorldService
    participant ChannelService

    Client->>LoginService: RequestQuit
    LoginService->>LoginSession: Disconnect()
    LoginSession-->>LoginService: Session disposed

    Client->>LoginService: Login
    LoginService->>WorldService: AccountInfo (accountId)
    WorldService->>ChannelService: Disconnect (characterId)
    ChannelService-->>WorldService: DisconnectResponse
    WorldService-->>LoginService: PlayerInfoResponse

    WorldService->>LoginService: Heartbeat
    LoginService->>LoginSession: Send Heartbeat packet
    LoginSession-->>LoginService: HeartbeatResponse

    WorldService->>ChannelService: Heartbeat (characterId)
    ChannelService->>GameSession: Send Heartbeat packet
    GameSession-->>ChannelService: HeartbeatResponse
Loading

Assessment against linked issues

Objective Addressed Explanation
Ensure LoginSession is disposed when user quits in character selection screen (#116)

Suggested labels

Field

Poem

A bunny hops through fields of code,
Where heartbeats pulse and sessions unload.
With every quit, a session ends,
Ensuring leaks no longer extend.
Packets bounce and servers cheer,
For clean-up time is finally here!
🐇💻✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
Maple2.Server.Core/Network/Session.cs (1)

113-118: Consider making heartbeat more robust with async implementation.

While the current implementation works, it blocks the thread with Thread.Sleep. Consider an asynchronous approach for better resource utilization.

-protected void Heartbeat() {
-    while (State == SessionState.Connected) {
-        Thread.Sleep(TimeSpan.FromMinutes(1));
-        Send(RequestPacket.Heartbeat());
-    }
-}
+protected async Task HeartbeatAsync(CancellationToken cancellationToken = default) {
+    while (State == SessionState.Connected && !cancellationToken.IsCancellationRequested) {
+        await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);
+        if (State == SessionState.Connected) {
+            Send(RequestPacket.Heartbeat());
+        }
+    }
+}
Maple2.Server.Core/proto/common.proto (1)

337-343: Consider adding a reason field for administrative disconnections.

For audit logging and user communication purposes, it might be helpful to include a reason for the disconnection.

message DisconnectRequest {
  int64 character_id = 1;
+  string reason = 2;
+  bool is_administrative = 3;
}
Maple2.Server.Login/PacketHandlers/ResponseHeartbeat.cs (1)

11-16: Heartbeat response handler reads ticks but takes no action.

The handler reads server and client ticks from the packet but doesn't do anything with them. Consider implementing heartbeat response validation to detect high latency or connection issues.

You could calculate the round-trip time and log or take action if it exceeds a threshold:

public override void Handle(LoginSession session, IByteReader packet) {
    int serverTick = packet.ReadInt();
    int clientTick = packet.ReadInt();

-   // should we do something with the ticks?
+   // Calculate round-trip time
+   int currentTick = Environment.TickCount;
+   int roundTripTime = currentTick - serverTick;
+   
+   // Log or take action if RTT is too high
+   if (roundTripTime > 5000) { // 5 seconds threshold
+       session.Logger.Warning("High latency detected: {RTT}ms", roundTripTime);
+   }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b22bce6 and 6b58462.

📒 Files selected for processing (14)
  • Maple2.Server.Core/Network/Session.cs (2 hunks)
  • Maple2.Server.Core/proto/channel/channel.proto (1 hunks)
  • Maple2.Server.Core/proto/common.proto (1 hunks)
  • Maple2.Server.Core/proto/sync.proto (1 hunks)
  • Maple2.Server.Core/proto/world/world.proto (2 hunks)
  • Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs (1 hunks)
  • Maple2.Server.Game/Service/ChannelService.Sync.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
  • Maple2.Server.Login/PacketHandlers/LoginHandler.cs (1 hunks)
  • Maple2.Server.Login/PacketHandlers/QuitHandler.cs (1 hunks)
  • Maple2.Server.Login/PacketHandlers/ResponseHeartbeat.cs (1 hunks)
  • Maple2.Server.Login/Session/LoginSession.cs (3 hunks)
  • Maple2.Server.World/Containers/PlayerInfoLookup.cs (2 hunks)
  • Maple2.Server.World/Service/WorldService.Sync.cs (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs (4)
Maple2.Server.Core/Network/Session.cs (3)
  • Session (25-307)
  • Session (57-80)
  • Session (82-82)
Maple2.Server.Login/PacketHandlers/ResponseHeartbeat.cs (2)
  • ResponseHeartbeat (8-17)
  • Handle (11-16)
Maple2.Server.Game/Session/GameSession.cs (3)
  • GameSession (37-807)
  • GameSession (109-121)
  • GameSession (705-705)
Maple2.Server.Login/PacketHandlers/QuitHandler.cs (1)
  • Handle (11-13)
Maple2.Server.Game/Session/GameSession.cs (1)
Maple2.Server.Core/Network/Session.cs (1)
  • Heartbeat (113-118)
Maple2.Server.World/Service/WorldService.Sync.cs (7)
Maple2.Server.World/Containers/PlayerInfoLookup.cs (4)
  • TryGet (50-59)
  • PlayerInfo (107-118)
  • PlayerInfo (143-146)
  • TryGetByAccountId (64-67)
Maple2.Database/Storage/Game/GameStorage.User.cs (2)
  • PlayerInfo (100-140)
  • Home (142-193)
Maple2.Model/Game/User/PlayerInfo.cs (3)
  • PlayerInfo (10-110)
  • PlayerInfo (39-44)
  • PlayerInfo (46-48)
Maple2.Server.Game/Service/ChannelService.Sync.cs (3)
  • Task (10-20)
  • Task (22-25)
  • Task (27-40)
Maple2.Server.World/Service/WorldService.Chat.cs (8)
  • Task (11-33)
  • Task (35-66)
  • Task (68-88)
  • Task (90-110)
  • Task (112-117)
  • Task (119-124)
  • Task (126-146)
  • Task (148-153)
Maple2.Server.World/Service/WorldService.Migrate.cs (2)
  • Task (20-67)
  • Task (69-91)
Maple2.Server.World/Containers/ChannelClientLookup.cs (3)
  • Channel (30-53)
  • Channel (43-52)
  • TryGetClient (109-117)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (26)
Maple2.Server.Core/Network/Session.cs (1)

113-118: Good addition of heartbeat mechanism to maintain connection status.

The Heartbeat method provides a clean implementation for sending periodic heartbeat packets to check connection health. The use of a constant 1-minute interval is appropriate for this use case.

Maple2.Server.Core/proto/common.proto (1)

337-343: Good addition of disconnect request/response messages.

The newly added DisconnectRequest and DisconnectResponse messages provide a clear protocol for handling disconnections. The character_id field in the request allows targeting specific users, and the success field in the response enables proper error handling.

Maple2.Server.Core/proto/sync.proto (1)

80-80: Good enhancement to enable account-based player lookups.

Adding the account_id field to PlayerInfoRequest enables more flexible player information retrieval, particularly useful for account-wide operations and detecting duplicate logins.

Maple2.Server.Core/proto/channel/channel.proto (2)

45-46: Good addition of explicit disconnect RPC.

Adding the Disconnect RPC to the Channel service provides a clear mechanism for handling disconnections, which aligns well with the DisconnectRequest and DisconnectResponse messages defined in common.proto.


45-46:

Details

✅ Verification successful

Ensure proper implementation in the ChannelService class.

The implementation of this RPC in the ChannelService class should properly validate the character_id, retrieve the session, and call Disconnect() on it. It should also handle error cases appropriately.


🏁 Script executed:

#!/bin/bash
# Look for Disconnect implementation in ChannelService

# Find ChannelService implementations
fd -e cs | grep -i "channelservice" | xargs grep -l "Disconnect" | xargs cat

Length of output: 4556


Disconnect RPC Implementation Confirmed in ChannelService
The Disconnect override already validates CharacterId, retrieves the GameSession, throws appropriate gRPC errors when invalid or not found, calls session.Disconnect(), and returns a success response. No further action required.

Maple2.Server.Game/Session/GameSession.cs (1)

43-43: Add heartbeat thread to maintain connection health.

Adding a heartbeat thread is a good approach for maintaining connection health and detecting disconnections.

Maple2.Server.World/Containers/PlayerInfoLookup.cs (1)

64-67: Good refactoring of TryGetByAccountId method.

The method now follows the standard TryGet pattern with a boolean return and an out parameter, making it consistent with other similar methods. This refactoring also improves performance by using FirstOrDefault instead of iterating through all cached players.

Maple2.Server.Login/PacketHandlers/QuitHandler.cs (1)

1-15: Good addition of explicit disconnect request handling.

This handler properly processes client disconnect requests by calling the Disconnect() method on the session. This is essential for managing session lifecycles and ensuring clean disconnections.

Maple2.Server.Core/proto/world/world.proto (2)

39-39: LGTM - New AccountInfo RPC added.

This RPC method will allow retrieving player information by account ID using existing message types, which is a logical extension of the existing PlayerInfo functionality.


60-61: LGTM - Disconnect RPC with appropriate comment.

The new Disconnect RPC implements an important mechanism for managing sessions across services, which will help fix the login session disposal issue mentioned in the PR title.

Maple2.Server.Game/Service/ChannelService.Sync.cs (2)

17-19: LGTM - Return statement reformatted for clarity.

The return statement has been reformatted to improve readability without changing the logic.


27-40: LGTM - Disconnect method implementation.

The implementation properly validates the input, retrieves the session, and disconnects it. The proper exception handling with descriptive error messages is a plus.

Maple2.Server.Login/Session/LoginSession.cs (4)

38-38: LGTM - Added heartbeat thread field.

The private readonly thread field is correctly declared for the heartbeat mechanism.


43-43: LGTM - Heartbeat thread initialization.

The heartbeat thread is properly initialized in the constructor, passing the Heartbeat method from the base Session class.


52-52: LGTM - Started heartbeat thread.

The heartbeat thread is started at the appropriate point after the session is marked as connected and the server is notified.


127-127: LGTM - Properly joined heartbeat thread during disposal.

Joining the heartbeat thread ensures it's properly terminated before the session is disposed, preventing resource leaks.

Maple2.Server.Login/PacketHandlers/LoginHandler.cs (4)

33-48: Refactored authentication logic to centralize credential handling.

The authentication logic has been moved to the beginning of the method, which is a good practice as it ensures credentials are verified before proceeding with any command handling. This eliminates duplicate authentication code across different command cases.


50-55: Proper handling of duplicate login sessions.

Good implementation of duplicate login detection and handling. The code checks if there's already an existing session for the same account and properly disconnects it before notifying the current session.


57-73: Added cross-server session management.

Excellent addition that checks if the player is already logged into a game channel and disconnects them. This prevents having multiple active sessions for the same account across different servers and addresses the PR's main objective of fixing LoginSession disposal.


79-79: Disconnect session after server list is sent.

The addition of session.Disconnect() after listing servers is appropriate since the connection is no longer needed at this point. This helps free up server resources and prevents lingering sessions.

Maple2.Server.World/Service/WorldService.Sync.cs (6)

20-21: Refactored response creation to use a helper method.

Good refactoring to use the PlayerInfoResponse helper method for response creation. This improves code reuse and maintainability.


23-33: Added AccountInfo method to retrieve player info by account ID.

This is a valuable addition that enables looking up player information by account ID rather than character ID. This method properly returns an empty response if no player is found, which is consistent with the API design.


36-36: Updated gender validation using pattern matching.

The gender validation has been refactored to use modern C# pattern matching syntax, which improves code readability without changing the logic.


49-57: Enhanced parameter validation and improved account lookup.

The input validation now uses pattern matching for more concise code. The account lookup logic has been corrected to properly check if a player was found by account ID before returning an empty response.


77-94: Added Disconnect method for character disconnection.

This new method is a critical component of the fix for LoginSession disposal. It properly validates the character ID, checks if the player is online and in a valid channel, and then forwards the disconnect request to the appropriate channel client.


96-145: Added helper method for creating PlayerInfoResponse objects.

Excellent addition of a helper method to centralize the creation of PlayerInfoResponse objects. This improves code reuse across both the PlayerInfo and AccountInfo methods, and ensures consistent response formatting.

Comment thread Maple2.Server.Core/Network/Session.cs Outdated
Comment thread Maple2.Server.Core/proto/sync.proto
Comment thread Maple2.Server.Game/Session/GameSession.cs Outdated
Comment thread Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs Outdated

@Zintixx Zintixx left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if we're implementing Heartbeat correct at the moment.
Right now it looks like we're just sending a heartbeat packet just to send it.
Along with Rabbit's comments, I think this serves as a good indicator if the user is online.
What I mean is we should have worldserver be the master for this.
The packet send to client should not originate from Game/LoginSession.
On worldserver, loop every Player online and send a heartbeat packet every 30 seconds and ensure if they're online. You'll know if they're online if they send a packet back. We send that packet to World and check against their tick and update their tick. If their tick is too distant from the ServerTick, we can disconnect due to latency. If we never receive a response back after maybe 1-2 minutes, we force disconnect the session.

Comment thread Maple2.Server.Core/Network/Session.cs Outdated
Comment thread Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (1)
Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs (1)

34-38: Remove unused delta variables

The serverDelta and clientDelta variables are calculated but never used. Either utilize these variables for drift detection or remove them to avoid confusion.

-int serverDelta = serverTick - session.LastServerTick;
-int clientDelta = clientTick - session.LastClientTick;

 session.LastClientTick = clientTick;
 session.LastServerTick = serverTick;
🧹 Nitpick comments (7)
Maple2.Server.Login/Session/LoginSession.cs (1)

39-42: Added latency tracking fields

The addition of these latency tracking fields is good, but consider adding XML documentation comments to explain how these fields are used in the heartbeat mechanism.

+/// <summary>
+/// Last server tick received from the client
+/// </summary>
 public int LastServerTick;
+/// <summary>
+/// Last client tick sent to the server
+/// </summary>
 public int LastClientTick;

+/// <summary>
+/// Current latency in milliseconds between client and server
+/// </summary>
 public int Latency;
Maple2.Server.Login/Service/LoginService.Heartbeat.cs (1)

8-8: Add missing interface implementation

The LoginService is declared as partial, but it's not clear what interface it implements based on this file.

Clarify the class definition to show it's implementing the Login.LoginBase service:

-public partial class LoginService {
+public partial class LoginService : Login.LoginBase {
Maple2.Server.Login/PacketHandlers/ResponseHeartbeat.cs (1)

28-32: Remove unused delta variables

The serverDelta and clientDelta variables are calculated but never used. Either utilize these variables for drift detection or remove them to avoid confusion.

-int serverDelta = serverTick - session.LastServerTick;
-int clientDelta = clientTick - session.LastClientTick;

 session.LastClientTick = clientTick;
 session.LastServerTick = serverTick;
Maple2.Server.Game/Service/ChannelService.Heartbeat.cs (1)

8-20: Add logging for heartbeat operations

Consider adding logging for heartbeat operations to help with diagnostics. This could include logging when sessions are not found or when heartbeats are successfully processed.

 public override Task<HeartbeatResponse> Heartbeat(HeartbeatRequest request, ServerCallContext context) {
     if (request.CharacterId == 0) {
+        logger.LogWarning("Heartbeat request received with Character ID 0");
         throw new RpcException(new Status(StatusCode.NotFound, "Character ID is 0."));
     }
     if (!server.GetSession(request.CharacterId, out GameSession? session)) {
+        logger.LogWarning("Heartbeat request for unknown character: {CharacterId}", request.CharacterId);
         throw new RpcException(new Status(StatusCode.NotFound, "Session not found."));
     }

+    logger.LogTrace("Processing heartbeat for character: {CharacterId}", request.CharacterId);
     session.Send(RequestPacket.Heartbeat());
     return Task.FromResult(new HeartbeatResponse {
         Success = true,
     });
 }
Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs (1)

12-23: Improve latency tracking and handling

The implementation now includes latency threshold checks and session disconnection, which is good. Consider adding logging when a session is disconnected due to high latency.

 session.Latency = Environment.TickCount - serverTick;
 if (session.Latency > Constant.MaxAllowedLatency) {
 #if !DEBUG
+    logger.LogWarning("Disconnecting session due to high latency: {Latency}ms > {MaxAllowed}ms", 
+        session.Latency, Constant.MaxAllowedLatency);
     session.Disconnect();
 #endif
     return;
 }
Maple2.Server.Login/Program.cs (1)

40-44: Port hard-coded through constant – double-check configuration flexibility

ListenAnyIP(Target.GrpcLoginPort …) couples the port to a compile-time constant.
If you want to run multiple instances or allow Ops to override the port, consider binding to configuration:

-options.ListenAnyIP(Target.GrpcLoginPort, listen => {
+int loginPort = builder.Configuration.GetValue("Login:GrpcPort", Target.GrpcLoginPort);
+options.ListenAnyIP(loginPort, listen => {
Maple2.Server.World/WorldServer.cs (1)

60-61: Synchronous gRPC call on login service blocks the whole thread

login.Heartbeat(new HeartbeatRequest()); performs a blocking call; the thread does
nothing else, so this isn’t catastrophic but it ties up a CLR thread pool thread for
network I/O unnecessarily. Using await login.HeartbeatAsync(...) (as shown above)
frees the thread while waiting and follows modern gRPC patterns.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f84289 and 5855251.

📒 Files selected for processing (23)
  • Maple2.Model/Metadata/Constants.cs (1 hunks)
  • Maple2.Server.Core/Constants/Target.cs (1 hunks)
  • Maple2.Server.Core/Network/Session.cs (1 hunks)
  • Maple2.Server.Core/proto/channel/channel.proto (1 hunks)
  • Maple2.Server.Core/proto/common.proto (1 hunks)
  • Maple2.Server.Core/proto/login/login.proto (1 hunks)
  • Maple2.Server.Core/proto/sync.proto (1 hunks)
  • Maple2.Server.Core/proto/world/world.proto (2 hunks)
  • Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs (1 hunks)
  • Maple2.Server.Game/Service/ChannelService.Heartbeat.cs (1 hunks)
  • Maple2.Server.Game/Service/ChannelService.Sync.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Login/PacketHandlers/LoginHandler.cs (1 hunks)
  • Maple2.Server.Login/PacketHandlers/QuitHandler.cs (1 hunks)
  • Maple2.Server.Login/PacketHandlers/ResponseHeartbeat.cs (1 hunks)
  • Maple2.Server.Login/Program.cs (3 hunks)
  • Maple2.Server.Login/Service/LoginService.Heartbeat.cs (1 hunks)
  • Maple2.Server.Login/Service/LoginService.cs (1 hunks)
  • Maple2.Server.Login/Session/LoginSession.cs (3 hunks)
  • Maple2.Server.World/Containers/PlayerInfoLookup.cs (3 hunks)
  • Maple2.Server.World/Program.cs (2 hunks)
  • Maple2.Server.World/Service/WorldService.Sync.cs (3 hunks)
  • Maple2.Server.World/WorldServer.cs (3 hunks)
✅ Files skipped from review due to trivial changes (3)
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Core/Constants/Target.cs
  • Maple2.Server.Login/Service/LoginService.cs
🚧 Files skipped from review as they are similar to previous changes (10)
  • Maple2.Server.Core/proto/sync.proto
  • Maple2.Server.Core/Network/Session.cs
  • Maple2.Server.Login/PacketHandlers/QuitHandler.cs
  • Maple2.Server.Core/proto/world/world.proto
  • Maple2.Server.Core/proto/channel/channel.proto
  • Maple2.Server.World/Containers/PlayerInfoLookup.cs
  • Maple2.Server.Game/Service/ChannelService.Sync.cs
  • Maple2.Server.Core/proto/common.proto
  • Maple2.Server.Login/PacketHandlers/LoginHandler.cs
  • Maple2.Server.World/Service/WorldService.Sync.cs
🧰 Additional context used
🧬 Code Graph Analysis (1)
Maple2.Server.World/WorldServer.cs (2)
Maple2.Server.World/Containers/ChannelClientLookup.cs (4)
  • Channel (30-53)
  • Channel (43-52)
  • ChannelClientLookup (14-236)
  • TryGetClient (109-117)
Maple2.Server.World/Containers/PlayerInfoLookup.cs (5)
  • Sync (84-105)
  • PlayerInfoLookup (16-153)
  • PlayerInfoLookup (29-43)
  • PlayerInfo (107-118)
  • PlayerInfo (143-146)
🪛 Buf (1.47.2)
Maple2.Server.Core/proto/login/login.proto

6-6: import "common.proto": file does not exist

(COMPILE)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (4)
Maple2.Server.Core/proto/login/login.proto (1)

1-10:

Details

✅ Verification successful

Review import path and ensure common.proto exists

The Login service definition looks good, but the static analysis tool reports that "common.proto" doesn't exist.

Verify the existence of the common.proto file and that the import path is correct:


🏁 Script executed:

#!/bin/bash
# Check if common.proto exists in the expected location
if [ -f "Maple2.Server.Core/proto/common.proto" ]; then
  echo "common.proto exists in expected location"
else
  echo "common.proto NOT found in expected location"
  find . -name "common.proto" -type f | head -n 5
fi

Length of output: 141


Import path for common.proto is correct

Verified that Maple2.Server.Core/proto/common.proto exists at the expected location. No changes to the import are required.

🧰 Tools
🪛 Buf (1.47.2)

6-6: import "common.proto": file does not exist

(COMPILE)

Maple2.Server.Login/Session/LoginSession.cs (2)

49-55: Session duplicate-checking logic removed

The previous duplicate session detection and disconnection logic has been removed from this method. Ensure that this functionality has been relocated elsewhere to prevent potential session duplication issues.

Could you confirm where the duplicate session handling logic has been relocated? This is important to maintain proper session management.


116-118: Dictionary initialization reformatted

The dictionary initialization has been reformatted for better readability. This is a good improvement.

Maple2.Server.World/Program.cs (1)

49-52: LGTM: Login client registration looks good

The gRPC client registration for the Login service is properly implemented with appropriate fallback to localhost when the environment variable isn't set.

Comment thread Maple2.Model/Metadata/Constants.cs
Comment thread Maple2.Server.Login/Service/LoginService.Heartbeat.cs
Comment thread Maple2.Server.Login/PacketHandlers/ResponseHeartbeat.cs
Comment thread Maple2.Server.Login/Program.cs
Comment thread Maple2.Server.Login/Program.cs
Comment thread Maple2.Server.World/WorldServer.cs
Comment thread Maple2.Server.World/WorldServer.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5855251 and 73499ff.

📒 Files selected for processing (1)
  • Maple2.Server.Login/LoginServer.cs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build

Comment thread Maple2.Server.Login/LoginServer.cs
Comment thread Maple2.Server.Core/Network/Session.cs Outdated
Comment thread Maple2.Server.Game/PacketHandlers/ResponseHeartbeat.cs Outdated
Comment thread Maple2.Server.Game/Session/GameSession.cs Outdated
Comment thread Maple2.Model/Metadata/Constants.cs
Comment thread Maple2.Server.Game/Session/GameSession.cs
Comment thread Maple2.Server.Game/Session/GameSession.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
Maple2.Server.Login/PacketHandlers/ResponseHeartbeatHandler.cs (1)

28-32: Delta calculation is present but unused.

The code calculates serverDelta and clientDelta but doesn't use these values. Consider either removing these calculations if they're not needed or documenting their purpose for future use.

-       int serverDelta = serverTick - session.ServerTick;
-       int clientDelta = clientTick - session.ClientTick;
        session.ClientTick = clientTick;
        session.ServerTick = serverTick;

Alternatively, if these calculations are meant for future use or debugging:

        // Calculate deltas for monitoring purposes
        int serverDelta = serverTick - session.ServerTick;
        int clientDelta = clientTick - session.ClientTick;
        session.ClientTick = clientTick;
        session.ServerTick = serverTick;
Maple2.Server.Game/PacketHandlers/ResponseHeartbeatHandler.cs (1)

34-39: Delta calculation is present but unused.

The code calculates serverDelta and clientDelta but doesn't use these values. Consider either removing these calculations if they're not needed or documenting their purpose for future use.

-       int serverDelta = serverTick - session.ServerTick;
-       int clientDelta = clientTick - session.ClientTick;

        session.ClientTick = clientTick;
        session.ServerTick = serverTick;

Alternatively, if these calculations are meant for future use or debugging:

        // Calculate deltas for monitoring purposes
        int serverDelta = serverTick - session.ServerTick;
        int clientDelta = clientTick - session.ClientTick;

        session.ClientTick = clientTick;
        session.ServerTick = serverTick;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f487c18 and 7981eff.

📒 Files selected for processing (7)
  • Maple2.Server.Core/Network/Session.cs (1 hunks)
  • Maple2.Server.Game/PacketHandlers/ResponseHeartbeatHandler.cs (1 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (3 hunks)
  • Maple2.Server.Login/PacketHandlers/ResponseHeartbeatHandler.cs (1 hunks)
  • Maple2.Server.Login/Session/LoginSession.cs (3 hunks)
  • Maple2.Server.World/Service/WorldService.Sync.cs (3 hunks)
  • Maple2.Server.World/WorldServer.cs (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Core/Network/Session.cs
🚧 Files skipped from review as they are similar to previous changes (3)
  • Maple2.Server.Login/Session/LoginSession.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.World/WorldServer.cs
🧰 Additional context used
🧬 Code Graph Analysis (1)
Maple2.Server.Login/PacketHandlers/ResponseHeartbeatHandler.cs (3)
Maple2.Server.Core/Network/Session.cs (3)
  • Session (21-296)
  • Session (53-76)
  • Session (78-78)
Maple2.Server.Game/PacketHandlers/ResponseHeartbeatHandler.cs (2)
  • ResponseHeartbeatHandler (9-40)
  • Handle (12-39)
Maple2.Server.Login/Session/LoginSession.cs (3)
  • LoginSession (20-135)
  • LoginSession (42-45)
  • LoginSession (120-120)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: build
  • GitHub Check: build
  • GitHub Check: format
🔇 Additional comments (15)
Maple2.Server.World/Service/WorldService.Sync.cs (7)

11-21: Good refactoring of PlayerInfo method

The pattern matching validation is more readable and the extraction of response creation to a private helper method improves code maintainability.


23-33: New AccountInfo method looks good

This method nicely complements the existing PlayerInfo method by allowing lookups by AccountId instead of CharacterId. Good choice to return an empty response when the account isn't found rather than throwing an exception.


36-36: Good use of pattern matching for validation

The pattern matching syntax makes the validation more concise and readable compared to traditional if statements.


49-49: Pattern matching improves validation readability

The updated validation is more concise and consistent with the pattern used throughout the file.


54-54: Improved fallback logic for player lookup

Good enhancement to try finding the player by AccountId if the CharacterId lookup fails.


77-94: New Disconnect method looks well-implemented

The disconnect method follows the same pattern as other methods in the class:

  1. Validates the input parameters
  2. Checks if the player exists and is online
  3. Gets the appropriate channel client
  4. Forwards the request to the channel

This implementation will help ensure that login sessions are properly disposed when needed.


96-145: Good extraction of response creation logic

The new helper method centralizes the response creation logic, which:

  1. Eliminates code duplication between PlayerInfo and AccountInfo methods
  2. Makes future updates to the response structure easier to maintain
  3. Follows the DRY principle

All necessary player information fields are included in the response.

Maple2.Server.Login/PacketHandlers/ResponseHeartbeatHandler.cs (3)

1-8: Imports and namespace look good.

The imports and namespace declaration are appropriate for this handler class.


9-11: Handler class setup looks correct.

The class is correctly declared as a packet handler for login sessions and properly overrides the OpCode property to handle ResponseHeartbeat packets.


22-26: Initialization logic is correct.

The conditional check for uninitialized ticks and their initialization is correctly implemented.

Maple2.Server.Game/PacketHandlers/ResponseHeartbeatHandler.cs (5)

1-8: Imports and namespace look good.

The imports and namespace declaration are appropriate for this handler class.


9-11: Handler class setup looks correct.

The class is correctly declared as a packet handler for game sessions and properly overrides the OpCode property to handle ResponseHeartbeat packets.


12-23: Latency check and disconnection logic is well implemented.

The handler correctly calculates latency and disconnects sessions with excessive latency, with a safeguard for DEBUG mode. This helps maintain server performance by removing high-latency connections.


24-32: Early returns and initialization logic are correct.

The handler properly handles the cases where ticks are zero and initializes session tick values when needed.


1-40: Verify the consistency across Login and Game server implementations.

The Game server implementation includes latency checking and disconnection, but the Login server implementation does not. This inconsistency could lead to different behavior in handling high-latency connections between the two servers.

Consider updating the Login server handler to include similar latency checking for consistency, or document why the different behavior is intentional.

Comment thread Maple2.Server.Login/PacketHandlers/ResponseHeartbeatHandler.cs
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.

LoginSession is not disposed if user quits in character selection screen

2 participants