yikes,
This commit is contained in:
@@ -0,0 +1,2049 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Vanadium.Auth;
|
||||
using Vanadium.Classes;
|
||||
using Vanadium.Classes.DBs;
|
||||
using Vanadium.Classes.DBs.DBClasses;
|
||||
using static Vanadium.Classes.DBs.DBClasses.PlayerDBClasses;
|
||||
using static Vanadium.Classes.DBs.DBClasses.RoomDBClasses;
|
||||
using Vanadium.Classes.WebSocket;
|
||||
using Vanadium.Utils.NotiController;
|
||||
using Vanadium.Controllers;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Vanadium.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("/match")]
|
||||
public partial class MatchController : ControllerBase
|
||||
{
|
||||
private static readonly ConcurrentDictionary<long, (long RoomId, DateTime MatchmadeAt)> _authorizedRoomSessions = new();
|
||||
private static readonly ConcurrentDictionary<(long, long), (int Count, DateTime Window)> _inviteRateLimit = new();
|
||||
|
||||
private static readonly string PhotonChatAppId = "9c035c47-8725-43d4-8c53-ab45ed381511";
|
||||
|
||||
private static readonly Random _photonRng = new Random();
|
||||
|
||||
public static long EnsurePlayerDorm(FullPlayer player)
|
||||
{
|
||||
long dormRoomId = player.Player.PlayerExtra.DormRoomId;
|
||||
|
||||
if (dormRoomId > 0 && RoomDB.DoesPlayerDormExist(player.PlayerId))
|
||||
return dormRoomId;
|
||||
|
||||
var dormRoom = RoomDB.GetPlayerDormRoom(player.PlayerId);
|
||||
if (dormRoom != null)
|
||||
{
|
||||
dormRoomId = dormRoom.RoomId;
|
||||
}
|
||||
else
|
||||
{
|
||||
dormRoomId = RoomDB.CloneDormRoom(player.PlayerId);
|
||||
}
|
||||
|
||||
PlayerDB.UpdateDormRoomId(player.PlayerId, dormRoomId);
|
||||
player.Player.PlayerExtra.DormRoomId = dormRoomId;
|
||||
return dormRoomId;
|
||||
}
|
||||
|
||||
private static void AuthorizeRoomSession(long playerId, long roomId)
|
||||
{
|
||||
_authorizedRoomSessions[playerId] = (roomId, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
private static void ClearRoomSession(long playerId)
|
||||
{
|
||||
_authorizedRoomSessions.TryRemove(playerId, out _);
|
||||
}
|
||||
|
||||
private static bool IsRoomSessionAuthorized(long playerId, long roomId)
|
||||
{
|
||||
if (!_authorizedRoomSessions.TryGetValue(playerId, out var session))
|
||||
return false;
|
||||
return session.RoomId == roomId && (DateTime.UtcNow - session.MatchmadeAt).TotalHours < 12;
|
||||
}
|
||||
|
||||
private static void KickPlayer(long playerId)
|
||||
{
|
||||
}
|
||||
|
||||
private static bool IsBannedFromRoom(Room? room, long playerId)
|
||||
{
|
||||
return room?.Roles?.Any(r => r.AccountId == playerId && r.Role == Role.Banned) ?? false;
|
||||
}
|
||||
|
||||
[HttpGet("player")]
|
||||
public async Task<IActionResult> GetPlayerHeartbeatBulk([FromQuery] List<long> id)
|
||||
{
|
||||
var playerId = AuthStuff.GetPlayerId(Request);
|
||||
if (playerId == null)
|
||||
return Unauthorized("");
|
||||
|
||||
return Ok(PlayerDB.GetPlayerHeartbeatsBulk(id));
|
||||
}
|
||||
|
||||
[HttpPost("roominstance/{roomInstanceId}/reportjoinresult")]
|
||||
public async Task<IActionResult> ReportJoinResultForRoomInstanceId(ulong roomInstanceId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
long resolvedAccountId = player.PlayerId;
|
||||
long newLevel = player.Player.Level;
|
||||
long newXP = player.Player.XP;
|
||||
|
||||
_ = NotiController.SendEvent(resolvedAccountId, "PlayerProgressionXPUpdate", new
|
||||
{
|
||||
PlayerId = resolvedAccountId,
|
||||
Level = newLevel,
|
||||
XP = newXP
|
||||
});
|
||||
|
||||
_ = NotiController.SendEvent(resolvedAccountId, "PlayerProgressionLevelUpdate", new
|
||||
{
|
||||
PlayerId = resolvedAccountId,
|
||||
Level = newLevel,
|
||||
XP = newXP
|
||||
});
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("roominstance/{roomInstanceId}/markprivate")]
|
||||
public async Task<IActionResult> MarkRoomInstancePrivate(long roomInstanceId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
Sessions.MarkInstancePrivate(roomInstanceId);
|
||||
Sessions.FakeInstanceFull(roomInstanceId);
|
||||
|
||||
var playersInInstance = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
.ToList();
|
||||
|
||||
foreach (var fp in playersInInstance)
|
||||
{
|
||||
if (fp.Player?.PlayerExtra?.Heartbeat?.roomInstance == null) continue;
|
||||
fp.Player.PlayerExtra.Heartbeat.roomInstance.isPrivate = true;
|
||||
PlayerDB.Players.Update(fp);
|
||||
}
|
||||
|
||||
var outsiderIds = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.isOnline == true
|
||||
&& p.Player.PlayerExtra.Heartbeat.roomInstance?.roomInstanceId != roomInstanceId)
|
||||
.Select(p => p.PlayerId)
|
||||
.ToList();
|
||||
|
||||
foreach (var fp in playersInInstance)
|
||||
{
|
||||
if (fp.Player?.PlayerExtra?.Heartbeat == null) continue;
|
||||
|
||||
var hbJson = Newtonsoft.Json.JsonConvert.SerializeObject(new WebsocketEvents.Response
|
||||
{
|
||||
Id = NotificationsController.EventTypes.PresenceUpdate,
|
||||
Msg = fp.Player.PlayerExtra.Heartbeat
|
||||
});
|
||||
|
||||
await NotificationsController.SendToPlayer(fp.PlayerId, hbJson);
|
||||
await NotificationsController.SendToPlayers(outsiderIds, hbJson);
|
||||
}
|
||||
|
||||
return Ok(new StorefrontsDBClasses.SuccessResult());
|
||||
}
|
||||
|
||||
private static HashSet<long> RecRoomPlusCheckWhitelisgt()
|
||||
{
|
||||
var path = Path.Combine(Environment.CurrentDirectory, "Data", "APIS", "RRPlus.txt");
|
||||
if (!System.IO.File.Exists(path))
|
||||
return new HashSet<long>();
|
||||
|
||||
var ids = new HashSet<long>();
|
||||
foreach (var line in System.IO.File.ReadAllLines(path))
|
||||
{
|
||||
if (long.TryParse(line.Trim(), out var id))
|
||||
ids.Add(id);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
[HttpGet("rooms/requiring/developer")]
|
||||
public async Task<IActionResult> RoomsRequiringDeveloper()
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
return Ok(ServerConfig.Bracket);
|
||||
}
|
||||
|
||||
[HttpGet("rooms/requiring/rrplus")]
|
||||
public async Task<IActionResult> RoomsRequiringRRPlus()
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
return Ok(ServerConfig.Bracket);
|
||||
}
|
||||
|
||||
[HttpPut("player/statusvisibility")]
|
||||
public IActionResult setStatusVisibilityShit()
|
||||
{
|
||||
return Ok(new { success = true });
|
||||
}
|
||||
|
||||
[HttpPut("player/photonregionpings")]
|
||||
public IActionResult setPhotonRegionShit()
|
||||
{
|
||||
return Ok(new { success = true });
|
||||
}
|
||||
|
||||
[HttpGet("room/{roomId}/instances")] // ripped from other code only for reference? i only needed the response data
|
||||
public async Task<IActionResult> GetRoomInstances(long roomId)
|
||||
{
|
||||
var id = AuthStuff.GetPlayerId(Request);
|
||||
if (id == null) return Unauthorized("");
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
if (room == null) return NotFound("");
|
||||
|
||||
var currentPlayer = PlayerDB.GetCurrentPlayer((long)id);
|
||||
|
||||
bool isDeveloper = currentPlayer?.PlayerRoles?.Any(r =>
|
||||
r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
|
||||
bool hasRoomModRole = room.CreatorAccountId == (long)id || (room.Roles?.Any(r =>
|
||||
r.AccountId == (long)id &&
|
||||
(int)r.Role >= (int)Role.Moderator) ?? false);
|
||||
|
||||
if (!isDeveloper && !hasRoomModRole)
|
||||
return StatusCode(403, "Permission Denied");
|
||||
|
||||
var allPlayers = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance != null
|
||||
&& p.Player.PlayerExtra.Heartbeat.isOnline)
|
||||
.ToList();
|
||||
|
||||
var instanceGroups = allPlayers
|
||||
.Where(p => p.Player.PlayerExtra.Heartbeat.roomInstance.roomId == roomId)
|
||||
.GroupBy(p => p.Player.PlayerExtra.Heartbeat.roomInstance.roomInstanceId)
|
||||
.ToList();
|
||||
|
||||
if (!instanceGroups.Any())
|
||||
return Ok(Array.Empty<object>());
|
||||
|
||||
bool canViewAll = isDeveloper || room.CreatorAccountId == (long)id || (room.Roles?.Any(r =>
|
||||
r.AccountId == (long)id &&
|
||||
(int)r.Role >= (int)Role.Moderator) ?? false);
|
||||
|
||||
var result = instanceGroups
|
||||
.Where(g =>
|
||||
{
|
||||
var sample = g.First();
|
||||
var instance = sample.Player.PlayerExtra.Heartbeat.roomInstance;
|
||||
return canViewAll || instance.isPrivate != true;
|
||||
})
|
||||
.OrderByDescending(g => g.Count())
|
||||
.Select(g =>
|
||||
{
|
||||
var sample = g.First().Player.PlayerExtra.Heartbeat.roomInstance;
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
["RoomInstanceId"] = sample.roomInstanceId,
|
||||
["RoomId"] = roomId,
|
||||
["SubRoomId"] = sample.subRoomId,
|
||||
["IsFull"] = Sessions.IsInstanceActuallyFull(sample.roomInstanceId),
|
||||
["MaxCapacity"] = sample.maxCapacity,
|
||||
["IsPrivate"] = sample.isPrivate,
|
||||
["PlayerIds"] = g.Select(p => p.PlayerId).ToList()
|
||||
};
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("player/exclusivelogin")]
|
||||
public async Task<IActionResult> PlayerExclusiveLogin()
|
||||
{
|
||||
var id = AuthStuff.GetPlayerId(Request);
|
||||
if (id == null)
|
||||
return Unauthorized("");
|
||||
|
||||
await NotificationsController.SendPlayerOnline(id.Value, new MatchDBClasses.PlayerOnlineDTO() { SenderIsMyFavoriteFriend = true });
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("player/login")]
|
||||
public async Task<IActionResult> PlayerLogin()
|
||||
{
|
||||
var id = AuthStuff.GetPlayerId(Request);
|
||||
if (id != null)
|
||||
{
|
||||
ClearRoomSession(id.Value);
|
||||
PlayerDB.UpdateLastLoginAt(id.Value);
|
||||
PlayerDB.UpdatePlayerHeartbeat(id.Value, null, online: true);
|
||||
|
||||
var someRequiredSetings = new[]
|
||||
{
|
||||
("Recroom.AccountCreation.HasStarted", "True"),
|
||||
("Recroom.AccountCreation.HasChosenUsername", "False"),
|
||||
("Recroom.AccountCreation.HasCreatedPassword", "True"),
|
||||
("Recroom.AccountCreation.HasFinished", "False"),
|
||||
("TUTORIAL_COMPLETE_MASK", "77")
|
||||
};
|
||||
|
||||
var existingSettings = PlayerDB.GetPlayerSettings(id.Value);
|
||||
|
||||
foreach (var (key, value) in someRequiredSetings)
|
||||
{
|
||||
if (!existingSettings.Any(s => s.Key == key))
|
||||
PlayerDB.SetPlayerSetting(key, value, id.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("player/logout")]
|
||||
public async Task<IActionResult> PlayerLogout()
|
||||
{
|
||||
var id = AuthStuff.GetPlayerId(Request);
|
||||
if (id != null)
|
||||
{
|
||||
ClearRoomSession(id.Value);
|
||||
PlayerDB.UpdatePlayerHeartbeat(id.Value, null, online: false);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("player/heartbeat")]
|
||||
public async Task<IActionResult> PostPlayerHeartbeat()
|
||||
{
|
||||
var id = AuthStuff.GetPlayerId(Request);
|
||||
if (id == null)
|
||||
return Unauthorized("");
|
||||
|
||||
var playerLock = PlayerDB.GetPlayerLock(id.Value);
|
||||
await playerLock.WaitAsync();
|
||||
FullPlayer player;
|
||||
Heartbeat hb;
|
||||
try
|
||||
{
|
||||
player = PlayerDB.Players.FindById(id.Value);
|
||||
if (player?.Player?.PlayerExtra == null)
|
||||
return Unauthorized("");
|
||||
|
||||
hb = player.Player.PlayerExtra.Heartbeat ?? new Heartbeat();
|
||||
|
||||
if (hb.roomInstance != null)
|
||||
{
|
||||
long claimedRoomId = hb.roomInstance.roomId;
|
||||
|
||||
if (!IsRoomSessionAuthorized(id.Value, claimedRoomId))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
hb.playerId = id.Value;
|
||||
hb.isOnline = true;
|
||||
hb.errorCode = 0;
|
||||
hb.photonAuthToken = null;
|
||||
hb.appVersion = player.Player.PlayerExtra.Heartbeat?.appVersion ?? hb.appVersion;
|
||||
|
||||
if (Request.HasFormContentType)
|
||||
{
|
||||
var form = await Request.ReadFormAsync();
|
||||
if (form.TryGetValue("DeviceClass", out var dc) && int.TryParse(dc, out var dcVal))
|
||||
hb.deviceClass = (DeviceClasses)dcVal;
|
||||
if (form.TryGetValue("StatusVisibility", out var sv) && int.TryParse(sv, out var svVal))
|
||||
hb.statusVisibility = (StatusVisibility)svVal;
|
||||
if (form.TryGetValue("VRMovementMode", out var vrm) && int.TryParse(vrm, out var vrmVal))
|
||||
hb.vrMovementMode = vrmVal;
|
||||
}
|
||||
|
||||
player.Player.PlayerExtra.Heartbeat = hb;
|
||||
PlayerDB.Players.Update(player);
|
||||
|
||||
await Services.ToxModService.EnsureCurrent(player);
|
||||
}
|
||||
finally
|
||||
{
|
||||
playerLock.Release();
|
||||
}
|
||||
|
||||
/*var (xpAwarded, leveledUp, newLevel, newXP) = PlayerDB.AwardHeartbeatXP(id.Value);
|
||||
|
||||
if (xpAwarded)
|
||||
{
|
||||
var progressionPayload = Newtonsoft.Json.JsonConvert.SerializeObject(
|
||||
WebsocketEvents.CreateLevelUpdateResponse(id.Value, newLevel, newXP));
|
||||
|
||||
await NotificationsController.SendToPlayer(id.Value, progressionPayload);
|
||||
}*/
|
||||
|
||||
return Ok(hb);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/none")]
|
||||
public async Task<IActionResult> MatchmakeNone()
|
||||
{
|
||||
var id = AuthStuff.GetPlayerId(Request);
|
||||
if (id == null)
|
||||
return Unauthorized("");
|
||||
|
||||
ClearRoomSession(id.Value);
|
||||
|
||||
var player = PlayerDB.GetCurrentPlayer(id.Value);
|
||||
if (player != null)
|
||||
EnsurePlayerDorm(player);
|
||||
|
||||
var heartbeat = PlayerDB.GetPlayerHeartbeat(id.Value);
|
||||
|
||||
if (heartbeat != null)
|
||||
await NotificationsController.RefreshHeartbeat(id.Value, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("goto/room/{roomName}")]
|
||||
public async Task<IActionResult> MatchmakeByRoomName(string roomName)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
});
|
||||
}
|
||||
|
||||
if (roomName.Equals("DormRoom", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
long dormRoomId = EnsurePlayerDorm(player);
|
||||
AuthorizeRoomSession(player.PlayerId, dormRoomId);
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(dormRoomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, dormRoomId);
|
||||
|
||||
var dormHeartbeat = Sessions.CreateDorm(player.PlayerId, player.Player.Username, dormRoomId);
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
dormHeartbeat.roomInstance.maxCapacity = 1;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, dormHeartbeat);
|
||||
return Ok(dormHeartbeat);
|
||||
}
|
||||
|
||||
var room = RoomDB.GetRoomByName(roomName);
|
||||
if (room == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
long roomId = room.RoomId;
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.BannedFromRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
bool isDeveloper = player.PlayerRoles?.Any(r => r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
bool isCreator = room.CreatorAccountId == player.PlayerId;
|
||||
bool hasAccess = room.Roles?.Any(r =>
|
||||
r.AccountId == player.PlayerId && (int)r.Role >= (int)Role.CoOwner) ?? false;
|
||||
bool isOwnerOrCoOwner = isCreator || hasAccess;
|
||||
|
||||
bool hasOwner = room.CreatorAccountId > 0 ||
|
||||
(room.Roles?.Any(r => (int)r.Role >= (int)Role.CoOwner) ?? false);
|
||||
|
||||
if (!hasOwner)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AccountDoesNotExist,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.Accessibility == RoomAccessibility.Dev_only || room.Accessibility == RoomAccessibility.Dev_Unlisted)
|
||||
{
|
||||
if (!isDeveloper && !isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.DeveloperOnly,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
else if (room.Accessibility == RoomAccessibility.Private)
|
||||
{
|
||||
if (!isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.RoomIsPrivate,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
if (!isOwnerOrCoOwner)
|
||||
{
|
||||
if (player.Player?.IsJunior == true && room.SupportsJuniors == false)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.JuniorNotAllowed,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.MinLevel > 0 && (player.Player?.Level ?? 1) < room.MinLevel)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.LevelTooLow,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
var (joinMode, autoFollow, _, additionalPlayerIds) = await ParseMatchmakeForm(Request);
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = Sessions.CreateRoom(
|
||||
player.PlayerId,
|
||||
roomId,
|
||||
null,
|
||||
joinMode: joinMode,
|
||||
additionalPlayersAutoFollow: autoFollow);
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
if (additionalPlayerIds.Count > 0 && autoFollow)
|
||||
await ShovePlayersToInstance(additionalPlayerIds, roomId, 0, heartbeat);
|
||||
else if (additionalPlayerIds.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIds, roomId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/dorm")]
|
||||
public async Task<IActionResult> MatchmakeDorm()
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
long dormRoomId = EnsurePlayerDorm(player);
|
||||
AuthorizeRoomSession(player.PlayerId, dormRoomId);
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(dormRoomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, dormRoomId);
|
||||
|
||||
var heartbeat = Sessions.CreateDorm(player.PlayerId, player.Player.Username, dormRoomId);
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
heartbeat.roomInstance.maxCapacity = 1;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/event/{eventId}")]
|
||||
public async Task<IActionResult> MatchmakeEvent(long eventId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
});
|
||||
}
|
||||
|
||||
var ev = Vanadium.Classes.DBs.EventDB.GetPlayerEventById(eventId);
|
||||
if (ev == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchGame,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
long roomId = ev.RoomId;
|
||||
long? subRoomId = ev.SubRoomId;
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
if (room == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.BannedFromRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
var (joinMode, autoFollow, _, additionalPlayerIds) = await ParseMatchmakeForm(Request);
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = Sessions.CreateRoom(
|
||||
player.PlayerId,
|
||||
roomId,
|
||||
subRoomId,
|
||||
joinMode: joinMode,
|
||||
additionalPlayersAutoFollow: autoFollow);
|
||||
|
||||
if (heartbeat?.roomInstance != null)
|
||||
heartbeat.roomInstance.eventId = eventId;
|
||||
|
||||
var fp = PlayerDB.Players.FindById(player.PlayerId);
|
||||
if (fp?.Player?.PlayerExtra != null)
|
||||
{
|
||||
fp.Player.PlayerExtra.Heartbeat = heartbeat;
|
||||
PlayerDB.Players.Update(fp);
|
||||
}
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
if (additionalPlayerIds.Count > 0 && autoFollow)
|
||||
await ShovePlayersToInstance(additionalPlayerIds, roomId, subRoomId ?? 0, heartbeat);
|
||||
else if (additionalPlayerIds.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIds, roomId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/club/{clubId}")]
|
||||
public async Task<IActionResult> MatchmakeToClub(long clubId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
return StatusCode(403);
|
||||
|
||||
var targetClub = Classes.DBs.ClubsDB.GetClub(clubId);
|
||||
if (targetClub == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchClub,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
long roomId = targetClub.ClubhouseRoomId ?? 0;
|
||||
if (roomId <= 0)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.ClubHasNoClubhouse,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
if (room == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.ClubHasNoClubhouse,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.BannedFromClub,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
bool isDeveloper = player.PlayerRoles?.Any(r => r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
bool isCreator = room.CreatorAccountId == player.PlayerId;
|
||||
bool hasAccess = room.Roles?.Any(r =>
|
||||
r.AccountId == player.PlayerId && (int)r.Role >= (int)Role.CoOwner) ?? false;
|
||||
bool isOwnerOrCoOwner = isCreator || hasAccess;
|
||||
|
||||
bool hasOwner = room.CreatorAccountId > 0 ||
|
||||
(room.Roles?.Any(r => (int)r.Role >= (int)Role.CoOwner) ?? false);
|
||||
|
||||
if (!hasOwner)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AccountDoesNotExist,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.Accessibility == RoomAccessibility.Dev_only || room.Accessibility == RoomAccessibility.Dev_Unlisted)
|
||||
{
|
||||
if (!isDeveloper && !isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.DeveloperOnly,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
if (!isOwnerOrCoOwner)
|
||||
{
|
||||
if (player.Player?.IsJunior == true && room.SupportsJuniors == false)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.JuniorNotAllowed,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.MinLevel > 0 && (player.Player?.Level ?? 1) < room.MinLevel)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.LevelTooLow,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
var currentInstanceHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
|
||||
var targetInstance = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomId == roomId)
|
||||
.Select(p => p.Player!.PlayerExtra!.Heartbeat!.roomInstance!)
|
||||
.GroupBy(ri => ri.roomInstanceId)
|
||||
.Select(g => g.First())
|
||||
.OrderByDescending(ri => Sessions.CountPlayersInInstance(ri.roomInstanceId))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (targetInstance != null)
|
||||
{
|
||||
if (currentInstanceHb?.roomInstance?.roomInstanceId == targetInstance.roomInstanceId)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AlreadyInTargetInstance,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (targetInstance.isFull || Sessions.CountPlayersInInstance(targetInstance.roomInstanceId) >= targetInstance.maxCapacity)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.InsufficientSpace,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, targetInstance);
|
||||
if (heartbeat == null)
|
||||
return StatusCode(500);
|
||||
|
||||
heartbeat.playerId = player.PlayerId;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var createdHeartbeat = Sessions.CreateRoom(player.PlayerId, roomId, joinMode: 0, additionalPlayersAutoFollow: false, roomNameOverride: targetClub.Name + " Clubhouse");
|
||||
if (createdHeartbeat == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.ClubHasNoClubhouse,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
createdHeartbeat.playerId = player.PlayerId;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, createdHeartbeat);
|
||||
|
||||
return Ok(createdHeartbeat);
|
||||
}
|
||||
|
||||
private static async Task ShovePlayersToInstance(List<long> playerIds, long roomId, long subRoomId, Heartbeat leaderHeartbeat)
|
||||
{
|
||||
foreach (var pid in playerIds)
|
||||
{
|
||||
var fp = PlayerDB.Players.FindById(pid);
|
||||
if (fp == null) continue;
|
||||
|
||||
var hb = Sessions.CreateRoom(pid, roomId, subRoomId, joinMode: 0, additionalPlayersAutoFollow: false);
|
||||
|
||||
if (leaderHeartbeat.roomInstance != null && hb.roomInstance != null)
|
||||
{
|
||||
hb.roomInstance.photonRoomId = leaderHeartbeat.roomInstance.photonRoomId;
|
||||
hb.roomInstance.photonRegion = leaderHeartbeat.roomInstance.photonRegion;
|
||||
hb.roomInstance.roomInstanceId = leaderHeartbeat.roomInstance.roomInstanceId;
|
||||
}
|
||||
|
||||
fp.Player.PlayerExtra ??= new PlayerExtra();
|
||||
fp.Player.PlayerExtra.Heartbeat = hb;
|
||||
PlayerDB.Players.Update(fp);
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(pid, hb);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<(int joinMode, bool autoFollow, bool bypassMovement, List<long> additionalPlayerIds)> ParseMatchmakeForm(HttpRequest request)
|
||||
{
|
||||
int joinMode = 0;
|
||||
bool autoFollow = false;
|
||||
bool bypassMovement = false;
|
||||
var additionalPlayerIds = new List<long>();
|
||||
|
||||
if (request.HasFormContentType)
|
||||
{
|
||||
var form = await request.ReadFormAsync();
|
||||
if (form.TryGetValue("JoinMode", out var joinModeStr))
|
||||
int.TryParse(joinModeStr, out joinMode);
|
||||
if (form.TryGetValue("AdditionalPlayersAutoFollow", out var autoFollowStr))
|
||||
autoFollow = autoFollowStr.ToString().Equals("True", StringComparison.OrdinalIgnoreCase);
|
||||
if (form.TryGetValue("BypassMovementModeRestriction", out var bypassStr))
|
||||
bypassMovement = bypassStr.ToString().Equals("True", StringComparison.OrdinalIgnoreCase);
|
||||
var additionalKey = form.Keys.FirstOrDefault(k => k.Equals("AdditionalPlayerIds", StringComparison.OrdinalIgnoreCase));
|
||||
if (additionalKey != null)
|
||||
{
|
||||
foreach (var val in form[additionalKey])
|
||||
{
|
||||
if (long.TryParse(val?.Trim(), out var pid))
|
||||
additionalPlayerIds.Add(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (joinMode, autoFollow, bypassMovement, additionalPlayerIds);
|
||||
}
|
||||
|
||||
[HttpPost("player/notifydisconnect")]
|
||||
public async Task<IActionResult> NotifyDisconnect()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/instance/{roomInstanceId}")]
|
||||
public async Task<IActionResult> MatchmakeInstance(long roomInstanceId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
});
|
||||
}
|
||||
|
||||
var targetInstance = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
.Select(p => p.Player.PlayerExtra.Heartbeat.roomInstance)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (targetInstance == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchGame,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (targetInstance.isFull || Sessions.CountPlayersInInstance(roomInstanceId) >= targetInstance.maxCapacity)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.InsufficientSpace,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
var currentInstanceHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
if (currentInstanceHb?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AlreadyInTargetInstance,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, targetInstance.roomId);
|
||||
|
||||
var heartbeat = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, targetInstance);
|
||||
heartbeat.playerId = player.PlayerId;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
var (_, autoFollowInstance, _, additionalPlayerIdsInstance) = await ParseMatchmakeForm(Request);
|
||||
if (additionalPlayerIdsInstance.Count > 0 && autoFollowInstance)
|
||||
await ShovePlayersToInstance(additionalPlayerIdsInstance, targetInstance.roomId, targetInstance.subRoomId, heartbeat);
|
||||
else if (additionalPlayerIdsInstance.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIdsInstance, targetInstance.roomId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/v2/instance/{roomInstanceId}")]
|
||||
public async Task<IActionResult> MatchmakeInstanceV2(long roomInstanceId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new { success = false, error_id = "Matchmaking.Banned", error = "You are banned.", value = new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
}});
|
||||
}
|
||||
|
||||
var targetInstance = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
.Select(p => p.Player.PlayerExtra.Heartbeat.roomInstance)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (targetInstance == null)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.NoSuchGame", error = "Instance not found.", value = new Heartbeat { errorCode = MatchmakingErrorCode.NoSuchGame, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (targetInstance.isFull || Sessions.CountPlayersInInstance(roomInstanceId) >= targetInstance.maxCapacity)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.InsufficientSpace", error = "Instance is full.", value = new Heartbeat { errorCode = MatchmakingErrorCode.InsufficientSpace, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
var currentInstanceHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
if (currentInstanceHb?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.AlreadyInTargetInstance", error = "Already in this instance.", value = new Heartbeat { errorCode = MatchmakingErrorCode.AlreadyInTargetInstance, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, targetInstance.roomId);
|
||||
|
||||
var heartbeat = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, targetInstance);
|
||||
heartbeat.playerId = player.PlayerId;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
var (_, autoFollowInstance, _, additionalPlayerIdsInstance) = await ParseMatchmakeForm(Request);
|
||||
if (additionalPlayerIdsInstance.Count > 0 && autoFollowInstance)
|
||||
await ShovePlayersToInstance(additionalPlayerIdsInstance, targetInstance.roomId, targetInstance.subRoomId, heartbeat);
|
||||
else if (additionalPlayerIdsInstance.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIdsInstance, targetInstance.roomId, heartbeat);
|
||||
|
||||
return Ok(new { success = true, error_id = (string?)null, error = (string?)null, value = heartbeat });
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/room/{roomId}")]
|
||||
public async Task<IActionResult> MatchmakeRoomRoomId(long roomId, [FromQuery] long? subRoomId = null)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
var bannedHeartbeat = new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
};
|
||||
|
||||
return Ok(bannedHeartbeat);
|
||||
}
|
||||
|
||||
var (joinMode, autoFollow, bypassMovement, additionalPlayerIds) = await ParseMatchmakeForm(Request);
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
|
||||
if (room == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (AuthStuff.GetAndEnsureAppVersion(Request) != "20250724" && room.Tags.Any(x => x.Tag.Equals("2025", StringComparison.OrdinalIgnoreCase)))
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.UpdateRequired,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.BannedFromRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
bool isDeveloper = player.PlayerRoles?.Any(r => r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
bool isCreator = room.CreatorAccountId == player.PlayerId;
|
||||
bool hasAccess = room.Roles?.Any(r =>
|
||||
r.AccountId == player.PlayerId && (int)r.Role >= (int)Role.CoOwner) ?? false;
|
||||
bool isOwnerOrCoOwner = isCreator || hasAccess;
|
||||
|
||||
bool hasOwner = room.CreatorAccountId > 0 ||
|
||||
(room.Roles?.Any(r => (int)r.Role >= (int)Role.CoOwner) ?? false);
|
||||
|
||||
if (!hasOwner)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AccountDoesNotExist,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.Accessibility == RoomAccessibility.Dev_only || room.Accessibility == RoomAccessibility.Dev_Unlisted)
|
||||
{
|
||||
if (!isDeveloper && !isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.DeveloperOnly,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
else if (room.Accessibility == RoomAccessibility.Private)
|
||||
{
|
||||
if (!isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.RoomIsPrivate,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
if (!isOwnerOrCoOwner)
|
||||
{
|
||||
if (player.Player?.IsJunior == true && room.SupportsJuniors == false)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.JuniorNotAllowed,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.MinLevel > 0 && (player.Player?.Level ?? 1) < room.MinLevel)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.LevelTooLow,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var currentHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
if (bypassMovement && joinMode == 0 && currentHb?.roomInstance != null && currentHb.roomInstance.roomId == roomId && !currentHb.roomInstance.isPrivate)
|
||||
{
|
||||
long currentInstanceId = currentHb.roomInstance.roomInstanceId;
|
||||
|
||||
var otherInstance = PlayerDB.Players
|
||||
.FindAll()
|
||||
.Where(p =>
|
||||
p.PlayerId != player.PlayerId &&
|
||||
p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomId == roomId &&
|
||||
!p.Player.PlayerExtra.Heartbeat.roomInstance.isPrivate &&
|
||||
p.Player.PlayerExtra.Heartbeat.roomInstance.roomInstanceId != currentInstanceId &&
|
||||
Sessions.CountPlayersInInstance(p.Player.PlayerExtra.Heartbeat.roomInstance.roomInstanceId) < p.Player.PlayerExtra.Heartbeat.roomInstance.maxCapacity)
|
||||
.Select(p => p.Player.PlayerExtra.Heartbeat.roomInstance)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (otherInstance != null)
|
||||
{
|
||||
var hb = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, otherInstance);
|
||||
hb.playerId = player.PlayerId;
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, hb);
|
||||
return Ok(hb);
|
||||
}
|
||||
|
||||
joinMode = 1;
|
||||
}
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = Sessions.CreateRoom(
|
||||
player.PlayerId,
|
||||
roomId,
|
||||
subRoomId,
|
||||
joinMode: joinMode,
|
||||
additionalPlayersAutoFollow: autoFollow);
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
if (additionalPlayerIds.Count > 0 && autoFollow)
|
||||
await ShovePlayersToInstance(additionalPlayerIds, roomId, subRoomId ?? 0, heartbeat);
|
||||
else if (additionalPlayerIds.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIds, roomId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/v2/room/{roomId}")]
|
||||
public async Task<IActionResult> MatchmakeRoomRoomIdV2(long roomId, [FromQuery] long? subRoomId = null)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new { success = false, error_id = "Matchmaking.Banned", error = "You are banned.", value = new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
}});
|
||||
}
|
||||
|
||||
var (joinMode, autoFollow, bypassMovement, additionalPlayerIds) = await ParseMatchmakeForm(Request);
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
|
||||
if (room == null)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.NoSuchRoom", error = "Room not found.", value = new Heartbeat { errorCode = MatchmakingErrorCode.NoSuchRoom, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (AuthStuff.GetAndEnsureAppVersion(Request) != "20250724" && room.Tags.Any(x => x.Tag.Equals("2025", StringComparison.OrdinalIgnoreCase)))
|
||||
return Ok(new { success = false, error_id = "Matchmaking.UpdateRequired", error = "Update required.", value = new Heartbeat { errorCode = MatchmakingErrorCode.UpdateRequired, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new { success = false, error_id = "Matchmaking.BannedFromRoom", error = "You are banned from this room.", value = new Heartbeat { errorCode = MatchmakingErrorCode.BannedFromRoom, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
bool isDeveloper = player.PlayerRoles?.Any(r => r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
bool isCreator = room.CreatorAccountId == player.PlayerId;
|
||||
bool hasAccess = room.Roles?.Any(r =>
|
||||
r.AccountId == player.PlayerId && (int)r.Role >= (int)Role.CoOwner) ?? false;
|
||||
bool isOwnerOrCoOwner = isCreator || hasAccess;
|
||||
|
||||
bool hasOwner = room.CreatorAccountId > 0 ||
|
||||
(room.Roles?.Any(r => (int)r.Role >= (int)Role.CoOwner) ?? false);
|
||||
|
||||
if (!hasOwner)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.AccountDoesNotExist", error = "Room has no owner.", value = new Heartbeat { errorCode = MatchmakingErrorCode.AccountDoesNotExist, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (room.Accessibility == RoomAccessibility.Dev_only || room.Accessibility == RoomAccessibility.Dev_Unlisted)
|
||||
{
|
||||
if (!isDeveloper && !isCreator && !hasAccess)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.DeveloperOnly", error = "This room is developer only.", value = new Heartbeat { errorCode = MatchmakingErrorCode.DeveloperOnly, isOnline = true, playerId = player.PlayerId } });
|
||||
}
|
||||
else if (room.Accessibility == RoomAccessibility.Private)
|
||||
{
|
||||
if (!isCreator && !hasAccess)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.RoomIsPrivate", error = "This room is private.", value = new Heartbeat { errorCode = MatchmakingErrorCode.RoomIsPrivate, isOnline = true, playerId = player.PlayerId } });
|
||||
}
|
||||
|
||||
if (!isOwnerOrCoOwner)
|
||||
{
|
||||
if (player.Player?.IsJunior == true && room.SupportsJuniors == false)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.JuniorNotAllowed", error = "Juniors are not allowed in this room.", value = new Heartbeat { errorCode = MatchmakingErrorCode.JuniorNotAllowed, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (room.MinLevel > 0 && (player.Player?.Level ?? 1) < room.MinLevel)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.LevelTooLow", error = "Your level is too low.", value = new Heartbeat { errorCode = MatchmakingErrorCode.LevelTooLow, isOnline = true, playerId = player.PlayerId } });
|
||||
}
|
||||
}
|
||||
|
||||
var currentHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
if (bypassMovement && joinMode == 0 && currentHb?.roomInstance != null && currentHb.roomInstance.roomId == roomId && !currentHb.roomInstance.isPrivate)
|
||||
{
|
||||
long currentInstanceId = currentHb.roomInstance.roomInstanceId;
|
||||
|
||||
var otherInstance = PlayerDB.Players
|
||||
.FindAll()
|
||||
.Where(p =>
|
||||
p.PlayerId != player.PlayerId &&
|
||||
p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomId == roomId &&
|
||||
!p.Player.PlayerExtra.Heartbeat.roomInstance.isPrivate &&
|
||||
p.Player.PlayerExtra.Heartbeat.roomInstance.roomInstanceId != currentInstanceId &&
|
||||
Sessions.CountPlayersInInstance(p.Player.PlayerExtra.Heartbeat.roomInstance.roomInstanceId) < p.Player.PlayerExtra.Heartbeat.roomInstance.maxCapacity)
|
||||
.Select(p => p.Player.PlayerExtra.Heartbeat.roomInstance)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (otherInstance != null)
|
||||
{
|
||||
var hb = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, otherInstance);
|
||||
hb.playerId = player.PlayerId;
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, hb);
|
||||
return Ok(new { success = true, error_id = (string?)null, error = (string?)null, value = hb });
|
||||
}
|
||||
|
||||
joinMode = 1;
|
||||
}
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = Sessions.CreateRoom(
|
||||
player.PlayerId,
|
||||
roomId,
|
||||
subRoomId,
|
||||
joinMode: joinMode,
|
||||
additionalPlayersAutoFollow: autoFollow);
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
if (additionalPlayerIds.Count > 0 && autoFollow)
|
||||
await ShovePlayersToInstance(additionalPlayerIds, roomId, subRoomId ?? 0, heartbeat);
|
||||
else if (additionalPlayerIds.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIds, roomId, heartbeat);
|
||||
|
||||
return Ok(new { success = true, error_id = (string?)null, error = (string?)null, value = heartbeat });
|
||||
}
|
||||
|
||||
[Route("player/avoidjuniors")]
|
||||
public IActionResult avoidjuniours()
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/room/{roomId}/{subRoomId}")]
|
||||
public async Task<IActionResult> MatchmakeRoomWithSubRoom(long roomId, long subRoomId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
var bannedHeartbeat = new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
};
|
||||
|
||||
return Ok(bannedHeartbeat);
|
||||
}
|
||||
|
||||
var (joinMode, autoFollow, bypassMovement, additionalPlayerIds) = await ParseMatchmakeForm(Request);
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
|
||||
if (room == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.BannedFromRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
bool isDeveloper = player.PlayerRoles?.Any(r => r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
bool isCreator = room.CreatorAccountId == player.PlayerId;
|
||||
bool hasAccess = room.Roles?.Any(r =>
|
||||
r.AccountId == player.PlayerId && (int)r.Role >= (int)Role.CoOwner) ?? false;
|
||||
bool isOwnerOrCoOwner = isCreator || hasAccess;
|
||||
|
||||
bool hasOwner = room.CreatorAccountId > 0 ||
|
||||
(room.Roles?.Any(r => (int)r.Role >= (int)Role.CoOwner) ?? false);
|
||||
|
||||
if (!hasOwner)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AccountDoesNotExist,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.Accessibility == RoomAccessibility.Dev_only || room.Accessibility == RoomAccessibility.Dev_Unlisted)
|
||||
{
|
||||
if (!isDeveloper && !isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.DeveloperOnly,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
else if (room.Accessibility == RoomAccessibility.Private)
|
||||
{
|
||||
if (!isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.RoomIsPrivate,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
if (!isOwnerOrCoOwner)
|
||||
{
|
||||
if (player.Player?.IsJunior == true && room.SupportsJuniors == false)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.JuniorNotAllowed,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.MinLevel > 0 && (player.Player?.Level ?? 1) < room.MinLevel)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.LevelTooLow,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = Sessions.CreateRoom(
|
||||
player.PlayerId,
|
||||
roomId,
|
||||
subRoomId,
|
||||
joinMode: joinMode,
|
||||
additionalPlayersAutoFollow: autoFollow);
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
if (additionalPlayerIds.Count > 0 && autoFollow)
|
||||
await ShovePlayersToInstance(additionalPlayerIds, roomId, subRoomId, heartbeat);
|
||||
else if (additionalPlayerIds.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIds, roomId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/v2/room/{roomId}/{subRoomId}")]
|
||||
public async Task<IActionResult> MatchmakeRoomWithSubRoomV2(long roomId, long subRoomId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new { success = false, error_id = "Matchmaking.Banned", error = "You are banned.", value = new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
}});
|
||||
}
|
||||
|
||||
var (joinMode, autoFollow, bypassMovement, additionalPlayerIds) = await ParseMatchmakeForm(Request);
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
|
||||
if (room == null)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.NoSuchRoom", error = "Room not found.", value = new Heartbeat { errorCode = MatchmakingErrorCode.NoSuchRoom, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new { success = false, error_id = "Matchmaking.BannedFromRoom", error = "You are banned from this room.", value = new Heartbeat { errorCode = MatchmakingErrorCode.BannedFromRoom, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
bool isDeveloper = player.PlayerRoles?.Any(r => r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
bool isCreator = room.CreatorAccountId == player.PlayerId;
|
||||
bool hasAccess = room.Roles?.Any(r =>
|
||||
r.AccountId == player.PlayerId && (int)r.Role >= (int)Role.CoOwner) ?? false;
|
||||
bool isOwnerOrCoOwner = isCreator || hasAccess;
|
||||
|
||||
bool hasOwner = room.CreatorAccountId > 0 ||
|
||||
(room.Roles?.Any(r => (int)r.Role >= (int)Role.CoOwner) ?? false);
|
||||
|
||||
if (!hasOwner)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.AccountDoesNotExist", error = "Room has no owner.", value = new Heartbeat { errorCode = MatchmakingErrorCode.AccountDoesNotExist, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (room.Accessibility == RoomAccessibility.Dev_only || room.Accessibility == RoomAccessibility.Dev_Unlisted)
|
||||
{
|
||||
if (!isDeveloper && !isCreator && !hasAccess)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.DeveloperOnly", error = "This room is developer only.", value = new Heartbeat { errorCode = MatchmakingErrorCode.DeveloperOnly, isOnline = true, playerId = player.PlayerId } });
|
||||
}
|
||||
else if (room.Accessibility == RoomAccessibility.Private)
|
||||
{
|
||||
if (!isCreator && !hasAccess)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.RoomIsPrivate", error = "This room is private.", value = new Heartbeat { errorCode = MatchmakingErrorCode.RoomIsPrivate, isOnline = true, playerId = player.PlayerId } });
|
||||
}
|
||||
|
||||
if (!isOwnerOrCoOwner)
|
||||
{
|
||||
if (player.Player?.IsJunior == true && room.SupportsJuniors == false)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.JuniorNotAllowed", error = "Juniors are not allowed in this room.", value = new Heartbeat { errorCode = MatchmakingErrorCode.JuniorNotAllowed, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (room.MinLevel > 0 && (player.Player?.Level ?? 1) < room.MinLevel)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.LevelTooLow", error = "Your level is too low.", value = new Heartbeat { errorCode = MatchmakingErrorCode.LevelTooLow, isOnline = true, playerId = player.PlayerId } });
|
||||
}
|
||||
}
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = Sessions.CreateRoom(
|
||||
player.PlayerId,
|
||||
roomId,
|
||||
subRoomId,
|
||||
joinMode: joinMode,
|
||||
additionalPlayersAutoFollow: autoFollow);
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
if (additionalPlayerIds.Count > 0 && autoFollow)
|
||||
await ShovePlayersToInstance(additionalPlayerIds, roomId, subRoomId, heartbeat);
|
||||
else if (additionalPlayerIds.Count > 0)
|
||||
await NotificationsController.SendPartyActivitySwitch(player.PlayerId, additionalPlayerIds, roomId, heartbeat);
|
||||
|
||||
return Ok(new { success = true, error_id = (string?)null, error = (string?)null, value = heartbeat });
|
||||
}
|
||||
|
||||
/* 20230616 & 20250724.01 photons */
|
||||
|
||||
private static readonly string[] _fallbackRealtime = new[]
|
||||
{
|
||||
"616d6ba8-edb1-47f8-a0de-31c8ce426685",
|
||||
"a7c732cd-5cea-4839-b0b3-ba8e9af14b06",
|
||||
"90d94f73-9797-409d-84ab-ed3992177612"
|
||||
};
|
||||
|
||||
private static readonly string[] _fallbackVoice = new[]
|
||||
{
|
||||
"b3a7f09a-b167-4ba1-87bb-2603da5a39be",
|
||||
"7e71f40c-d1fa-4e48-8851-981402e630e5",
|
||||
"3e010413-c8c8-48df-95cf-bf7f2bf430e6"
|
||||
};
|
||||
|
||||
[HttpGet("player/connection-info")]
|
||||
public async Task<IActionResult> GetPlayerConnectionInfo([FromQuery] long? roomInstanceId)
|
||||
{
|
||||
var id = AuthStuff.GetPlayerId(Request);
|
||||
if (id == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (roomInstanceId == null || roomInstanceId <= 0)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
error = (string?)null,
|
||||
value = new
|
||||
{
|
||||
PhotonRealtimeAppId = _fallbackRealtime[_photonRng.Next(_fallbackRealtime.Length)],
|
||||
PhotonChatAppId,
|
||||
PhotonVoiceAppId = _fallbackVoice[_photonRng.Next(_fallbackVoice.Length)],
|
||||
experiments = new { shouldUseGameServerNetworking = false }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var dbEntry = InstanceDB.Get(roomInstanceId.Value);
|
||||
|
||||
if (dbEntry == null)
|
||||
{
|
||||
var liveInstance = PlayerDB.Players.FindAll()
|
||||
.Select(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance)
|
||||
.FirstOrDefault(ri => ri?.roomInstanceId == roomInstanceId.Value);
|
||||
|
||||
if (liveInstance != null)
|
||||
{
|
||||
dbEntry = InstanceDB.Upsert(liveInstance, liveInstance.isPrivate);
|
||||
}
|
||||
}
|
||||
|
||||
if (dbEntry == null)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
error = (string?)null,
|
||||
value = new
|
||||
{
|
||||
PhotonRealtimeAppId = _fallbackRealtime[_photonRng.Next(_fallbackRealtime.Length)],
|
||||
PhotonChatAppId,
|
||||
PhotonVoiceAppId = _fallbackVoice[_photonRng.Next(_fallbackVoice.Length)],
|
||||
experiments = new { shouldUseGameServerNetworking = false }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(dbEntry.PhotonRealtimeAppId) || string.IsNullOrEmpty(dbEntry.PhotonVoiceAppId))
|
||||
{
|
||||
var (rt, vo) = InstanceDB.AssignPhotonIds(roomInstanceId.Value);
|
||||
dbEntry.PhotonRealtimeAppId = rt;
|
||||
dbEntry.PhotonVoiceAppId = vo;
|
||||
}
|
||||
|
||||
var liveInst = PlayerDB.Players.FindAll()
|
||||
.Select(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance)
|
||||
.FirstOrDefault(ri => ri?.roomInstanceId == roomInstanceId.Value);
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
error = (string?)null,
|
||||
value = new
|
||||
{
|
||||
PhotonAuthToken = "",
|
||||
PhotonRealtimeAppId = dbEntry.PhotonRealtimeAppId,
|
||||
PhotonChatAppId,
|
||||
PhotonVoiceAppId = dbEntry.PhotonVoiceAppId,
|
||||
PhotonRegion = liveInst?.photonRegion ?? dbEntry.PhotonRegion ?? "us",
|
||||
PhotonRoomId = liveInst?.photonRoomId ?? dbEntry.PhotonRoomId,
|
||||
VoiceConnectionInfo = (string?)null,
|
||||
VoiceServerId = (string?)null,
|
||||
experiments = new { shouldUseGameServerNetworking = false }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("invite")]
|
||||
public async Task<IActionResult> Invite([FromForm] long playerId, [FromForm] long roomInstanceId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (playerId <= 0 || roomInstanceId <= 0)
|
||||
return BadRequest();
|
||||
|
||||
var targetPlayer = PlayerDB.Players.FindById(playerId);
|
||||
if (targetPlayer == null)
|
||||
return NotFound("");
|
||||
|
||||
var rel = FriendsDB.GetRelationships(player.PlayerId).FirstOrDefault(r => r.OtherPlayerID == playerId);
|
||||
if (rel?.RelationshipType != FriendsDBClasses.RelationshipType.Friend)
|
||||
return BadRequest();
|
||||
|
||||
var heartbeat = PlayerDB.GetPlayerHeartbeat(player.PlayerId);
|
||||
if (heartbeat?.roomInstance == null || heartbeat.roomInstance.roomInstanceId != roomInstanceId)
|
||||
return BadRequest();
|
||||
|
||||
var key = (player.PlayerId, playerId);
|
||||
var now = DateTime.UtcNow;
|
||||
_inviteRateLimit.AddOrUpdate(key, _ => (1, now), (_, e) =>
|
||||
(now - e.Window).TotalSeconds >= 15 ? (1, now) : (e.Count + 1, e.Window));
|
||||
|
||||
if (_inviteRateLimit.TryGetValue(key, out var rate) && rate.Count > 3 && (now - rate.Window).TotalSeconds < 15)
|
||||
return BadRequest();
|
||||
|
||||
var invite = new MatchDBClasses.InviteDTO
|
||||
{
|
||||
InviteId = roomInstanceId,
|
||||
Name = heartbeat.roomInstance.Name ?? "Unknown Room",
|
||||
InviteMode = 0
|
||||
};
|
||||
|
||||
await NotificationsController.SendInvite(playerId, player.PlayerId, heartbeat.roomInstance.roomId, invite);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
//[HttpPost("matchmake/instance/{roomInstanceId}")] // added back because some bitch deleted it
|
||||
[HttpPost("matchmake/invite/{roomInstanceId}")] // ez
|
||||
//[HttpPost("matchmake/v2/instance/{roomInstanceId}")]
|
||||
public async Task<IActionResult> MatchmakeToInviteInstance(long roomInstanceId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
});
|
||||
}
|
||||
|
||||
var targetInstance = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
.Select(p => p.Player.PlayerExtra.Heartbeat.roomInstance)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (targetInstance == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchGame,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (targetInstance.isFull || Sessions.CountPlayersInInstance(roomInstanceId) >= targetInstance.maxCapacity)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.InsufficientSpace,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
var currentInstanceHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
if (currentInstanceHb?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AlreadyInTargetInstance,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, targetInstance.roomId);
|
||||
|
||||
var heartbeat = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, targetInstance);
|
||||
heartbeat.playerId = player.PlayerId;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/v2/invite/{roomInstanceId}")]
|
||||
public async Task<IActionResult> MatchmakeToInviteInstanceV2(long roomInstanceId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new { success = false, error_id = "Matchmaking.Banned", error = "You are banned.", value = new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
}});
|
||||
}
|
||||
|
||||
var targetInstance = PlayerDB.Players.FindAll()
|
||||
.Where(p => p.Player?.PlayerExtra?.Heartbeat?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
.Select(p => p.Player.PlayerExtra.Heartbeat.roomInstance)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (targetInstance == null)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.NoSuchGame", error = "Instance not found.", value = new Heartbeat { errorCode = MatchmakingErrorCode.NoSuchGame, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
if (targetInstance.isFull || Sessions.CountPlayersInInstance(roomInstanceId) >= targetInstance.maxCapacity)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.InsufficientSpace", error = "Instance is full.", value = new Heartbeat { errorCode = MatchmakingErrorCode.InsufficientSpace, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
var currentInstanceHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
if (currentInstanceHb?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
return Ok(new { success = false, error_id = "Matchmaking.AlreadyInTargetInstance", error = "Already in this instance.", value = new Heartbeat { errorCode = MatchmakingErrorCode.AlreadyInTargetInstance, isOnline = true, playerId = player.PlayerId } });
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, targetInstance.roomId);
|
||||
|
||||
var heartbeat = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, targetInstance);
|
||||
heartbeat.playerId = player.PlayerId;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
return Ok(new { success = true, error_id = (string?)null, error = (string?)null, value = heartbeat });
|
||||
}
|
||||
|
||||
[HttpPost("matchmake/player/{targetPlayerId}")]
|
||||
public async Task<IActionResult> MatchmakeToPlayer(long targetPlayerId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
if (PlayerDB.IsBanned(player.PlayerId))
|
||||
{
|
||||
var previousHeartbeat = player.Player?.PlayerExtra?.Heartbeat;
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
appVersion = AuthStuff.GetAndEnsureAppVersion(Request),
|
||||
deviceClass = previousHeartbeat?.deviceClass ?? DeviceClasses.Unknown,
|
||||
errorCode = MatchmakingErrorCode.Banned,
|
||||
isOnline = previousHeartbeat?.isOnline ?? true,
|
||||
playerId = player.PlayerId,
|
||||
roomInstance = null,
|
||||
statusVisibility = previousHeartbeat?.statusVisibility ?? StatusVisibility.Online,
|
||||
vrMovementMode = previousHeartbeat?.vrMovementMode ?? 0,
|
||||
photonAuthToken = null,
|
||||
photonRealtimeAppId = null,
|
||||
photonVoiceAppId = null,
|
||||
photonChatAppId = null,
|
||||
photonRegion = null,
|
||||
photonRoomId = null,
|
||||
voiceConnectionInfo = null,
|
||||
voiceServerId = null,
|
||||
experiments = null
|
||||
});
|
||||
}
|
||||
|
||||
var targetPlayer = PlayerDB.Players.FindById(targetPlayerId);
|
||||
if (targetPlayer == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AccountDoesNotExist,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
var targetHb = targetPlayer.Player?.PlayerExtra?.Heartbeat;
|
||||
if (targetHb == null || !targetHb.isOnline || targetHb.roomInstance == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.PlayerNotOnline,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
var targetInstance = targetHb.roomInstance;
|
||||
long roomId = targetInstance.roomId;
|
||||
long roomInstanceId = targetInstance.roomInstanceId;
|
||||
|
||||
var room = RoomDB.GetRoom(roomId);
|
||||
if (room == null)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.NoSuchRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (IsBannedFromRoom(room, player.PlayerId))
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.BannedFromRoom,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
bool isDeveloper = player.PlayerRoles?.Any(r => r == PlayerDBClasses.PlayerRoles.Developer) ?? false;
|
||||
bool isCreator = room.CreatorAccountId == player.PlayerId;
|
||||
bool hasAccess = room.Roles?.Any(r =>
|
||||
r.AccountId == player.PlayerId && (int)r.Role >= (int)Role.CoOwner) ?? false;
|
||||
bool isOwnerOrCoOwner = isCreator || hasAccess;
|
||||
|
||||
bool hasOwner = room.CreatorAccountId > 0 ||
|
||||
(room.Roles?.Any(r => (int)r.Role >= (int)Role.CoOwner) ?? false);
|
||||
|
||||
if (!hasOwner)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AccountDoesNotExist,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.Accessibility == RoomAccessibility.Dev_only || room.Accessibility == RoomAccessibility.Dev_Unlisted)
|
||||
{
|
||||
if (!isDeveloper && !isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.DeveloperOnly,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
else if (room.Accessibility == RoomAccessibility.Private)
|
||||
{
|
||||
if (!isCreator && !hasAccess)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.RoomIsPrivate,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
if (!isOwnerOrCoOwner)
|
||||
{
|
||||
if (player.Player?.IsJunior == true && room.SupportsJuniors == false)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.JuniorNotAllowed,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
if (room.MinLevel > 0 && (player.Player?.Level ?? 1) < room.MinLevel)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.LevelTooLow,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
}
|
||||
|
||||
if (targetInstance.isFull || Sessions.CountPlayersInInstance(roomInstanceId) >= targetInstance.maxCapacity)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.InsufficientSpace,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
var currentInstanceHb = player.Player?.PlayerExtra?.Heartbeat;
|
||||
if (currentInstanceHb?.roomInstance?.roomInstanceId == roomInstanceId)
|
||||
return Ok(new Heartbeat
|
||||
{
|
||||
errorCode = MatchmakingErrorCode.AlreadyInTargetInstance,
|
||||
isOnline = true,
|
||||
playerId = player.PlayerId
|
||||
});
|
||||
|
||||
RoomDB.IncrementRoomVisitCount(roomId);
|
||||
PlayerDB.UpdateRoomLastVisitedAt(player.PlayerId, roomId);
|
||||
|
||||
AuthorizeRoomSession(player.PlayerId, roomId);
|
||||
|
||||
var heartbeat = PlayerDB.UpdatePlayerHeartbeat(player.PlayerId, targetInstance);
|
||||
heartbeat.playerId = player.PlayerId;
|
||||
|
||||
await NotificationsController.RefreshHeartbeat(player.PlayerId, heartbeat);
|
||||
|
||||
return Ok(heartbeat);
|
||||
}
|
||||
|
||||
[HttpDelete("invite/{inviteId}")]
|
||||
public async Task<IActionResult> DeclineInvite(long inviteId)
|
||||
{
|
||||
var player = AuthStuff.GetCurrentPlayer(Request);
|
||||
if (player == null)
|
||||
return Unauthorized("");
|
||||
|
||||
var messages = PlayerDB.GetMessages(player.PlayerId);
|
||||
var invite = messages.FirstOrDefault(m => m.Id == inviteId);
|
||||
|
||||
var invitedata = new MatchDBClasses.InviteDTO
|
||||
{
|
||||
InviteId = inviteId,
|
||||
Name = "Unknown Room",
|
||||
InviteMode = 0
|
||||
};
|
||||
|
||||
if (invite != null)
|
||||
{
|
||||
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new
|
||||
{
|
||||
Id = "2",
|
||||
Msg = new
|
||||
{
|
||||
FromPlayerId = player.PlayerId,
|
||||
Id = PlayerDB.GenerateRandomMessageId(),
|
||||
SentTime = DateTime.UtcNow,
|
||||
Type = MessageType.GameInviteDeclined,
|
||||
Data = invitedata,
|
||||
RoomId = invite.RoomId,
|
||||
PlayerEventId = (long?)null
|
||||
}
|
||||
});
|
||||
|
||||
await NotificationsController.SendToPlayer(invite.FromPlayerId, json);
|
||||
PlayerDB.DeleteMessage(player.PlayerId, inviteId);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user