Feat: accept optional client username and forward to ClientApp #271

Merged
jona.walpert merged 15 commits from feat/change-username-at-start-or-in-game into main 2026-04-12 11:17:39 +02:00
3 changed files with 26 additions and 44 deletions
Showing only changes of commit 999dd9beb9 - Show all commits
@@ -51,8 +51,7 @@ public class User {
} }
/** /**
* Sets a new display name for this user. Thread-safe; callers must ensure the * Sets a new display name for this user. Thread-safe; callers must ensure the registry is
* registry is
* updated to maintain uniqueness when needed. * updated to maintain uniqueness when needed.
* *
* @param newName the new display name * @param newName the new display name
@@ -73,8 +72,7 @@ public class User {
/** /**
* Returns the time at which this user disconnected, if applicable. * Returns the time at which this user disconnected, if applicable.
* *
* @return an Optional containing the disconnect timestamp, or empty if * @return an Optional containing the disconnect timestamp, or empty if connected
* connected
*/ */
public Optional<Instant> getDisconnectedAt() { public Optional<Instant> getDisconnectedAt() {
return Optional.ofNullable(disconnectedAt); return Optional.ofNullable(disconnectedAt);
@@ -90,10 +88,7 @@ public class User {
this.disconnectedAt = null; this.disconnectedAt = null;
} }
/** /** Marks this user as disconnected by clearing the session and recording the timestamp. */
* Marks this user as disconnected by clearing the session and recording the
* timestamp.
*/
public void markDisconnected() { public void markDisconnected() {
this.sessionId = null; this.sessionId = null;
this.disconnectedAt = Instant.now(); this.disconnectedAt = Instant.now();
@@ -18,16 +18,13 @@ public class UserFactory {
} }
/** /**
* Creates and registers a new user with the given name and session. If the name * Creates and registers a new user with the given name and session. If the name is already
* is already * taken, a numeric suffix is appended and incremented until a free name is found (e.g.
* taken, a numeric suffix is appended and incremented until a free name is * Lars_001, Lars_002, ...). If the desiredName is null or empty, an automatic name of the form
* found (e.g. * "playerN" is assigned, incrementing N until a free name is found.
* Lars_001, Lars_002, ...). If the desiredName is null or empty, an automatic
* name of the
* form "playerN" is assigned, incrementing N until a free name is found.
* *
* @param desiredName the preferred display name * @param desiredName the preferred display name
* @param sessionId the session to associate with the new user * @param sessionId the session to associate with the new userwas
* @return the newly created and registered user * @return the newly created and registered user
*/ */
public User create(String desiredName, SessionId sessionId) { public User create(String desiredName, SessionId sessionId) {
@@ -12,8 +12,7 @@ public class UserRegistry {
private final ConcurrentHashMap<SessionId, User> bySessionId = new ConcurrentHashMap<>(); private final ConcurrentHashMap<SessionId, User> bySessionId = new ConcurrentHashMap<>();
/** /**
* Attempts to register a user under the given name atomically. Returns the * Attempts to register a user under the given name atomically. Returns the registered user, or
* registered user, or
* empty if the name is already taken. * empty if the name is already taken.
* *
* @param name the desired display name * @param name the desired display name
@@ -93,10 +92,8 @@ public class UserRegistry {
} }
/** /**
* Removes the user with the given ID, but only if they are still disconnected. * Removes the user with the given ID, but only if they are still disconnected. This prevents
* This prevents * removing a user who has reconnected between the cleanup job's check and its removal call.
* removing a user who has reconnected between the cleanup job's check and its
* removal call.
* *
* @param userId the ID of the user to remove * @param userId the ID of the user to remove
*/ */
@@ -115,8 +112,7 @@ public class UserRegistry {
} }
/** /**
* Marks the user associated with the given session as disconnected, clearing * Marks the user associated with the given session as disconnected, clearing the session
* the session
* association and recording the disconnect timestamp. * association and recording the disconnect timestamp.
* *
* @param sessionId the session ID of the disconnected client * @param sessionId the session ID of the disconnected client
@@ -131,8 +127,7 @@ public class UserRegistry {
} }
/** /**
* Reassociates a user with a new session, effectively restoring them after a * Reassociates a user with a new session, effectively restoring them after a reconnect.
* reconnect.
* *
* @param userId the ID of the user to reconnect * @param userId the ID of the user to reconnect
* @param sessionId the new session ID * @param sessionId the new session ID
@@ -153,8 +148,7 @@ public class UserRegistry {
* Looks up a user by their {@link SessionId}. * Looks up a user by their {@link SessionId}.
* *
* @param sessionId the SessionId to look up * @param sessionId the SessionId to look up
* @return an Optional containing the {@link User}, or empty if no user is * @return an Optional containing the {@link User}, or empty if no user is associated with this
* associated with this
* SessionId * SessionId
*/ */
public Optional<User> getBySessionId(SessionId sessionId) { public Optional<User> getBySessionId(SessionId sessionId) {
@@ -165,8 +159,7 @@ public class UserRegistry {
* Looks up a user by their {@link UserId}. * Looks up a user by their {@link UserId}.
* *
* @param userId the UserId to look up * @param userId the UserId to look up
* @return an Optional containing the {@link User}, or empty if no user is * @return an Optional containing the {@link User}, or empty if no user is associated with this
* associated with this
* UserId * UserId
*/ */
public Optional<User> getByUserId(UserId userId) { public Optional<User> getByUserId(UserId userId) {
@@ -177,8 +170,7 @@ public class UserRegistry {
* Looks up a user by their username. * Looks up a user by their username.
* *
* @param username the username to look up * @param username the username to look up
* @return an Optional containing the {@link User}, or empty if no user is * @return an Optional containing the {@link User}, or empty if no user is associated with this
* associated with this
* username * username
*/ */
public Optional<User> getByUsername(String username) { public Optional<User> getByUsername(String username) {
@@ -195,14 +187,12 @@ public class UserRegistry {
} }
/** /**
* Attempts to change the username of an existing user. Ensures the new name is * Attempts to change the username of an existing user. Ensures the new name is not already
* not already
* taken and updates internal indices atomically. * taken and updates internal indices atomically.
* *
* @param userId the id of the user to rename * @param userId the id of the user to rename
* @param newName the desired new name * @param newName the desired new name
* @return true if the rename succeeded, false if the name was already taken or * @return true if the rename succeeded, false if the name was already taken or user not found
* user not found
*/ */
public synchronized boolean changeUsername(UserId userId, String newName) { public synchronized boolean changeUsername(UserId userId, String newName) {
User user = byId.get(userId); User user = byId.get(userId);