Skip to content

Feature/automatically creation for new register user and supporting custom player initialization#80

Merged
jun92 merged 13 commits into
mainfrom
feature/automatically-creation-for-new-register-user-and-supporting-custom-player-initialization
Mar 6, 2026
Merged

Feature/automatically creation for new register user and supporting custom player initialization#80
jun92 merged 13 commits into
mainfrom
feature/automatically-creation-for-new-register-user-and-supporting-custom-player-initialization

Conversation

@jun92
Copy link
Copy Markdown
Owner

@jun92 jun92 commented Mar 6, 2026

No description provided.

@jun92 jun92 added this to the Prototype milestone Mar 6, 2026
@jun92 jun92 self-assigned this Mar 6, 2026
@jun92 jun92 added this to ABMGS Mar 6, 2026
@jun92 jun92 added the enhancement New feature or request label Mar 6, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in ABMGS Mar 6, 2026
@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 refines core player management and authentication processes. It introduces a robust system for automatically creating and managing player profiles, ensuring data persistence and a smooth user experience. The authentication mechanism has been enhanced to embed identity provider information directly into JWT tokens, providing richer context for user sessions. Additionally, players can now update their in-game names, a feature fully supported by updated network protocols and database interactions. The underlying database context management has been optimized for better performance and scalability, and the development environment's PostgreSQL setup has been secured.

Highlights

  • Player Data Management: Implemented automatic player data creation and retrieval upon PlayerActor activation, ensuring seamless onboarding for new users and persistent data for existing ones. Player data is now saved upon actor deactivation.
  • Enhanced Authentication: Upgraded JWT authentication to include an Identity Provider (IdP) claim, allowing for more granular control and context regarding the player's origin platform.
  • Player Name Update Feature: Introduced new functionality for players to update their in-game names, complete with new network packet definitions, server-side handling, and a dedicated integration test.
  • Database Context Refactoring: Migrated database context registration from AddDbContextPool to AddDbContextFactory for SyncnetDbContext, improving concurrency and resource management, especially in a distributed system like Orleans.
  • FlatBuffers Schema Updates: Updated the FlatBuffers schema and regenerated code to support the new player name update packets and a simplified user information structure, removing unused fields like 'level' and 'exp'.
  • PostgreSQL Configuration: Configured PostgreSQL in the Aspire host to use a secret password and a data volume, enhancing security and data persistence for the development environment.

