Hi! I’m trying to understand how the matchmaker works and I don’t understand why my ticket is timed out, although the server is responding to it
Server logs:
Mono path[0] = '/game/Snake_Data/Managed'
Mono config path = '/game/Snake_Data/MonoBleedingEdge/etc'
Preloaded 'lib_burst_generated.so'
[Physics::Module] Initialized MultithreadedJobDispatcher with 1 workers.
Initialize engine version: 2022.3.16f1 (d2c21f0ef2f1)
[Subsystems] Discovering subsystems at path /game/Snake_Data/UnitySubsystems
Forcing GfxDevice: Null
GfxDevice: creating device client; threaded=0; jobified=0
NullGfxDevice:
Version: NULL 1.0 [1.0]
Renderer: Null Device
Vendor: Unity Technologies
Begin MonoManager ReloadAssembly
- Loaded All Assemblies, in 0.401 seconds
- Finished resetting the current domain, in 0.003 seconds
ERROR: Shader Sprites/Default shader is not supported on this GPU (none of subshaders/fallbacks are suitable)
ERROR: Shader Sprites/Mask shader is not supported on this GPU (none of subshaders/fallbacks are suitable)
ERROR: Shader TextMeshPro/Mobile/Distance Field shader is not supported on this GPU (none of subshaders/fallbacks are suitable)
ERROR: Shader GUI/Text Shader shader is not supported on this GPU (none of subshaders/fallbacks are suitable)
UnloadTime: 1.224717 ms
ThreadLog initialized.
[Netcode] StartServer
[Netcode] Initialize
I'M HERE!
SQP server: SQP server started on 0.0.0.0:9010
[Wire]: Attempting connection on: ws://127.0.0.1:8086/v1/connection/websocket
[Wire]: Websocket connected to : ws://127.0.0.1:8086/v1/connection/websocket. Initiating Wire handshake.
Awaiting Allocation. Server config is:
-ServerId: 78003447
-AllocationID: 622b4a2c-079e-46ae-b994-e5947ea865a6
-Port: 9000
-QPort: 9010
-logs: /mnt/unity/logs/
OnAllocation: 622b4a2c-079e-46ae-b994-e5947ea865a6
GetMatchmakerPayloadAsync:
{
"matchProperties": {
"teams": [
{
"teamName": "Snakes",
"teamId": "7d51c7bc-0922-4177-8c9e-4d0dd368df76",
"playerIds": [
"3GBSAqYKoqEEzZs20gxpAMPHCA9S"
]
}
],
"players": [
{
"id": "3GBSAqYKoqEEzZs20gxpAMPHCA9S",
"customData": {
"Skill": 100
}
}
],
"region": "4ddb446e-b58d-418d-b878-379cb62eaf83",
"backfillTicketId": "97bc96d4-ffd2-40a4-811e-e2d4be42c77a"
},
"generatorName": "Arena",
"queueName": "SnakeMode",
"poolName": "Default",
"environmentId": "27bcfe14-425c-4c12-9f6a-0e8722f738ed",
"backfillTicketId": "97bc96d4-ffd2-40a4-811e-e2d4be42c77a",
"matchId": "f39148fb-dfc2-4cb8-8255-3a66618ff543",
"poolId": "a54acefe-c6ce-4e1f-befc-7c3ce151e2e3"
}
Got payload: Unity.Services.Matchmaker.Models.MatchmakingResults
[Matchmaker]: RateLimited (21429)
Title: Too Many Requests
Errors: Rate limit has been exceeded
OnAllocation: 622b4a2c-079e-46ae-b994-e5947ea865a6
Output may be truncated for performance
Code:
using System.Collections.Generic;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Matchmaker;
using Unity.Services.Matchmaker.Models;
using StatusOptions = Unity.Services.Matchmaker.Models.MultiplayAssignment.StatusOptions;
using UnityEngine;
using System;
using Unity.Netcode.Transports.UTP;
public class ClientMatchmaker : MonoBehaviour
{
private string _ticketId;
private void OnEnable()
{
ServerStart.ClientInstance += SignIn;
}
private void OnDisable()
{
ServerStart.ClientInstance -= SignIn;
}
private async void SignIn()
{
await ClientSignIn("SnakePlayer");
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
private async Task ClientSignIn(string serviceProfileName = null)
{
await UnityServices.InitializeAsync();
Debug.Log($"Signed In Anonymousley as {serviceProfileName}({PlayerID()})");
}
private string PlayerID()
{
return AuthenticationService.Instance.PlayerId;
}
public void StartClient()
{
CreateATicket();
}
private async void CreateATicket()
{
var options = new CreateTicketOptions(queueName:"SnakeMode");
var players = new List<Player>
{
new Player(
PlayerID(),
new MatchmakingPlayerData
{
Skill = 100,
}
)
};
var ticketResponse = await MatchmakerService.Instance.CreateTicketAsync(players, options);
_ticketId = ticketResponse.Id;
Debug.Log($"Ticket{_ticketId}");
PollTicketStatus();
}
private async void PollTicketStatus()
{
MultiplayAssignment multiplayAssignment = null;
bool gotAssigment = false;
do
{
await Task.Delay(TimeSpan.FromSeconds(1f));
var ticketStatus = await MatchmakerService.Instance.GetTicketAsync(_ticketId);
if (ticketStatus == null) continue;
if (ticketStatus.Type == typeof(MultiplayAssignment))
{
multiplayAssignment = ticketStatus.Value as MultiplayAssignment;
}
switch(multiplayAssignment.Status)
{
case StatusOptions.Found:
gotAssigment = true;
TicketAssigned(multiplayAssignment);
break;
case StatusOptions.InProgress:
break;
case StatusOptions.Failed:
gotAssigment = true;
Debug.LogError($"Failed to get ticket status. Error: {multiplayAssignment.Message}");
break;
case StatusOptions.Timeout:
gotAssigment = true;
Debug.LogError($"Failed to get ticket status. Ticket timed out");
break;
default:
throw new InvalidOperationException();
}
} while(!gotAssigment);
}
private void TicketAssigned(MultiplayAssignment assignment)
{
Debug.Log($"Ticket Assigned: {assignment.Ip}:{assignment.Port}");
NetworkManager.Singleton.GetComponent<UnityTransport>().SetConnectionData(assignment.Ip, (ushort)assignment.Port);
NetworkManager.Singleton.StartClient();
}
[Serializable]
public class MatchmakingPlayerData
{
public int Skill;
}
}