diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index 7a68182c..9a6134aa 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -72,6 +72,7 @@ UseExplicitType UseExplicitType UseExplicitType + DLC LBP MM NAT diff --git a/ProjectLighthouse/Controllers/MatchController.cs b/ProjectLighthouse/Controllers/MatchController.cs index 4d1fa398..07483f14 100644 --- a/ProjectLighthouse/Controllers/MatchController.cs +++ b/ProjectLighthouse/Controllers/MatchController.cs @@ -71,33 +71,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers #endregion - #region Process match data - - if (matchData is UpdateMyPlayerData) MatchHelper.SetUserLocation(user.UserId, token.UserLocation); - - if (matchData is FindBestRoom && MatchHelper.UserLocations.Count > 1) - { - foreach ((int id, string? location) in MatchHelper.UserLocations) - { - if (id == user.UserId) continue; - if (location == null) continue; - if (MatchHelper.DidUserRecentlyDiveInWith(user.UserId, id)) continue; - - User? otherUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id); - if (otherUser == null) continue; - - FindBestRoomResponse response = MatchHelper.FindBestRoomResponse(user.Username, otherUser.Username, token.UserLocation, location); - - string serialized = JsonSerializer.Serialize(response, typeof(FindBestRoomResponse)); - - MatchHelper.AddUserRecentlyDivedIn(user.UserId, id); - - return new ObjectResult($"[{{\"StatusCode\":200}},{serialized}]"); - } - } - - #endregion - #region Update LastMatch LastMatch? lastMatch = await this.database.LastMatches.Where(l => l.UserId == user.UserId).FirstOrDefaultAsync(); @@ -119,6 +92,27 @@ namespace LBPUnion.ProjectLighthouse.Controllers #endregion + #region Process match data + + if (matchData is UpdateMyPlayerData) MatchHelper.SetUserLocation(user.UserId, token.UserLocation); + + if (matchData is FindBestRoom && MatchHelper.UserLocations.Count > 1) + { + FindBestRoomResponse? response = RoomHelper.FindBestRoom(user, token.UserLocation); + + if (response == null) return this.BadRequest(); + + string serialized = JsonSerializer.Serialize(response, typeof(FindBestRoomResponse)); + foreach (Player player in response.Players) + { + MatchHelper.AddUserRecentlyDivedIn(user.UserId, player.User.UserId); + } + + return new ObjectResult($"[{{\"StatusCode\":200}},{serialized}]"); + } + + #endregion + return this.Ok("[{\"StatusCode\":200}]"); } } diff --git a/ProjectLighthouse/Helpers/MatchHelper.cs b/ProjectLighthouse/Helpers/MatchHelper.cs index b3017e2a..30f07616 100644 --- a/ProjectLighthouse/Helpers/MatchHelper.cs +++ b/ProjectLighthouse/Helpers/MatchHelper.cs @@ -39,37 +39,6 @@ namespace LBPUnion.ProjectLighthouse.Helpers return recentlyDivedIn.Contains(otherUserId); } - public static FindBestRoomResponse FindBestRoomResponse(string username, string otherUsername, string location, string otherLocation) - => new() - { - Players = new List - { - new() - { - MatchingRes = 0, - PlayerId = otherUsername, - }, - new() - { - MatchingRes = 1, - PlayerId = username, - }, - }, - Locations = new List - { - location, - otherLocation, - }, - Slots = new List> - { - new() - { - 5, - 0, - }, - }, - }; - public static IMatchData? Deserialize(string data) { string matchType = ""; diff --git a/ProjectLighthouse/Helpers/RoomHelper.cs b/ProjectLighthouse/Helpers/RoomHelper.cs new file mode 100644 index 00000000..81647450 --- /dev/null +++ b/ProjectLighthouse/Helpers/RoomHelper.cs @@ -0,0 +1,84 @@ +#nullable enable +using System.Collections.Generic; +using System.Linq; +using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.Types.Match; + +namespace LBPUnion.ProjectLighthouse.Helpers +{ + public class RoomHelper + { + public static readonly List Rooms = new(); + + public static FindBestRoomResponse? FindBestRoom(User user, string location) + { + bool anyRoomsLookingForPlayers = Rooms.Any(r => r.IsLookingForPlayers); + + // Look for rooms looking for players before moving on to rooms that are idle. + foreach (Room room in Rooms.Where(r => !anyRoomsLookingForPlayers || r.IsLookingForPlayers)) + { + if (MatchHelper.DidUserRecentlyDiveInWith(user.UserId, room.Players[0].UserId)) continue; + + Dictionary relevantUserLocations = new(); + + // Determine if all players in a room have UserLocations stored, also store the relevant userlocations while we're at it + bool allPlayersHaveLocations = room.Players.All + ( + p => + { + bool gotValue = MatchHelper.UserLocations.TryGetValue(p.UserId, out string? value) && value != null; + + if (gotValue) relevantUserLocations.Add(p.UserId, value!); + return gotValue; + } + ); + + // If we don't have all locations then the game won't know how to communicate. Thus, it's not a valid room. + if (!allPlayersHaveLocations) continue; + + // If we got here then it should be a valid room. + + FindBestRoomResponse response = new(); + + response.Players = new List(); + foreach (User player in room.Players) + { + response.Players.Add + ( + new Player + { + MatchingRes = 0, + User = player, + } + ); + + response.Locations.Add(relevantUserLocations.GetValueOrDefault(player.UserId)); // Already validated to exist + } + + response.Players.Add + ( + new Player + { + MatchingRes = 1, + User = user, + } + ); + + response.Locations.Add(location); + + response.Slots = new List> + { + new() + { + (int)room.Slot.SlotType, + room.Slot.SlotId, + }, + }; + + return response; + } + + return null; + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Match/Player.cs b/ProjectLighthouse/Types/Match/Player.cs index ad2140fa..95c18ec6 100644 --- a/ProjectLighthouse/Types/Match/Player.cs +++ b/ProjectLighthouse/Types/Match/Player.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; namespace LBPUnion.ProjectLighthouse.Types.Match @@ -6,7 +7,11 @@ namespace LBPUnion.ProjectLighthouse.Types.Match [Serializable] public class Player { - public string PlayerId { get; set; } + [JsonIgnore] + public User User { get; set; } + + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public string PlayerId => User.Username; [JsonPropertyName("matching_res")] public int MatchingRes { get; set; } diff --git a/ProjectLighthouse/Types/Match/Room.cs b/ProjectLighthouse/Types/Match/Room.cs new file mode 100644 index 00000000..466ecc4a --- /dev/null +++ b/ProjectLighthouse/Types/Match/Room.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using LBPUnion.ProjectLighthouse.Types.Levels; + +namespace LBPUnion.ProjectLighthouse.Types.Match +{ + public class Room + { + public List Players; + public RoomState State; + public RoomSlot Slot; + + public bool IsInPod => Slot.SlotType == SlotType.Pod; + public bool IsLookingForPlayers => this.State == RoomState.DivingIntoLevel || this.State == RoomState.DivingInWaiting; + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Match/RoomSlot.cs b/ProjectLighthouse/Types/Match/RoomSlot.cs new file mode 100644 index 00000000..438fa763 --- /dev/null +++ b/ProjectLighthouse/Types/Match/RoomSlot.cs @@ -0,0 +1,10 @@ +using LBPUnion.ProjectLighthouse.Types.Levels; + +namespace LBPUnion.ProjectLighthouse.Types.Match +{ + public class RoomSlot + { + public SlotType SlotType; + public int SlotId; + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Match/RoomState.cs b/ProjectLighthouse/Types/Match/RoomState.cs index 2cfc28e2..f3d31406 100644 --- a/ProjectLighthouse/Types/Match/RoomState.cs +++ b/ProjectLighthouse/Types/Match/RoomState.cs @@ -2,10 +2,29 @@ namespace LBPUnion.ProjectLighthouse.Types.Match { public enum RoomState { + /// + /// The room isn't doing anything in particular. + /// Idle = 0, - LookingForPlayersForLevel = 1, + + /// + /// The room is looking to join an existing room playing a specific slot. + /// + DivingIntoLevel = 1, + + /// + /// ??? + /// Unknown = 2, + + /// + /// The room is looking for other rooms to join. + /// DivingIn = 3, + + /// + /// The room is waiting for players to join their room. + /// DivingInWaiting = 4, } } \ No newline at end of file