🧠 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
  • Source/ABMGS.ServerV2.AspireTests/TestMain.cs
    • Added PlayerNameUpdateText integration test to verify player name update functionality.
    • Added BuildUpdatePlayerNamePacket and BuildReqUserInfoPacket helper methods for testing.
  • Source/ABMGS.Serverv2.Package/Actors/PlayerActor.cs
    • Added _playerData field to store player-specific data.
    • Modified OnActivateAsync to retrieve or create PlayerData from the repository.
    • Implemented OnDeactivateAsync to persist PlayerData changes.
    • Added SetIdProvider, UpdatePlayerName, and GetPlayerName methods.
    • Refactored _repository to _playerModelRepository.
  • Source/ABMGS.Serverv2.Package/Authentication/SyncnetAuthProvider/SyncnetAuth.cs
    • Introduced JwtRegisteredClaimNamesExt static class for a custom Idp claim.
    • Modified IssueNewToken method to accept and include an idProvider claim in the JWT.
  • Source/ABMGS.Serverv2.Package/Controllers/AuthController.cs
    • Updated TestIssueToken and IssueToken methods to pass the SupportedPlatformType as the idProvider when issuing JWT tokens.
  • Source/ABMGS.Serverv2.Package/Controllers/GameSessionController.cs
    • Added SyncnetAuthProvider namespace.
    • Modified GameSession method to extract the Idp claim from the JWT.
    • Updated player ID parsing to also include providerFrom from the Idp claim.
  • Source/ABMGS.Serverv2.Package/Databases/SyncnetDbContext.cs
    • Added Created property with DateTime.UtcNow default to the PlayerData model.
  • Source/ABMGS.Serverv2.Package/Extensions/FrontendApplicationBuilderExtension.cs
    • Changed AddDbContextPool to AddDbContextFactory for SyncnetDbContext registration.
  • Source/ABMGS.Serverv2.Package/Extensions/SiloApplicationBuilderExtension.cs
    • Changed AddDbContextPool to AddDbContextFactory for SyncnetDbContext registration.
  • Source/ABMGS.Serverv2.Package/Interfaces/Actors/IPlayerActor.cs
    • Added GetPlayerName, SetIdProvider, and UpdatePlayerName method declarations.
  • Source/ABMGS.Serverv2.Package/Migrations/20251217051244_InitCreated.Designer.cs
    • Renamed to 20260305034242_Init.Designer.cs.
    • Updated ProductVersion to '10.0.3'.
    • Added Created column to the PlayerData table in the model snapshot.
  • Source/ABMGS.Serverv2.Package/Migrations/20251217051244_InitCreated.cs
    • Renamed to 20260305034242_Init.cs.
    • Added Created column to the Players table in the Up method.
  • Source/ABMGS.Serverv2.Package/Migrations/SyncnetDbContextModelSnapshot.cs
    • Updated ProductVersion to '10.0.3'.
    • Added Created column to the PlayerData entity configuration.
  • Source/ABMGS.Serverv2.Package/Network/Handlers/SystemPacketHandler.cs
    • Modified HandleReqUserInfo to retrieve and send the player's name.
    • Replaced HandleReqCreateNewUser with HandleReqUpdatePlayerName to process player name update requests.
  • Source/ABMGS.Serverv2.Package/Network/Sessions/GameSessionService.cs
    • Added logic to set the Idp for the PlayerActor during RunGameLoop.
  • Source/ABMGS.Serverv2.Package/PacketBuilder/Args.cs
    • Removed ReqCreateNewUserArgs and ResCreateNewUserArgs.
    • Modified ResUserInfoArgs to remove level and exp parameters.
    • Added ReqUpdatePlayerNameArgs and ResUpdatePlayerNameArgs.
  • Source/ABMGS.Serverv2.Package/PacketBuilder/PacketBuilders.cs
    • Updated ResUserInfoPacketBuilder to match the simplified ResUserInfoArgs.
    • Replaced ReqCreateNewUserPacketBuilder and ResCreateNewUserPacketBuilder with ReqUpdatePlayerNamePacketBuilder and ResUpdatePlayerNamePacketBuilder.
    • Commented out the old ReqCreateNewUserPacketBuilder and ResCreateNewUserPacketBuilder.
  • Source/ABMGS.Serverv2.Package/fbs/Player.fbs
    • Removed ReqCreateNewUser and ResCreateNewUser FlatBuffer tables.
    • Modified ResUserInfo table to remove level and exp fields.
    • Added ReqUpdatePlayerName and ResUpdatePlayerName FlatBuffer tables.
  • Source/ABMGS.Serverv2.Package/fbs/System.fbs
    • Updated SystemPacket union to remove ReqCreateNewUser and ResCreateNewUser, and include ReqUpdatePlayerName and ResUpdatePlayerName.
  • Source/ABMGS.Serverv2.Package/generated/SyncnetPlatform/Protocols/Generated/PacketWrapper.cs
    • Updated SystemPacketAs... methods to reflect changes in SystemPacket union.
  • Source/ABMGS.Serverv2.Package/generated/SyncnetPlatform/Protocols/Generated/ReqUpdatePlayerName.cs
    • Added new generated FlatBuffers file for ReqUpdatePlayerName.
  • Source/ABMGS.Serverv2.Package/generated/SyncnetPlatform/Protocols/Generated/ResUpdatePlayerName.cs
    • Added new generated FlatBuffers file for ResUpdatePlayerName.
  • Source/ABMGS.Serverv2.Package/generated/SyncnetPlatform/Protocols/Generated/ResUserInfo.cs
    • Modified to remove Level and Exp properties and related build/verify methods.
  • Source/ABMGS.Serverv2.Package/generated/SyncnetPlatform/Protocols/Generated/SystemPacket.cs
    • Updated SystemPacket enum and Verify method to reflect changes in the System.fbs union.
  • Source/AppHost/AppHost.cs
    • Modified PostgreSQL configuration to use a secret password and add a data volume.
  • Source/AppHost/appsettings.json
    • Added postgres-password parameter to appsettings.json.
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
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 functionality for automatically creating new users and allowing them to update their player names, with changes across database models, repositories, actors, network handlers, and tests. However, a critical authentication bypass was identified in the AuthController where a test endpoint allows issuing valid JWT tokens for any player ID without authentication. Additionally, a medium-severity issue exists in the SystemPacketHandler due to insufficient input validation on the player name, which could lead to Denial of Service or injection attacks. Beyond these security concerns, the review also highlighted a bug where the identity provider is hardcoded instead of being read from the JWT token, opportunities for code cleanup (e.g., removing unused fields, redundant checks, commented-out code), suggestions to improve performance by avoiding unnecessary async/await state machines, and a minor naming convention issue in the tests.

