From b3b05b716dd0cc58feb2c66423c768c03c7d444a Mon Sep 17 00:00:00 2001 From: Jay Malhotra Date: Fri, 11 Aug 2023 21:39:31 +0100 Subject: [PATCH] Modify statemanager logic around leaving and closing rooms - Don't call to set room visibility to false on RoomBroken, as the state manager will handle this and it can cause errors. - Remove RemovedFromRedis flag in actor state and instead make trying to remove a player from a room they aren't in a non-error --- DragaliaAPI.Photon.Plugin/GluonPlugin.cs | 49 +++++++++---------- .../Models/ActorState.cs | 2 - .../Controllers/EventController.cs | 28 ++++++++--- 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/DragaliaAPI.Photon.Plugin/GluonPlugin.cs b/DragaliaAPI.Photon.Plugin/GluonPlugin.cs index afc2b3562..abaf20ccd 100644 --- a/DragaliaAPI.Photon.Plugin/GluonPlugin.cs +++ b/DragaliaAPI.Photon.Plugin/GluonPlugin.cs @@ -170,8 +170,6 @@ public override void OnLeave(ILeaveGameCallInfo info) Event.RoomBroken, new RoomBroken() { Reason = RoomBroken.RoomBrokenType.HostDisconnected } ); - - this.SetRoomVisibility(info, false); } if (!this.actorState.Remove(info.ActorNr)) @@ -195,40 +193,39 @@ public override void OnLeave(ILeaveGameCallInfo info) return; } - if ( - actor.TryGetViewerId(out int viewerId) - && this.actorState.TryGetValue(info.ActorNr, out ActorState actorState) - && !actorState.RemovedFromRedis - ) + if (!actor.TryGetViewerId(out int viewerId)) { - this.logger.InfoFormat( - "Actor {0} with viewer ID {1} left game {2}", - info.ActorNr, - viewerId, - this.PluginHost.GameId + this.logger.WarnFormat( + "OnLeave: failed to acquire viewer ID of actor {0}", + info.ActorNr ); + return; + } - this.PostStateManagerRequest( - GameLeaveEndpoint, - new GameModifyRequest - { - GameName = this.PluginHost.GameId, - Player = new Player() { ViewerId = viewerId } - }, - info, - true - ); + this.logger.InfoFormat( + "Actor {0} with viewer ID {1} left game {2}", + info.ActorNr, + viewerId, + this.PluginHost.GameId + ); - // For some strange reason on completing a quest this appears to be raised twice for each actor. - // Prevent duplicate requests by setting a flag. - actorState.RemovedFromRedis = true; - } + this.PostStateManagerRequest( + GameLeaveEndpoint, + new GameModifyRequest + { + GameName = this.PluginHost.GameId, + Player = new Player() { ViewerId = viewerId } + }, + info, + true + ); if (this.roomState.MinGoToIngameState > 0) { int newMinGoToIngameState = this.PluginHost.GameActors .Where(x => x.ActorNr != info.ActorNr) .Select(x => x.Properties.GetIntOrDefault(ActorPropertyKeys.GoToIngameState)) + .DefaultIfEmpty() .Min(); this.roomState.MinGoToIngameState = newMinGoToIngameState; diff --git a/DragaliaAPI.Photon.Plugin/Models/ActorState.cs b/DragaliaAPI.Photon.Plugin/Models/ActorState.cs index b1482152e..c878c452f 100644 --- a/DragaliaAPI.Photon.Plugin/Models/ActorState.cs +++ b/DragaliaAPI.Photon.Plugin/Models/ActorState.cs @@ -19,7 +19,5 @@ internal class ActorState public bool Dead { get; set; } public bool Ready { get; set; } - - public bool RemovedFromRedis { get; set; } } } diff --git a/DragaliaAPI.Photon.StateManager/Controllers/EventController.cs b/DragaliaAPI.Photon.StateManager/Controllers/EventController.cs index e5287dd11..bda7e2de2 100644 --- a/DragaliaAPI.Photon.StateManager/Controllers/EventController.cs +++ b/DragaliaAPI.Photon.StateManager/Controllers/EventController.cs @@ -3,6 +3,7 @@ using DragaliaAPI.Photon.Shared.Requests; using DragaliaAPI.Photon.StateManager.Authentication; using DragaliaAPI.Photon.StateManager.Models; +using MessagePack.Formatters; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; @@ -90,6 +91,17 @@ public async Task GameJoin(GameModifyRequest request) return this.Conflict(); } + if (game.Players.Any(x => x.ViewerId == request.Player.ViewerId)) + { + this.logger.LogError( + "Player {@player} attempted to join game {@game} that they were already in.", + request.Player, + game + ); + + return this.Conflict(); + } + game.Players.Add(request.Player); await this.Games.UpdateAsync(game); @@ -117,17 +129,17 @@ public async Task GameLeave(GameModifyRequest request) Player? toRemove = game.Players.FirstOrDefault(x => x.ViewerId == request.Player.ViewerId); if (toRemove is null) { - this.logger.LogError( - "Cannot remove player {@player} from game {@game} as they are not in it.", + this.logger.LogInformation( + "Player {@player} was not in game {@game}", request.Player, game ); - return this.BadRequest(); + return this.Ok(); } game.Players.Remove(toRemove); - if (game.Players.Count == 0) + if (game.Players.Count == 0 || request.Player.ActorNr == 1) { // Don't remove it just yet, as Photon will request that shortly this.logger.LogDebug("Hiding game {@game}", game); @@ -157,8 +169,12 @@ public async Task GameClose(GameModifyRequest request) if (game is null) { - this.logger.LogError("Could not find game {name}", request.GameName); - return this.NotFound(); + this.logger.LogInformation( + "Could not find game {name}. It may have already been closed.", + request.GameName + ); + + return this.Ok(); } await this.Games.DeleteAsync(game);