mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-07-19 03:31:29 +00:00
Fix level ordering in busiest slots
This commit is contained in:
parent
15a3cbea42
commit
91e792aea0
3 changed files with 163 additions and 22 deletions
|
@ -351,31 +351,30 @@ public class SlotsController : ControllerBase
|
||||||
|
|
||||||
PaginationData pageData = this.Request.GetPaginationData();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
Dictionary<int, int> playersBySlotId = new();
|
List<int> busiestSlots = RoomHelper.Rooms.Where(r => r.Slot.SlotType == SlotType.User)
|
||||||
|
.GroupBy(r => r.Slot.SlotId)
|
||||||
|
.OrderByDescending(kvp => kvp.Count())
|
||||||
|
.Select(kvp => kvp.Key)
|
||||||
|
.AsQueryable()
|
||||||
|
.ApplyPagination(pageData)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
foreach (Room room in RoomHelper.Rooms)
|
pageData.TotalElements = busiestSlots.Count;
|
||||||
|
|
||||||
|
List<SlotBase> slots = new();
|
||||||
|
|
||||||
|
Expression<Func<SlotEntity, bool>> filterQuery = this.FilterFromRequest(token).Build();
|
||||||
|
|
||||||
|
foreach (int slotId in busiestSlots)
|
||||||
{
|
{
|
||||||
// TODO: support developer slotTypes?
|
SlotBase? slot = await this.database.Slots.Where(s => s.SlotId == slotId)
|
||||||
if (room.Slot.SlotType != SlotType.User) continue;
|
.Where(filterQuery)
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
if (!playersBySlotId.TryGetValue(room.Slot.SlotId, out int playerCount))
|
.FirstOrDefaultAsync();
|
||||||
playersBySlotId.Add(room.Slot.SlotId, 0);
|
if (slot == null) continue;
|
||||||
|
slots.Add(slot);
|
||||||
playerCount += room.PlayerIds.Count;
|
|
||||||
|
|
||||||
playersBySlotId.Remove(room.Slot.SlotId);
|
|
||||||
playersBySlotId.Add(room.Slot.SlotId, playerCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pageData.TotalElements = playersBySlotId.Count;
|
|
||||||
|
|
||||||
List<int> orderedPlayersBySlotId = playersBySlotId.OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key).ToList();
|
|
||||||
|
|
||||||
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
|
||||||
queryBuilder.AddFilter(0, new SlotIdFilter(orderedPlayersBySlotId));
|
|
||||||
|
|
||||||
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, new SlotSortBuilder<SlotEntity>());
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, pageData));
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,13 +1,16 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||||
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -377,4 +380,139 @@ public class SlotControllerTests
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region BusiestLevels
|
||||||
|
|
||||||
|
// Rather than trying to mock a singleton
|
||||||
|
// we just make the unit tests take turns
|
||||||
|
private static readonly Mutex roomMutex = new(false);
|
||||||
|
|
||||||
|
private static async Task AddRoom(int slotId, SlotType type, params int[] playerIds)
|
||||||
|
{
|
||||||
|
await RoomHelper.Rooms.AddAsync(new Room
|
||||||
|
{
|
||||||
|
PlayerIds = new List<int>(playerIds),
|
||||||
|
Slot = new RoomSlot
|
||||||
|
{
|
||||||
|
SlotId = slotId,
|
||||||
|
SlotType = type,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BusiestLevels_ShouldReturnSlots_OrderedByRoomCount()
|
||||||
|
{
|
||||||
|
roomMutex.WaitOne();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
new List<SlotEntity>
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SlotId = 1,
|
||||||
|
Type = SlotType.User,
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
Type = SlotType.User,
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SlotId = 3,
|
||||||
|
Type = SlotType.User,
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SlotId = 4,
|
||||||
|
Type = SlotType.Developer,
|
||||||
|
InternalSlotId = 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
SlotsController controller = new(db);
|
||||||
|
controller.SetupTestController();
|
||||||
|
|
||||||
|
await AddRoom(1, SlotType.User, 1);
|
||||||
|
await AddRoom(2, SlotType.User, 2);
|
||||||
|
await AddRoom(2, SlotType.User, 3);
|
||||||
|
await AddRoom(3, SlotType.User, 4);
|
||||||
|
await AddRoom(3, SlotType.User, 5);
|
||||||
|
await AddRoom(3, SlotType.User, 6);
|
||||||
|
|
||||||
|
await AddRoom(10, SlotType.Developer, 7);
|
||||||
|
|
||||||
|
IActionResult result = await controller.BusiestLevels();
|
||||||
|
GenericSlotResponse slotResponse = result.CastTo<OkObjectResult, GenericSlotResponse>();
|
||||||
|
Assert.Equal(3, slotResponse.Slots.Count);
|
||||||
|
Assert.IsType<GameUserSlot>(slotResponse.Slots[0]);
|
||||||
|
Assert.Equal(3, ((GameUserSlot)slotResponse.Slots[0]).SlotId);
|
||||||
|
Assert.IsType<GameUserSlot>(slotResponse.Slots[1]);
|
||||||
|
Assert.Equal(2, ((GameUserSlot)slotResponse.Slots[1]).SlotId);
|
||||||
|
Assert.IsType<GameUserSlot>(slotResponse.Slots[2]);
|
||||||
|
Assert.Equal(1, ((GameUserSlot)slotResponse.Slots[2]).SlotId);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
roomMutex.ReleaseMutex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BusiestLevels_ShouldNotIncludeDeveloperSlots()
|
||||||
|
{
|
||||||
|
roomMutex.WaitOne();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
new List<SlotEntity>
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SlotId = 4,
|
||||||
|
Type = SlotType.Developer,
|
||||||
|
InternalSlotId = 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
SlotsController controller = new(db);
|
||||||
|
controller.SetupTestController();
|
||||||
|
|
||||||
|
await AddRoom(10, SlotType.Developer, 1);
|
||||||
|
|
||||||
|
IActionResult result = await controller.BusiestLevels();
|
||||||
|
GenericSlotResponse slotResponse = result.CastTo<OkObjectResult, GenericSlotResponse>();
|
||||||
|
Assert.Empty(slotResponse.Slots);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
roomMutex.ReleaseMutex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BusiestLevels_ShouldNotIncludeInvalidSlots()
|
||||||
|
{
|
||||||
|
roomMutex.WaitOne();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase();
|
||||||
|
SlotsController controller = new(db);
|
||||||
|
controller.SetupTestController();
|
||||||
|
|
||||||
|
await AddRoom(1, SlotType.User, 1);
|
||||||
|
|
||||||
|
IActionResult result = await controller.BusiestLevels();
|
||||||
|
GenericSlotResponse slotResponse = result.CastTo<OkObjectResult, GenericSlotResponse>();
|
||||||
|
Assert.Empty(slotResponse.Slots);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
roomMutex.ReleaseMutex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
@ -53,6 +54,8 @@ public static class MockHelper
|
||||||
|
|
||||||
public static async Task<DatabaseContext> GetTestDatabase(IEnumerable<IList> sets, [CallerMemberName] string caller = "", [CallerLineNumber] int lineNum = 0)
|
public static async Task<DatabaseContext> GetTestDatabase(IEnumerable<IList> sets, [CallerMemberName] string caller = "", [CallerLineNumber] int lineNum = 0)
|
||||||
{
|
{
|
||||||
|
await RoomHelper.Rooms.RemoveAllAsync();
|
||||||
|
|
||||||
Dictionary<Type, IList> setDict = new();
|
Dictionary<Type, IList> setDict = new();
|
||||||
foreach (IList list in sets)
|
foreach (IList list in sets)
|
||||||
{
|
{
|
||||||
|
@ -77,7 +80,6 @@ public static class MockHelper
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DbContextOptions<DatabaseContext> options = new DbContextOptionsBuilder<DatabaseContext>()
|
DbContextOptions<DatabaseContext> options = new DbContextOptionsBuilder<DatabaseContext>()
|
||||||
.UseInMemoryDatabase($"{caller}_{lineNum}")
|
.UseInMemoryDatabase($"{caller}_{lineNum}")
|
||||||
.Options;
|
.Options;
|
||||||
|
@ -101,6 +103,8 @@ public static class MockHelper
|
||||||
[CallerMemberName] string caller = "", [CallerLineNumber] int lineNum = 0
|
[CallerMemberName] string caller = "", [CallerLineNumber] int lineNum = 0
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
await RoomHelper.Rooms.RemoveAllAsync();
|
||||||
|
|
||||||
users ??= new List<UserEntity>
|
users ??= new List<UserEntity>
|
||||||
{
|
{
|
||||||
GetUnitTestUser(),
|
GetUnitTestUser(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue