diff --git a/TournamentAssistant/UI/FlowCoordinators/RoomCoordinator.cs b/TournamentAssistant/UI/FlowCoordinators/RoomCoordinator.cs index 2d73f9e3..6e563091 100644 --- a/TournamentAssistant/UI/FlowCoordinators/RoomCoordinator.cs +++ b/TournamentAssistant/UI/FlowCoordinators/RoomCoordinator.cs @@ -588,7 +588,11 @@ public void SongFinished(StandardLevelScenesTransitionSetupDataSO standardLevelS Difficulties = map.parentDifficultyBeatmapSet.difficultyBeatmaps.Select(x => (int)x.difficulty).ToArray() } }, - Score = results.modifiedScore + Score = results.modifiedScore, + Misses = results.missedCount, + BadCuts = results.badCutsCount, + GoodCuts = results.goodCutsCount, + EndTime = results.endSongTime }; if (results.levelEndStateType == LevelCompletionResults.LevelEndStateType.Cleared) diff --git a/TournamentAssistantCore/Properties/PublishProfiles/Docker.pubxml.user b/TournamentAssistantCore/Properties/PublishProfiles/Docker.pubxml.user index 293b2f36..e53a0329 100644 --- a/TournamentAssistantCore/Properties/PublishProfiles/Docker.pubxml.user +++ b/TournamentAssistantCore/Properties/PublishProfiles/Docker.pubxml.user @@ -5,6 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAgLk4hF8hxkiQ4cN43iSg7QAAAAACAAAAAAAQZgAAAAEAACAAAAC8Sc4fYUa+pPv8FqV9y4fAc+xCbmMWjHaWkNO2FxOrAAAAAAAOgAAAAAIAACAAAACLSwjFK4hPrz9yiKpBuF376VK8+p17OSWwOPXgmYTbaCAAAACrSl4IwcYt26VqOU9wOo+potPvZIb/NK6FmcDuKu2STkAAAABxh2+7mXLQT4WAOBdSLjvZkMrGLayMc/i4jtsXEoq9/6H3/x8fezQotV1AMNo1kEQygdlJZK6VEWzGySVJWPqy - True|2022-05-31T05:04:46.8734125Z;True|2022-05-24T18:10:10.9432816-05:00;True|2022-05-20T00:48:31.1875219-05:00;False|2022-05-20T00:36:09.3699887-05:00;True|2022-05-19T23:32:40.4898188-05:00;False|2022-05-19T23:29:05.2480570-05:00;True|2022-05-10T00:05:07.5292150-05:00;False|2022-05-10T00:02:10.1918955-05:00;True|2022-04-30T16:38:37.1271080-05:00;True|2022-04-30T16:29:18.9429794-05:00;False|2022-04-30T15:33:44.6878088-05:00;False|2022-04-30T15:30:26.1186139-05:00;False|2022-04-30T15:26:53.4525242-05:00;False|2022-04-30T15:25:34.9467241-05:00;False|2022-04-30T14:55:17.3885287-05:00;False|2022-04-30T14:39:42.4783680-05:00;False|2022-04-30T14:35:58.9702981-05:00;False|2022-04-30T14:23:28.3338839-05:00;False|2022-04-30T14:20:47.8025347-05:00;False|2022-04-30T14:10:49.7546588-05:00;False|2022-04-30T14:06:39.9156950-05:00;False|2022-04-30T13:59:27.1702334-05:00;False|2022-04-30T13:57:34.2037863-05:00;False|2022-04-30T13:45:03.5555315-05:00;False|2022-04-30T13:42:58.7480471-05:00;False|2022-04-30T13:42:33.4223134-05:00;False|2022-04-30T13:33:49.9959663-05:00;False|2022-04-30T01:11:15.8646243-05:00;False|2022-04-30T01:08:38.2080358-05:00;False|2022-04-30T01:05:43.1047108-05:00;False|2022-04-30T01:00:34.5274425-05:00;False|2022-04-30T00:53:49.0872590-05:00;False|2022-04-30T00:51:25.5073205-05:00;False|2022-04-30T00:50:48.7949266-05:00;False|2022-04-30T00:47:08.2989707-05:00;False|2022-04-30T00:46:50.6142024-05:00;False|2022-04-30T00:46:35.5329678-05:00;False|2022-04-30T00:45:28.0401932-05:00;False|2022-04-30T00:36:12.5530251-05:00;False|2022-04-30T00:30:44.8961474-05:00;False|2022-04-30T00:27:55.9635992-05:00;False|2022-04-30T00:26:30.2101687-05:00;False|2022-04-30T00:22:58.6204642-05:00;True|2021-08-13T20:40:00.8260412-05:00;False|2021-08-13T20:38:44.3992083-05:00;False|2021-08-13T20:36:58.0439107-05:00;False|2021-08-13T20:33:10.5051184-05:00;False|2021-08-13T20:27:53.2235208-05:00;False|2021-08-13T20:27:16.7369936-05:00;False|2021-08-13T20:26:25.6866293-05:00;False|2021-08-13T20:24:31.5457991-05:00;False|2021-08-13T20:24:13.4994144-05:00; + True|2024-06-28T00:18:33.5337402Z;True|2022-05-31T00:04:46.8734125-05:00;True|2022-05-24T18:10:10.9432816-05:00;True|2022-05-20T00:48:31.1875219-05:00;False|2022-05-20T00:36:09.3699887-05:00;True|2022-05-19T23:32:40.4898188-05:00;False|2022-05-19T23:29:05.2480570-05:00;True|2022-05-10T00:05:07.5292150-05:00;False|2022-05-10T00:02:10.1918955-05:00;True|2022-04-30T16:38:37.1271080-05:00;True|2022-04-30T16:29:18.9429794-05:00;False|2022-04-30T15:33:44.6878088-05:00;False|2022-04-30T15:30:26.1186139-05:00;False|2022-04-30T15:26:53.4525242-05:00;False|2022-04-30T15:25:34.9467241-05:00;False|2022-04-30T14:55:17.3885287-05:00;False|2022-04-30T14:39:42.4783680-05:00;False|2022-04-30T14:35:58.9702981-05:00;False|2022-04-30T14:23:28.3338839-05:00;False|2022-04-30T14:20:47.8025347-05:00;False|2022-04-30T14:10:49.7546588-05:00;False|2022-04-30T14:06:39.9156950-05:00;False|2022-04-30T13:59:27.1702334-05:00;False|2022-04-30T13:57:34.2037863-05:00;False|2022-04-30T13:45:03.5555315-05:00;False|2022-04-30T13:42:58.7480471-05:00;False|2022-04-30T13:42:33.4223134-05:00;False|2022-04-30T13:33:49.9959663-05:00;False|2022-04-30T01:11:15.8646243-05:00;False|2022-04-30T01:08:38.2080358-05:00;False|2022-04-30T01:05:43.1047108-05:00;False|2022-04-30T01:00:34.5274425-05:00;False|2022-04-30T00:53:49.0872590-05:00;False|2022-04-30T00:51:25.5073205-05:00;False|2022-04-30T00:50:48.7949266-05:00;False|2022-04-30T00:47:08.2989707-05:00;False|2022-04-30T00:46:50.6142024-05:00;False|2022-04-30T00:46:35.5329678-05:00;False|2022-04-30T00:45:28.0401932-05:00;False|2022-04-30T00:36:12.5530251-05:00;False|2022-04-30T00:30:44.8961474-05:00;False|2022-04-30T00:27:55.9635992-05:00;False|2022-04-30T00:26:30.2101687-05:00;False|2022-04-30T00:22:58.6204642-05:00;True|2021-08-13T20:40:00.8260412-05:00;False|2021-08-13T20:38:44.3992083-05:00;False|2021-08-13T20:36:58.0439107-05:00;False|2021-08-13T20:33:10.5051184-05:00;False|2021-08-13T20:27:53.2235208-05:00;False|2021-08-13T20:27:16.7369936-05:00;False|2021-08-13T20:26:25.6866293-05:00;False|2021-08-13T20:24:31.5457991-05:00;False|2021-08-13T20:24:13.4994144-05:00; + \ No newline at end of file diff --git a/TournamentAssistantCore/StateManager.cs b/TournamentAssistantCore/StateManager.cs new file mode 100644 index 00000000..bdce8223 --- /dev/null +++ b/TournamentAssistantCore/StateManager.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TournamentAssistantShared.Models; +using TournamentAssistantShared.Models.Packets; +using TournamentAssistantShared.Utilities; + +namespace TournamentAssistantCore +{ + internal class StateManager + { + public event Func UserConnected; + public event Func UserDisconnected; + public event Func UserInfoUpdated; + public event Func MatchInfoUpdated; + public event Func MatchCreated; + public event Func MatchDeleted; + + private SystemServer Server { get; set; } + + public StateManager(SystemServer server) + { + Server = server; + } + + public List GetUsers() + { + lock (Server.State.Users) + { + return Server.State.Users.ToList(); + } + } + + public User GetUserById(string guid) + { + lock (Server.State.Users) + { + return Server.State.Users.FirstOrDefault(x => x.Guid == guid.ToString()); + } + } + + public List GetMatches() + { + lock (Server.State.Matches) + { + return Server.State.Matches.ToList(); + } + } + + public List GetServers() + { + lock (Server.State.KnownHosts) + { + return Server.State.KnownHosts.ToList(); + } + } + + #region EventManagement + public async Task AddUser(User user) + { + lock (Server.State.Users) + { + Server.State.Users.Add(user); + } + + var @event = new Event + { + user_added_event = new Event.UserAddedEvent + { + User = user + } + }; + + await Server.BroadcastToAllClients(new Packet + { + Event = @event + }); + + if (UserConnected != null) await UserConnected.Invoke(user); + } + + public async Task UpdateUser(User user) + { + lock (Server.State.Users) + { + var userToReplace = Server.State.Users.FirstOrDefault(x => x.UserEquals(user)); + Server.State.Users.Remove(userToReplace); + Server.State.Users.Add(user); + } + + var @event = new Event + { + user_updated_event = new Event.UserUpdatedEvent + { + User = user + } + }; + await Server.BroadcastToAllClients(new Packet + { + Event = @event + }); + + if (UserInfoUpdated != null) await UserInfoUpdated.Invoke(user); + } + + public async Task RemoveUser(User user) + { + User userToRemove; + lock (Server.State.Users) + { + userToRemove = Server.State.Users.FirstOrDefault(x => x.UserEquals(user)); + if (userToRemove == null) + { + return; + } + Server.State.Users.Remove(userToRemove); + } + + var @event = new Event + { + user_left_event = new Event.UserLeftEvent + { + User = user + } + }; + + await Server.BroadcastToAllClients(new Packet + { + Event = @event + }); + + for (int i = 0; i < Server.State.Matches.Count; i++) + { + var m = Server.State.Matches[i]; + if (m.AssociatedUsers.Contains(userToRemove.Guid)) + { + m.AssociatedUsers.RemoveAll((x) => x == userToRemove.Guid); + await UpdateMatch(m); + } + } + + if (UserDisconnected != null) await UserDisconnected.Invoke(user); + } + + public async Task CreateMatch(Match match) + { + lock (Server.State.Matches) + { + Server.State.Matches.Add(match); + } + + var @event = new Event + { + match_created_event = new Event.MatchCreatedEvent + { + Match = match + } + }; + await Server.BroadcastToAllClients(new Packet + { + Event = @event + }); + + if (MatchCreated != null) await MatchCreated.Invoke(match); + } + + public async Task UpdateMatch(Match match) + { + lock (Server.State.Matches) + { + var matchToReplace = Server.State.Matches.FirstOrDefault(x => x.MatchEquals(match)); + Server.State.Matches.Remove(matchToReplace); + Server.State.Matches.Add(match); + } + + var @event = new Event + { + match_updated_event = new Event.MatchUpdatedEvent + { + Match = match + } + }; + + var updatePacket = new Packet + { + Event = @event + }; + + await Server.BroadcastToAllClients(updatePacket); + + if (MatchInfoUpdated != null) await MatchInfoUpdated.Invoke(match); + } + + public async Task DeleteMatch(Match match) + { + lock (Server.State.Matches) + { + var matchToRemove = Server.State.Matches.FirstOrDefault(x => x.MatchEquals(match)); + Server.State.Matches.Remove(matchToRemove); + } + + var @event = new Event + { + match_deleted_event = new Event.MatchDeletedEvent + { + Match = match + } + }; + await Server.BroadcastToAllClients(new Packet + { + Event = @event + }); + + if (MatchDeleted != null) await MatchDeleted.Invoke(match); + } + #endregion EventManagement + } +} \ No newline at end of file diff --git a/TournamentAssistantCore/SystemServer.cs b/TournamentAssistantCore/SystemServer.cs index 63f055be..18c7224f 100644 --- a/TournamentAssistantCore/SystemServer.cs +++ b/TournamentAssistantCore/SystemServer.cs @@ -26,13 +26,6 @@ public class SystemServer : INotifyPropertyChanged { Server server; - public event Func UserConnected; - public event Func UserDisconnected; - public event Func UserInfoUpdated; - public event Func MatchInfoUpdated; - public event Func MatchCreated; - public event Func MatchDeleted; - public event Func PlayerFinishedSong; public event Func AckReceived; @@ -57,6 +50,8 @@ public State State public User Self { get; set; } + private StateManager StateManager { get; set; } + public QualifierBot QualifierBot { get; private set; } public Discord.Database.QualifierDatabaseContext Database { get; private set; } @@ -238,6 +233,8 @@ public async void Start() Database = service.DatabaseContext; } + StateManager = new StateManager(this); + //Translate Event and Songs from database to model format var events = Database.Events.Where(x => !x.Old); Func> getSongsForEvent = (string eventId) => @@ -432,10 +429,10 @@ private async Task Server_ClientDisconnected(ConnectedUser client) { Logger.Debug("Client Disconnected!"); - var user = State.Users.FirstOrDefault(x => x.Guid == client.id.ToString()); + var user = StateManager.GetUserById(client.id.ToString()); if (user != null) { - await RemoveUser(user).ConfigureAwait(false); + await StateManager.RemoveUser(user).ConfigureAwait(false); } } @@ -514,7 +511,7 @@ public async Task ForwardTo(Guid[] ids, Guid from, Packet packet) await server.Send(ids, new PacketWrapper(packet)); } - private async Task BroadcastToAllClients(Packet packet) + public async Task BroadcastToAllClients(Packet packet) { packet.From = Self.Guid; Logger.Debug($"Sending data: {LogPacket(packet)}"); @@ -522,175 +519,6 @@ private async Task BroadcastToAllClients(Packet packet) } #region EventManagement - - public async Task AddUser(User user) - { - lock (State) - { - State.Users.Add(user); - } - - NotifyPropertyChanged(nameof(State)); - - var @event = new Event - { - user_added_event = new Event.UserAddedEvent - { - User = user - } - }; - await BroadcastToAllClients(new Packet - { - Event = @event - }); - - if (UserConnected != null) await UserConnected.Invoke(user); - } - - public async Task UpdateUser(User user) - { - lock (State) - { - var userToReplace = State.Users.FirstOrDefault(x => x.UserEquals(user)); - State.Users.Remove(userToReplace); - State.Users.Add(user); - } - - NotifyPropertyChanged(nameof(State)); - - var @event = new Event - { - user_updated_event = new Event.UserUpdatedEvent - { - User = user - } - }; - await BroadcastToAllClients(new Packet - { - Event = @event - }); - - if (UserInfoUpdated != null) await UserInfoUpdated.Invoke(user); - } - - public async Task RemoveUser(User user) - { - User userToRemove; - lock (State) - { - userToRemove = State.Users.FirstOrDefault(x => x.UserEquals(user)); - if (userToRemove == null) - { - return; - } - State.Users.Remove(userToRemove); - } - NotifyPropertyChanged(nameof(State)); - - var @event = new Event - { - user_left_event = new Event.UserLeftEvent - { - User = user - } - }; - - await BroadcastToAllClients(new Packet - { - Event = @event - }); - - for (int i = 0; i < State.Matches.Count; i++) - { - var m = State.Matches[i]; - if (m.AssociatedUsers.Contains(userToRemove.Guid)) - { - m.AssociatedUsers.RemoveAll((x) => x == userToRemove.Guid); - await UpdateMatch(m).ConfigureAwait(false); - } - } - - if (UserDisconnected != null) await UserDisconnected.Invoke(user); - } - - public async Task CreateMatch(Match match) - { - lock (State) - { - State.Matches.Add(match); - } - - NotifyPropertyChanged(nameof(State)); - - var @event = new Event - { - match_created_event = new Event.MatchCreatedEvent - { - Match = match - } - }; - await BroadcastToAllClients(new Packet - { - Event = @event - }); - - if (MatchCreated != null) await MatchCreated.Invoke(match); - } - - public async Task UpdateMatch(Match match) - { - lock (State) - { - var matchToReplace = State.Matches.FirstOrDefault(x => x.MatchEquals(match)); - State.Matches.Remove(matchToReplace); - State.Matches.Add(match); - } - - NotifyPropertyChanged(nameof(State)); - - var @event = new Event - { - match_updated_event = new Event.MatchUpdatedEvent - { - Match = match - } - }; - - var updatePacket = new Packet - { - Event = @event - }; - - await BroadcastToAllClients(updatePacket); - - if (MatchInfoUpdated != null) await MatchInfoUpdated.Invoke(match); - } - - public async Task DeleteMatch(Match match) - { - lock (State) - { - var matchToRemove = State.Matches.FirstOrDefault(x => x.MatchEquals(match)); - State.Matches.Remove(matchToRemove); - } - - NotifyPropertyChanged(nameof(State)); - - var @event = new Event - { - match_deleted_event = new Event.MatchDeletedEvent - { - Match = match - } - }; - await BroadcastToAllClients(new Packet - { - Event = @event - }); - - if (MatchDeleted != null) await MatchDeleted.Invoke(match); - } - public async Task SendCreateQualifierEvent(CoreServer host, QualifierEvent qualifierEvent) { if (host.CoreServerEquals(ServerSelf)) @@ -1199,7 +1027,7 @@ private async Task Server_PacketReceived(ConnectedUser user, Packet packet) else if (string.IsNullOrWhiteSpace(settings.Password) || connect.Password == settings.Password) { connect.User.Guid = user.id.ToString(); - await AddUser(connect.User); + await StateManager.AddUser(connect.User); //Give the newly connected player their Self and State await Send(user.id, new Packet @@ -1310,22 +1138,22 @@ await ForwardTo(forwardingPacket.ForwardToes.Select(x => Guid.Parse(x)).ToArray( switch (@event.ChangedObjectCase) { case Event.ChangedObjectOneofCase.match_created_event: - await CreateMatch(@event.match_created_event.Match); + await StateManager.CreateMatch(@event.match_created_event.Match); break; case Event.ChangedObjectOneofCase.match_updated_event: - await UpdateMatch(@event.match_updated_event.Match); + await StateManager.UpdateMatch(@event.match_updated_event.Match); break; case Event.ChangedObjectOneofCase.match_deleted_event: - await DeleteMatch(@event.match_deleted_event.Match); + await StateManager.DeleteMatch(@event.match_deleted_event.Match); break; case Event.ChangedObjectOneofCase.user_added_event: - await AddUser(@event.user_added_event.User); + await StateManager.AddUser(@event.user_added_event.User); break; case Event.ChangedObjectOneofCase.user_updated_event: - await UpdateUser(@event.user_updated_event.User); + await StateManager.UpdateUser(@event.user_updated_event.User); break; case Event.ChangedObjectOneofCase.user_left_event: - await RemoveUser(@event.user_left_event.User); + await StateManager.RemoveUser(@event.user_left_event.User); break; case Event.ChangedObjectOneofCase.qualifier_created_event: var createResponse = await CreateQualifierEvent(@event.qualifier_created_event.Event); diff --git a/TournamentAssistantProtos b/TournamentAssistantProtos index 5d0eba23..a99348ff 160000 --- a/TournamentAssistantProtos +++ b/TournamentAssistantProtos @@ -1 +1 @@ -Subproject commit 5d0eba234584c903e43894500b2f82842929edb9 +Subproject commit a99348ff6309de6f7a35dd623928d6e2fc463e05 diff --git a/TournamentAssistantShared/Constants.cs b/TournamentAssistantShared/Constants.cs index 605d4d2f..a25a6590 100644 --- a/TournamentAssistantShared/Constants.cs +++ b/TournamentAssistantShared/Constants.cs @@ -8,8 +8,8 @@ namespace TournamentAssistantShared public static class Constants { public const string NAME = "TournamentAssistant"; - public const string VERSION = "0.7.4"; - public const int VERSION_CODE = 074; + public const string VERSION = "0.7.9"; + public const int VERSION_CODE = 079; public const string MASTER_SERVER = "tournamentassistant.net"; public const string Changelog = "0.0.1: Begin assembling UI for coordinator panels\n" + @@ -64,7 +64,9 @@ public static class Constants "0.7.0: Some server synchronization fixes, for players and users that means more stability\n" + "0.7.3: Update for 1.29.1\n" + "0.7.4: Score update fix\n" + - "0.7.5: Add ability for players to select Pro Mode"; + "0.7.5: Add ability for players to select Pro Mode\n" + + "0.7.8: Added song end time to results\n" + + "0.7.9: Added bad cuts to results"; public enum BeatmapDifficulty { diff --git a/TournamentAssistantUI/Misc/MockClient.cs b/TournamentAssistantUI/Misc/MockClient.cs index f8ef71ab..035c3cc9 100644 --- a/TournamentAssistantUI/Misc/MockClient.cs +++ b/TournamentAssistantUI/Misc/MockClient.cs @@ -34,7 +34,7 @@ public class MockClient : SystemClient private static readonly Random random = new(); - public MockClient(string endpoint, int port, string username, string userId = "0") : base(endpoint, port, username, User.ClientTypes.Player, userId) + public MockClient(string endpoint, int port, string username, string userId = "0", string password = null) : base(endpoint, port, username, User.ClientTypes.Player, userId, password) { LoadedSong += MockClient_LoadedSong; PlaySong += MockClient_PlaySong; diff --git a/TournamentAssistantUI/TournamentAssistantUI.csproj b/TournamentAssistantUI/TournamentAssistantUI.csproj index f67faaf7..54d2c921 100644 --- a/TournamentAssistantUI/TournamentAssistantUI.csproj +++ b/TournamentAssistantUI/TournamentAssistantUI.csproj @@ -81,8 +81,9 @@ ..\packages\MessagingToolkit.Barcode.1.7.0.2\lib\net40\WPF\Any CPU\MessagingToolkit.Barcode.dll - - ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + ..\packages/Microsoft.Bcl.AsyncInterfaces.8.0.0/lib/net462/Microsoft.Bcl.AsyncInterfaces.dll + True ..\packages\Microsoft.Bcl.HashCode.1.1.0\lib\net461\Microsoft.Bcl.HashCode.dll @@ -257,8 +258,9 @@ True True - - ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + ..\packages/System.Memory.4.5.5/lib/net461/System.Memory.dll + True ..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll @@ -284,8 +286,9 @@ True True - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages/System.Runtime.CompilerServices.Unsafe.6.0.0/lib/net461/System.Runtime.CompilerServices.Unsafe.dll + True ..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll @@ -323,11 +326,13 @@ True - - ..\packages\System.Text.Encodings.Web.4.7.1\lib\net461\System.Text.Encodings.Web.dll + + ..\packages/System.Text.Encodings.Web.8.0.0/lib/net462/System.Text.Encodings.Web.dll + True - - ..\packages\System.Text.Json.4.7.2\lib\net461\System.Text.Json.dll + + ..\packages/System.Text.Json.8.0.4/lib/net462/System.Text.Json.dll + True ..\packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll diff --git a/TournamentAssistantUI/UI/MatchPage.xaml.cs b/TournamentAssistantUI/UI/MatchPage.xaml.cs index 68cdbf4e..3e3d868b 100644 --- a/TournamentAssistantUI/UI/MatchPage.xaml.cs +++ b/TournamentAssistantUI/UI/MatchPage.xaml.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows.Controls; @@ -17,7 +16,6 @@ using TournamentAssistantShared.BeatSaver; using TournamentAssistantShared.Models; using TournamentAssistantShared.Models.Packets; -using TournamentAssistantShared.Sockets; using TournamentAssistantShared.Utilities; using TournamentAssistantUI.Misc; using TournamentAssistantUI.UI.Forms; @@ -91,6 +89,7 @@ public bool SongLoading } private List _levelCompletionResults = new(); + private Dictionary _latestRealtimeScores = new(); public event Action AllPlayersFinishedSong; public MainPage MainPage { get; set; } @@ -145,6 +144,8 @@ public MatchPage(Match match, MainPage mainPage) //If player info is updated (ie: download state) we need to know it MainPage.Client.UserInfoUpdated += Connection_UserInfoUpdated; + MainPage.Client.RealtimeScoreReceived += Client_RealtimeScoreReceived; + //Let's get notified when a player finishes a song MainPage.Client.PlayerFinishedSong += Connection_PlayerFinishedSong; @@ -204,7 +205,7 @@ private void MatchPage_AllPlayersFinishedSong() { await DialogHost.Show(new GameOverDialogTeams(_levelCompletionResults), "RootDialog"); } - else await DialogHost.Show(new GameOverDialog(_levelCompletionResults), "RootDialog"); + else await DialogHost.Show(new GameOverDialog(_levelCompletionResults, _latestRealtimeScores), "RootDialog"); }); } @@ -244,6 +245,16 @@ private Task Connection_UserInfoUpdated(User player) return Task.CompletedTask; } + private Task Client_RealtimeScoreReceived(RealtimeScore score) + { + //If the updated player is part of our match + if (Match.AssociatedUsers.Contains(score.UserGuid)) + { + _latestRealtimeScores[score.UserGuid] = score; + } + return Task.CompletedTask; + } + private async Task Connection_MatchInfoUpdated(Match updatedMatch) { if (!updatedMatch.MatchEquals(Match)) @@ -276,8 +287,7 @@ await Dispatcher.InvokeAsync(() => private void UpdateTeamsGrid(Match match) { - var playersInMatch = match.AssociatedUsers.Where(x => MainPage.Client.GetUserByGuid(x)?.ClientType == User.ClientTypes.Player).Select(MainPage.Client.GetUserByGuid); - var teamsInMatch = playersInMatch.Select(x => x.Team?.Id).Where(x => x != null).Distinct().Select(MainPage.Client.GetTeamByGuid); + var teamsInMatch = GetPlayersInMatch().Select(x => x.Team?.Id).Where(x => x != null).Distinct().Select(MainPage.Client.GetTeamByGuid); Dispatcher.Invoke(() => { @@ -574,8 +584,7 @@ private async Task SetUpAndPlaySong(bool useSync = false) { if (useSync) { - var playersInMatch = Match.AssociatedUsers.Where(x => MainPage.Client.GetUserByGuid(x).ClientType == User.ClientTypes.Player).Select(MainPage.Client.GetUserByGuid); - var teamsInMatch = playersInMatch.Select(x => x.Team?.Id).Where(x => x != null).Distinct().Select(MainPage.Client.GetTeamByGuid); + var teamsInMatch = GetPlayersInMatch().Select(x => x.Team?.Id).Where(x => x != null).Distinct().Select(MainPage.Client.GetTeamByGuid); _checkedTeams = teamsInMatch.Where(x => TeamNameIsCheckedInGrid(x.Name)).ToList(); } diff --git a/TournamentAssistantUI/UI/MockPage.xaml b/TournamentAssistantUI/UI/MockPage.xaml index 833c2fdb..3626c54b 100644 --- a/TournamentAssistantUI/UI/MockPage.xaml +++ b/TournamentAssistantUI/UI/MockPage.xaml @@ -20,6 +20,7 @@ + \ No newline at end of file diff --git a/TournamentAssistantUI/UI/UserControls/GameOverDialog.xaml.cs b/TournamentAssistantUI/UI/UserControls/GameOverDialog.xaml.cs index b959a0a3..dfe1dbe0 100644 --- a/TournamentAssistantUI/UI/UserControls/GameOverDialog.xaml.cs +++ b/TournamentAssistantUI/UI/UserControls/GameOverDialog.xaml.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Windows.Controls; using System.Windows; +using TournamentAssistantShared.Models; +using MessagingToolkit.Barcode; namespace TournamentAssistantUI.UI.UserControls { @@ -13,23 +15,35 @@ public partial class GameOverDialog : UserControl { public class SongFinishedWithDistanceFromFirstPlayer : Push.SongFinished { + public int NonGoodCuts { get; set; } public int Distance { get; set; } } public List Results { get; set; } + private Dictionary latestRealtimeScores { get; set; } - public GameOverDialog(List results) + public GameOverDialog(List results, Dictionary latestScores) { + latestRealtimeScores = latestScores ?? new Dictionary(); + var orderedResults = results.OrderByDescending(x => x.Score); var firstPlace = orderedResults.First(); - Results = orderedResults.Select(x => new SongFinishedWithDistanceFromFirstPlayer - { - Beatmap = x.Beatmap, - Player = x.Player, - Score = x.Score, - Type = x.Type, - Distance = x.Score - firstPlace.Score, + Results = orderedResults.Select(x => { + // latestRealtimeScores.TryGetValue(x.Player.Guid, out var lastRealtimeScore); + return new SongFinishedWithDistanceFromFirstPlayer + { + Beatmap = x.Beatmap, + Player = x.Player, + Score = x.Score, + Type = x.Type, + Distance = x.Score - firstPlace.Score, + Misses = x.Misses, + BadCuts = x.BadCuts, + GoodCuts = x.GoodCuts, + NonGoodCuts = x.Misses + x.BadCuts, + EndTime = x.EndTime + }; }).ToList(); DataContext = this; @@ -42,9 +56,35 @@ private void Copy_Click(object _, RoutedEventArgs __) var copyToClipboard = "RESULTS:\n"; var index = 1; - foreach (var result in Results) copyToClipboard += $"{index++}: {result.Player.Name} - {result.Score}\n"; + foreach (var result in Results) + { + copyToClipboard += $"## {index++}: {result.Player.Name}\n"; + copyToClipboard += $" - Score: {result.Score}\n"; + copyToClipboard += $" - Misses: {result.Misses}\n"; + copyToClipboard += $" - Bad Cuts: {result.BadCuts}\n"; + copyToClipboard += $" - Good Cuts: {result.GoodCuts}\n"; + copyToClipboard += $" - Non-Good Cuts: {result.NonGoodCuts}\n\n"; + } Clipboard.SetText(copyToClipboard); } + + private void SortByMisses_Checked(object sender, RoutedEventArgs e) + { + Dispatcher.Invoke(() => + { + Results = Results.OrderByDescending(x => x.Misses).ToList(); + PlayerListBox.ItemsSource = Results; + }); + } + + private void SortByMissesCheckbox_Unchecked(object sender, RoutedEventArgs e) + { + Dispatcher.Invoke(() => + { + Results = Results.OrderByDescending(x => x.Score).ToList(); + PlayerListBox.ItemsSource = Results; + }); + } } } diff --git a/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml b/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml index 457a2469..e6e3c3c4 100644 --- a/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml +++ b/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml @@ -35,6 +35,10 @@ + + + + diff --git a/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml.cs b/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml.cs index a9c7e804..a3fdda85 100644 --- a/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml.cs +++ b/TournamentAssistantUI/UI/UserControls/GameOverDialogTeams.xaml.cs @@ -15,15 +15,19 @@ public partial class GameOverDialogTeams : UserControl public class TeamResult { public Team Team { get; set; } - public List<(User, int)> Players { get; set; } + public List<(User, Push.SongFinished)> Players { get; set; } public int TotalScore { get; set; } = 0; + public int TotalMisses { get;set; } = 0; + public int TotalBadCuts { get; set; } = 0; + public int TotalGoodCuts { get; set; } = 0; + public int TotalNonGoodCuts { get; set; } = 0; public string IndividualScores { get { var rankIndex = 1; var totalScoreText = string.Empty; - Players.OrderByDescending(x => x.Item2).ToList().ForEach(x => totalScoreText += $"{rankIndex++}: {x.Item1.Name} - {x.Item2}\n"); + Players.OrderByDescending(x => x.Item2).ToList().ForEach(x => totalScoreText += $"{rankIndex++}: {x.Item1.Name} - {x.Item2.Score}\n"); return totalScoreText; } } @@ -45,12 +49,17 @@ public GameOverDialogTeams(List results) teamResult = new TeamResult() { Team = x.Player.Team, - Players = new List<(User, int)>() + Players = new List<(User, Push.SongFinished)>() }; TeamResults.Add(teamResult); } - teamResult.Players.Add((x.Player, x.Score)); + teamResult.Players.Add((x.Player, x)); + teamResult.TotalScore += x.Score; + teamResult.TotalMisses += x.Misses; + teamResult.TotalBadCuts += x.BadCuts; + teamResult.TotalGoodCuts += x.GoodCuts; + teamResult.TotalNonGoodCuts += x.BadCuts + x.Misses; teamResult.TotalScore += x.Score; }); @@ -63,17 +72,17 @@ public GameOverDialogTeams(List results) private void Copy_Click(object _, RoutedEventArgs __) { - var copyToClipboard = "RESULTS:\n"; + var copyToClipboard = "# RESULTS:\n"; var index = 1; foreach (var result in TeamResults) { - copyToClipboard += $"{index}: {result.Team.Name} - {result.TotalScore}\n"; - foreach (var player in result.Players) - { - copyToClipboard += $"\t\t{player.Item1.Name} - {player.Item2}\n"; - } - copyToClipboard += "\n"; + copyToClipboard += $"## {index}: {result.Team.Name}\n"; + copyToClipboard += $" - Score: {result.TotalScore}\n"; + copyToClipboard += $" - Misses: {result.TotalMisses}\n"; + copyToClipboard += $" - Bad Cuts: {result.TotalBadCuts}\n"; + copyToClipboard += $" - Good Cuts: {result.TotalGoodCuts}\n"; + copyToClipboard += $" - Non-Good Cuts: {result.TotalNonGoodCuts}\n\n"; } Clipboard.SetText(copyToClipboard); diff --git a/TournamentAssistantUI/packages.config b/TournamentAssistantUI/packages.config index 023a15c7..0bffbae1 100644 --- a/TournamentAssistantUI/packages.config +++ b/TournamentAssistantUI/packages.config @@ -4,7 +4,7 @@ - + @@ -61,7 +61,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -84,8 +84,8 @@ - - + + diff --git a/vagueNotes.txt b/vagueNotes.txt new file mode 100644 index 00000000..f3850472 --- /dev/null +++ b/vagueNotes.txt @@ -0,0 +1,75 @@ +Vague notes: + +Better heartbeat stuff + - Looks like we don't have good handling for when the dns doesn't resolve to the correct ip + +We can leverage the auth plugin's stack trace verification / calling assembly signature verification +to more confidently assign userId and username as well as discord info for Players + +We should take extra care that final scores are signed w/stack trace + +Make the default T actually default and not just filler + +Might need to merge the Splash screens (If this was on the TAUI side, it's done) + +AuthorizationRequestedFromServer... Should that be a Request? later moon: I don't think so? + +I've disabled modals for now, until they can be revisited + +Fix antifail autorestart bug + +Add toggles for showing quals / tournaments + +Add popup on end qual for downloading scores + +WEIGHTING: Get score percentage, take player #1's score, divide percentage by 100, multiply rest of scores by result + + +TIPS, NOT TODO: + +Allow Transparency in OBS keeps qr codes (or color bars) from appearing + +AuthorizedUsers are not in state, so they don't update automatically + +Keep an eye on image size, and how that affects Join Response time + +Do not- DO NOT use await after getting a database object and before changing and saving it. In console apps, await +might resume on a different thread + +!!! - CURRENT POTENTIAL CRASH - !!! + IE: even if UpdateMatch() properly wraps match locking, + what's wrapping match.AssociatedUsers? There's probably more like it out there + + + + +Notes on generating new .pfx when necessary: + +FRONTEND: +1. Set up port forwarding and all that for 80,443 +2. `certbot certonly --standalone --key-type rsa` +3. `openssl pkcs12 -export -out certificate.pfx -inkey privateKey.pem -in certificate.pem` + +PLAYER: + +How to check certificate expiration date: + +1. `certutil -dump certificate.pfx` +OR +1. `openssl pkcs12 -in yourfile.pfx -passin pass:exportpassword -nokeys | openssl x509 -noout -dates` + +Notes on how to publish TAAuth: + +1. Build with ILRepack, without EAZFuscator +2. Find EAZFuscator executable in nuget package + (C:\Users\Moon\.nuget\packages\gapotchenko.eazfuscator.net\2023.1.427\tools) +3. Use command-line tool to obfuscate the dll + If it's expired, EAZFuscator stores its license info in HKCU\Identities\{0FE6CF32-23D2-4166-B147-20D4E86A8523}, so delete it + If there's a Microsoft.Net.SDK error, install .NET Build tools in any VS installations where it's missing +4. Use the trial remover on the resulting dll + + + +Testing notes: +4. Results didn't appear once +5. Token expiry during match causes havoc \ No newline at end of file