Comment on lines 39 to 42
public async Task<IActionResult> TestIssueToken([FromRoute] string playerId)
{
return Ok(_syncnetJwtAuthenticationService.IssueNewToken(playerId));
return Ok(_syncnetJwtAuthenticationService.IssueNewToken(playerId, SupportedPlatformType.guest.ToString()));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-critical critical

The TestIssueToken endpoint allows any user to obtain a valid JWT token for any playerId without any authentication or authorization. This token can then be used to access the game session and manipulate the data of any player. This is a critical authentication bypass vulnerability. Remove this endpoint from production code. If it is needed for testing, ensure it is only available in development environments (e.g., using #if DEBUG) or protected by strong authentication.

Comment on lines +87 to +89
if(
!Guid.TryParse(userIdClaim, out Guid playerId) ||
!Enum.TryParse(typeof(SupportedPlatformType), userIdpClaim, out var providerFrom))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The providerFrom variable is parsed from the JWT claim but is never used. The identity provider is then hardcoded to guest in GameSessionService.cs. This seems like a bug. The providerFrom value should be passed to _gameSessionService.StartGameSession and used to set the player's identity provider.

You should consider changing the signature of IGameSessionService.StartGameSession to accept the provider type.

{
IPacketHandlerActor packetHandlingActor = _clusterClient.GetGrain<IPacketHandlerActor>(playerId);
IPlayerActor playerActor = _clusterClient.GetGrain<IPlayerActor>(playerId);
await playerActor.SetIdProvider(Controllers.SupportedPlatformType.guest);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The identity provider is hardcoded to SupportedPlatformType.guest. This should be a parameter passed into this method, originating from the JWT token claims parsed in GameSessionController. Hardcoding this value prevents the system from correctly handling different identity providers.

var PlayerData = ctx.GetPlayerData();
await PlayerData.CreateNewPlayerData(request.PlayerName);
IPlayerActor player = ctx.GetPlayer();
await player.UpdatePlayerName(request.PlayerName);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-medium medium

The HandleReqUpdatePlayerName method accepts a player name from a client-supplied packet and passes it directly to the UpdatePlayerName method without any validation or sanitization. An attacker could provide an arbitrarily long string, leading to a Denial of Service (DoS) by consuming database space or memory. Furthermore, if this name is later rendered in a UI without proper escaping, it could lead to Cross-Site Scripting (XSS) or other injection attacks. Implement strict validation on the PlayerName input, including a maximum length check and potentially a whitelist of allowed characters.


var wsClient = await OpenAuthoredWebSocket(wsUri, token);

string RandomPlayerName = "Guest" + CreateRandomString(6);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

According to C# naming conventions, local variable names should use camelCase. Please rename RandomPlayerName to randomPlayerName here and in its subsequent usages on lines 98 and 121 to improve readability and maintainability.

        string randomPlayerName = "Guest" + CreateRandomString(6);

Comment on lines +23 to +25
protected int _dbid;
protected string _name = String.Empty;
protected SupportedPlatformType _idpFrom;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The fields _dbid, _name, and _idpFrom are declared but their values are never read. Please remove them to clean up the code and improve maintainability.

Comment on lines +54 to +57
if(_playerData != null)
{
await _playerModelRepository.Update(_playerData);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The _playerData field is initialized on declaration and re-assigned in OnActivateAsync from GetOrCreate, which is guaranteed to return a non-null object. Therefore, _playerData will never be null here. This null check is redundant and can be removed.

            await _playerModelRepository.Update(_playerData);

Comment on lines +66 to +74
public async Task UpdatePlayerName(string newName)
{
_playerData.PlayerName = newName;
}

public async Task<string> GetPlayerName()
{
return _playerData.PlayerName;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The methods UpdatePlayerName and GetPlayerName are marked async but do not perform any awaitable operations. This adds unnecessary overhead from the async state machine. You can make them more efficient by removing async and returning Task.CompletedTask and Task.FromResult respectively.

    public Task UpdatePlayerName(string newName)
    {
        _playerData.PlayerName = newName;
        return Task.CompletedTask;
    }

    public Task<string> GetPlayerName()
    {
        return Task.FromResult(_playerData.PlayerName);
    }

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@gemini-code-assist Does Orleans Grain's method should be async type?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That's an excellent question, and it touches on a core aspect of Orleans Grain development!

Orleans Grain methods, especially those exposed on the grain interface, must return Task or ValueTask (or their generic versions like Task<T> or ValueTask<T>). This is because all calls to grains are inherently asynchronous, even if the grain's internal logic is synchronous. The Orleans runtime handles the asynchronous messaging and scheduling.

My previous suggestion was specifically about the async keyword. While grain methods must return a Task, the async keyword itself is only necessary if you are using the await keyword inside the method. If a method is marked async but doesn't contain any await operations, the C# compiler still generates an asynchronous state machine, which introduces a small, unnecessary overhead.

By removing the async keyword and explicitly returning Task.CompletedTask (for Task returning methods) or Task.FromResult(value) (for Task<T> returning methods), you achieve the following:

  1. Maintain Orleans compatibility: The methods still return Task, satisfying the Orleans requirement for asynchronous grain methods.
  2. Optimize performance: You avoid the overhead of the compiler-generated state machine when no await operations are actually performed.

So, to summarize: Orleans Grain methods should always be Task-returning, but they only need to be marked async if they perform await operations internally. If they don't, you can optimize them by removing async and returning Task.CompletedTask or Task.FromResult.

Comment on lines +97 to +115
//internal class ReqCreateNewUserPacketBuilder: PacketBABuilder<ReqCreateNewUserArgs>
//{
// public override byte[] Build(ReqCreateNewUserArgs args)
// {
// var builder = CreateBuilder();
// StringOffset playerName = builder.CreateString(args.PlayerName);
// Offset<ReqCreateNewUser> offsetCreateNewUser = ReqCreateNewUser.CreateReqCreateNewUser(builder, playerName);
// return Wrap(builder, SystemPacket.ReqCreateNewUser, offsetCreateNewUser.Value);
// }
//}
//internal class ResCreateNewUserPacketBuilder : PacketBABuilder<ResCreateNewUserArgs>
//{
// public override byte[] Build(ResCreateNewUserArgs args)
// {
// var builder = CreateBuilder();
// Offset<ResCreateNewUser> offsetCreateNewUser = ResCreateNewUser.CreateResCreateNewUser(builder, args.ErrorCode);
// return Wrap(builder, SystemPacket.ResCreateNewUser, offsetCreateNewUser.Value);
// }
//}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This block of commented-out code should be removed to improve code clarity and maintainability. If it's for reference, it should be documented elsewhere, not left as dead code in the source.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

migrationBuilder.CreateTable(
name: "player_data",

P1 Badge Preserve existing EF migration chain

This migration re-creates the baseline tables as a new initial migration instead of extending the existing chain, which breaks upgrades for databases that already applied the prior initial migration (20251217051244_InitCreated). Since startup runs Database.Migrate() (Source/ABMGS.Serverv2.Package/Extensions/HostExtension.cs), those environments will see 20260305034242_Init as pending and attempt CreateTable again, causing startup failures on already-existing tables; this should be an additive migration (e.g., only add Created) rather than replacing the initial migration ID.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

string? userIdpClaim = User.FindFirstValue(JwtRegisteredClaimNamesExt.Idp);

ArgumentNullException.ThrowIfNullOrEmpty(userIdClaim);
ArgumentNullException.ThrowIfNullOrEmpty(userIdpClaim);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid throwing on missing Idp claim in websocket auth path

Using ArgumentNullException.ThrowIfNullOrEmpty(userIdpClaim) here turns a missing Idp claim into an unhandled exception (HTTP 500) instead of a controlled auth failure, which affects clients presenting still-valid tokens that were issued before this claim was added (or any token without that custom claim). The endpoint should return 400/401 for invalid claims rather than throwing from request handling.

Useful? React with 👍 / 👎.

@jun92 jun92 merged commit ca39ce9 into main Mar 6, 2026
3 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in ABMGS Mar 6, 2026
@jun92 jun92 deleted the feature/automatically-creation-for-new-register-user-and-supporting-custom-player-initialization branch March 6, 2026 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Automatically creation for new register user and supporting custom player initialization

1 participant