浏览代码

fix : color, entry and double calls.

-Updated the Rate limiting code to use similar design to the service one
-Fixed colors not appearing for filters (filtering still does not work)
-Fixed Emotes sticking after leaving and joining lobbies
-Fixed double-calls using the Toggles.
-Fixed Lobby Player Entry Init
/main/staging/2021_Upgrade/Async_Refactor
UnityJacob 2 年前
当前提交
d9767fc6
共有 21 个文件被更改,包括 374 次插入230 次删除
  1. 8
      Assets/Prefabs/UI/JoinContent.prefab
  2. 24
      Assets/Prefabs/UI/JoinCreateCanvas.prefab
  3. 2
      Assets/Prefabs/UI/LobbyEntryUI.prefab
  4. 2
      Assets/Prefabs/UI/LobbyUserList.prefab
  5. 4
      Assets/Prefabs/UI/UserCardPanel.prefab
  6. 51
      Assets/Prefabs/UI/UserInteractionPanel.prefab
  7. 23
      Assets/Scenes/mainScene.unity
  8. 22
      Assets/Scripts/GameLobby/Game/GameManager.cs
  9. 7
      Assets/Scripts/GameLobby/Game/LocalLobby.cs
  10. 2
      Assets/Scripts/GameLobby/Game/LocalPlayer.cs
  11. 6
      Assets/Scripts/GameLobby/Infrastructure/Actionvalue.cs
  12. 154
      Assets/Scripts/GameLobby/Lobby/LobbyManager.cs
  13. 6
      Assets/Scripts/GameLobby/Tests/PlayMode/LobbyRoundtripTests.cs
  14. 36
      Assets/Scripts/GameLobby/UI/InLobbyUserUI.cs
  15. 73
      Assets/Scripts/GameLobby/UI/JoinMenuUI.cs
  16. 4
      Assets/Scripts/GameLobby/UI/LobbyEntryUI.cs
  17. 59
      Assets/Scripts/GameLobby/UI/RateLimitVisibility.cs
  18. 6
      Assets/Scripts/GameLobby/UI/UserStateVisibilityUI.cs
  19. 71
      Assets/Scripts/GameLobby/UI/ColorLobbyUI.cs
  20. 44
      Assets/Scripts/GameLobby/UI/RecolorForLobbyType.cs
  21. 0
      /Assets/Scripts/GameLobby/UI/ColorLobbyUI.cs.meta

8
Assets/Prefabs/UI/JoinContent.prefab


m_onVisibilityChange:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 1462126939442648229}
m_TargetAssemblyTypeName: LobbyRelaySample.UI.JoinMenuUI, LobbyRelaySample
m_MethodName: JoinMenuChangedVisibility
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: GameLobby.UI.UITinter, LobbyRelaySample
m_MethodName: SetToColor
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_LobbyButtonPrefab: {fileID: 7018369548608736188, guid: f6d35a456ba76a24587dce83bd088b7d, type: 3}
m_LobbyEntryPrefab: {fileID: 7018369548608736188, guid: f6d35a456ba76a24587dce83bd088b7d, type: 3}
m_LobbyButtonParent: {fileID: 7824921818678239159}
m_JoinCodeField: {fileID: 8659642538454988273}
m_JoinCreateLobbyUI: {fileID: 0}

24
Assets/Prefabs/UI/JoinCreateCanvas.prefab


- component: {fileID: 8158052573755836851}
- component: {fileID: 6665477889391988598}
- component: {fileID: 5354665607884969002}
- component: {fileID: 302397968031337808}
m_Layer: 5
m_Name: BackButton
m_TagString: Untagged

m_Script: {fileID: 11500000, guid: 3c93e82eef7d613418b85194aace7f69, type: 3}
m_Name:
m_EditorClassIdentifier:
m_onVisibilityChange:
m_PersistentCalls:
m_Calls: []
--- !u!225 &302397968031337808
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3486344428529569277}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!1 &3603267332317325680
GameObject:
m_ObjectHideFlags: 0

value:
objectReference: {fileID: 4578721078997909056}
- target: {fileID: 1462126939442648229, guid: c308ffc2a02e5ab4bbe70a8b2e8108c6, type: 3}
propertyPath: m_onVisibilityChange.m_PersistentCalls.m_Calls.Array.size
value: 2
objectReference: {fileID: 0}
- target: {fileID: 1462126939442648229, guid: c308ffc2a02e5ab4bbe70a8b2e8108c6, type: 3}
objectReference: {fileID: 0}
- target: {fileID: 1462126939442648229, guid: c308ffc2a02e5ab4bbe70a8b2e8108c6, type: 3}
propertyPath: m_onVisibilityChange.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 0}
- target: {fileID: 1462126939442648229, guid: c308ffc2a02e5ab4bbe70a8b2e8108c6, type: 3}
propertyPath: m_onVisibilityChange.m_PersistentCalls.m_Calls.Array.data[1].m_Target

2
Assets/Prefabs/UI/LobbyEntryUI.prefab


m_Script: {fileID: 11500000, guid: b408c4b47ec1dd74e8708c04dc35a8fd, type: 3}
m_Name:
m_EditorClassIdentifier:
m_ColorLobbyUI: {fileID: 6515571473500817606}
lobbyNameText: {fileID: 5163640836259929489}
lobbyCountText: {fileID: 5305878922170146764}
onLobbyPressed:

m_Script: {fileID: 11500000, guid: 4079cd003fcd20c40a3bac78acf44b55, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UseLocalLobby: 0
m_toRecolor:
- {fileID: 4172744935978053658}
--- !u!1 &8569242987132969498

2
Assets/Prefabs/UI/LobbyUserList.prefab


m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 1
m_PresetInfoIsWorld: 0
--- !u!114 &4463750083940306577
MonoBehaviour:
m_ObjectHideFlags: 0

4
Assets/Prefabs/UI/UserCardPanel.prefab


m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 26
m_fontSize: 70.95
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1

m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: '<color=#ADD8E6>Lobby
m_text: '<color=#ADD8E6>In Lobby
'
m_isRightToLeft: 0

51
Assets/Prefabs/UI/UserInteractionPanel.prefab


m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 13.3
m_fontSize: 13
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1

m_Calls:
- m_Target: {fileID: 2987822160017223264}
m_TargetAssemblyTypeName: LobbyRelaySample.UI.RecolorForLobbyType, LobbyRelaySample
m_MethodName: SetLobbyColor
m_Mode: 3
m_MethodName: ToggleOrange
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine

m_Father: {fileID: 5026269005358103012}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 208.5, y: -27.5}
m_SizeDelta: {x: 50, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5387756616337415243
CanvasRenderer:

m_Calls:
- m_Target: {fileID: 2987822160017223264}
m_TargetAssemblyTypeName: LobbyRelaySample.UI.RecolorForLobbyType, LobbyRelaySample
m_MethodName: SetLobbyColor
m_Mode: 3
m_MethodName: ToggleGreen
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine

m_Script: {fileID: 11500000, guid: 4079cd003fcd20c40a3bac78acf44b55, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UseLocalLobby: 1
m_toRecolor:
- {fileID: 5621563591146875997}
- {fileID: 4807901211461671397}

m_Father: {fileID: 5026269005358103012}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 49.5, y: -27.5}
m_SizeDelta: {x: 50, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8764544246360663793
CanvasRenderer:

m_Father: {fileID: 5026269005358103012}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 155.5, y: -27.5}
m_SizeDelta: {x: 50, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4202478155384707071
CanvasRenderer:

m_Calls:
- m_Target: {fileID: 2987822160017223264}
m_TargetAssemblyTypeName: LobbyRelaySample.UI.RecolorForLobbyType, LobbyRelaySample
m_MethodName: SetLobbyColor
m_Mode: 3
m_MethodName: ToggleWhite
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine

m_Calls:
- m_Target: {fileID: 2987822160017223264}
m_TargetAssemblyTypeName: LobbyRelaySample.UI.RecolorForLobbyType, LobbyRelaySample
m_MethodName: SetLobbyColor
m_Mode: 3
m_MethodName: ToggleBlue
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine

m_Father: {fileID: 5026269005358103012}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 102.5, y: -27.5}
m_SizeDelta: {x: 50, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4168724985671927024
CanvasRenderer:

23
Assets/Scenes/mainScene.unity


m_Script: {fileID: 11500000, guid: 78d292f3bd9f1614cb744dcb4fe3ac12, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &1056570786 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 3677991032586468434, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}
m_PrefabInstance: {fileID: 8628454959146822954}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 137b029a1106d7949a33106b02d1e837, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1176462898 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 3513144941912357516, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}

objectReference: {fileID: 0}
- target: {fileID: 1282422528845055840, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}
propertyPath: m_AnchoredPosition.x
value: -0.000003829884
value: 0
value: -0.00002864438
value: 0.000030517578
objectReference: {fileID: 0}
- target: {fileID: 1386321973193631240, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}
propertyPath: m_AnchorMax.x

propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6410570481816805232, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}
propertyPath: m_Name
value: LobbySpace
objectReference: {fileID: 0}
- target: {fileID: 6468178321825623330, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}
propertyPath: m_AnchorMax.y
value: 0

propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7570872190661528690, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}
propertyPath: m_onVisibilityChange.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1056570786}
- target: {fileID: 7591092274140645142, guid: 9aae991127b410c45a001ecd7f75311d, type: 3}
propertyPath: onValueChanged.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:

22
Assets/Scripts/GameLobby/Game/GameManager.cs


{
LobbyList.QueryState.Value = LobbyQueryState.Fetching;
var qr = await LobbyManager.RetrieveLobbyListAsync(m_lobbyColorFilter);
if (qr == null)
{
return;
}
if (qr != null)
SetCurrentLobbies(LobbyConverters.QueryToLocalList(qr));
else
LobbyList.QueryState.Value = LobbyQueryState.Error;
SetCurrentLobbies(LobbyConverters.QueryToLocalList(qr));
}
public async void QuickJoin()

public void SetLocalLobbyColor(int color)
{
if (m_LocalLobby.PlayerCount < 1)
return;
bool updatingLobby;
async void SendLocalLobbyData()
{

m_LocalLobby.onUserReadyChange = OnPlayersReady;
try
{
await JoinLobby();
await BindLobby();
}
catch (Exception exception)
{

async Task JoinLobby()
{
//Trigger UI Even when same value
m_LocalUser.IsHost.ForceSet(false);
await BindLobby();
}
async Task BindLobby()
{
await LobbyManager.BindLocalLobbyToRemote(m_LocalLobby.LobbyID.Value, m_LocalLobby);
m_LocalLobby.LocalLobbyState.onChanged += OnLobbyStateChanged;

7
Assets/Scripts/GameLobby/Game/LocalLobby.cs


public LocalPlayer GetLocalPlayer(int index)
{
if (PlayerCount < index)
return m_LocalPlayers[index];
return null;
return PlayerCount > index ? m_LocalPlayers[index] : null;
Debug.Log($"Adding User: {user.DisplayName.Value} - {user.ID.Value}");
Debug.Log($"Added User: {user.DisplayName.Value} - {user.ID.Value} to slot {index+1}/{PlayerCount}");
}
public void RemovePlayer(int playerIndex)

2
Assets/Scripts/GameLobby/Game/LocalPlayer.cs


{
IsHost.Value = false;
Emote.Value = EmoteType.None;
UserStatus.Value = LobbyRelaySample.PlayerStatus.Menu;
UserStatus.Value = PlayerStatus.Menu;
}
}
}

6
Assets/Scripts/GameLobby/Infrastructure/Actionvalue.cs


}
}
public void ForceSet(T value)
{
m_CachedValue = value;
onChanged?.Invoke(m_CachedValue);
}
public void SetNoCallback(T value)
{
m_CachedValue = value;

154
Assets/Scripts/GameLobby/Lobby/LobbyManager.cs


return true;
}
public RateLimiter GetRateLimit(RequestType type)
public ServiceRateLimiter GetRateLimit(RequestType type)
{
if (type == RequestType.Join)
return m_JoinCooldown;

// Rate Limits are posted here: https://docs.unity.com/lobby/rate-limits.html
RateLimiter m_QueryCooldown = new RateLimiter(1f);
RateLimiter m_CreateCooldown = new RateLimiter(3f);
RateLimiter m_JoinCooldown = new RateLimiter(3f);
RateLimiter m_QuickJoinCooldown = new RateLimiter(10f);
RateLimiter m_GetLobbyCooldown = new RateLimiter(1f);
RateLimiter m_DeleteLobbyCooldown = new RateLimiter(.2f);
RateLimiter m_UpdateLobbyCooldown = new RateLimiter(.3f);
RateLimiter m_UpdatePlayerCooldown = new RateLimiter(.3f);
RateLimiter m_LeaveLobbyOrRemovePlayer = new RateLimiter(.3f);
RateLimiter m_HeartBeatCooldown = new RateLimiter(6f);
ServiceRateLimiter m_QueryCooldown = new ServiceRateLimiter(1, 1f);
ServiceRateLimiter m_CreateCooldown = new ServiceRateLimiter(2, 6f);
ServiceRateLimiter m_JoinCooldown = new ServiceRateLimiter(2, 6f);
ServiceRateLimiter m_QuickJoinCooldown = new ServiceRateLimiter(1, 10f);
ServiceRateLimiter m_GetLobbyCooldown = new ServiceRateLimiter(1, 1f);
ServiceRateLimiter m_DeleteLobbyCooldown = new ServiceRateLimiter(2, 1f);
ServiceRateLimiter m_UpdateLobbyCooldown = new ServiceRateLimiter(5, 5f);
ServiceRateLimiter m_UpdatePlayerCooldown = new ServiceRateLimiter(5, 5f);
ServiceRateLimiter m_LeaveLobbyOrRemovePlayer = new ServiceRateLimiter(5, 1);
ServiceRateLimiter m_HeartBeatCooldown = new ServiceRateLimiter(5, 30);
#endregion

public async Task<Lobby> CreateLobbyAsync(string lobbyName, int maxPlayers, bool isPrivate,
LocalPlayer localUser)
{
if (m_CreateCooldown.IsInCooldown)
if (m_CreateCooldown.IsCoolingDown)
await m_CreateCooldown.WaitUntilCooldown();
await m_CreateCooldown.QueueUntilCooldown();
Debug.Log("Lobby - Creating");

public async Task<Lobby> JoinLobbyAsync(string lobbyId, string lobbyCode, LocalPlayer localUser)
{
if (m_JoinCooldown.IsInCooldown ||
if (m_JoinCooldown.IsCoolingDown ||
await m_JoinCooldown.WaitUntilCooldown();
Debug.Log($"{localUser.DisplayName}({localUser.ID}) Joining Lobby- {lobbyId} with {lobbyCode}");
await m_JoinCooldown.QueueUntilCooldown();
Debug.Log($"{localUser.DisplayName.Value}({localUser.ID.Value}) Joining Lobby- {lobbyId} / {lobbyCode}");
string uasId = AuthenticationService.Instance.PlayerId;
var playerData = CreateInitialPlayerData(localUser);

public async Task<Lobby> QuickJoinLobbyAsync(LocalPlayer localUser, LobbyColor limitToColor = LobbyColor.None)
{
//We dont want to queue a quickjoin
if (m_QuickJoinCooldown.IsInCooldown)
if (m_QuickJoinCooldown.IsCoolingDown)
await m_QuickJoinCooldown.WaitUntilCooldown();
await m_QuickJoinCooldown.QueueUntilCooldown();
Debug.Log("Lobby - Quick Joining.");
var filters = LobbyColorToFilters(limitToColor);
string uasId = AuthenticationService.Instance.PlayerId;

public async Task<QueryResponse> RetrieveLobbyListAsync(LobbyColor limitToColor = LobbyColor.None)
{
await m_QueryCooldown.WaitUntilCooldown();
var filters = LobbyColorToFilters(limitToColor);
var filters = LobbyColorToFilters(limitToColor);
if (m_QueryCooldown.TaskQueued)
return null;
await m_QueryCooldown.QueueUntilCooldown();
QueryLobbiesOptions queryOptions = new QueryLobbiesOptions
{

Debug.Log("Retrieving Lobby List");
return await LobbyService.Instance.QueryLobbiesAsync(queryOptions);
}

{
var playerIndex = lobbyPlayerChanges.Key;
var localPlayer = localLobby.GetLocalPlayer(playerIndex);
Debug.Log($"{localPlayer} at index {playerIndex} data changed");
var playerChanges = lobbyPlayerChanges.Value;
if (playerChanges.ConnectionInfoChanged.Changed)
{

if (playerChanges.LastUpdatedChanged.Changed)
{
var lastUpdated = playerChanges.LastUpdatedChanged.Value;
Debug.Log(
$"LastUpdated for {localPlayer.DisplayName.Value} changed to {lastUpdated}");
Debug.Log($"LastUpdated for {localPlayer.DisplayName.Value} changed to {lastUpdated}");
//There are changes on the Player
//There are changes on some of the changes in the player list of changes
if (changedValue.Changed)
{
if (changedValue.Removed)

{
if (!InLobby())
return null;
await m_GetLobbyCooldown.WaitUntilCooldown();
await m_GetLobbyCooldown.QueueUntilCooldown();
lobbyId ??= m_CurrentLobby.Id;
return m_CurrentLobby = await LobbyService.Instance.GetLobbyAsync(lobbyId);
}

await m_LeaveLobbyOrRemovePlayer.WaitUntilCooldown();
await m_LeaveLobbyOrRemovePlayer.QueueUntilCooldown();
if (!InLobby())
return;
string playerId = AuthenticationService.Instance.PlayerId;

{
if (!InLobby())
return;
await m_UpdatePlayerCooldown.WaitUntilCooldown();
Debug.Log("Lobby - Updating Player Data");
string playerId = AuthenticationService.Instance.PlayerId;
Dictionary<string, PlayerDataObject> dataCurr = new Dictionary<string, PlayerDataObject>();

dataCurr.Add(dataNew.Key, dataObj);
}
if (m_UpdatePlayerCooldown.TaskQueued)
return;
await m_UpdatePlayerCooldown.QueueUntilCooldown();
Debug.Log("Lobby - Updating Player Data");
UpdatePlayerOptions updateOptions = new UpdatePlayerOptions
{
Data = dataCurr,

m_CurrentLobby = await LobbyService.Instance.UpdatePlayerAsync(m_CurrentLobby.Id, playerId, updateOptions);
}
public async Task<Lobby> UpdatePlayerRelayInfoAsync(string lobbyID, string allocationId, string connectionInfo)
public async Task UpdatePlayerRelayInfoAsync(string lobbyID, string allocationId, string connectionInfo)
return null;
await m_UpdatePlayerCooldown.WaitUntilCooldown();
Debug.Log("Lobby - Relay Info (Player)");
return;
if (m_UpdatePlayerCooldown.TaskQueued)
return;
await m_UpdatePlayerCooldown.QueueUntilCooldown();
Debug.Log("Lobby - Relay Info (Player)");
UpdatePlayerOptions updateOptions = new UpdatePlayerOptions
{
Data = new Dictionary<string, PlayerDataObject>(),

return m_CurrentLobby = await LobbyService.Instance.UpdatePlayerAsync(lobbyID, playerId, updateOptions);
m_CurrentLobby = await LobbyService.Instance.UpdatePlayerAsync(lobbyID, playerId, updateOptions);
}
public async Task UpdateLobbyDataAsync(Dictionary<string, string> data)

await m_UpdateLobbyCooldown.WaitUntilCooldown();
Debug.Log("Lobby - Updating Lobby Data");
Dictionary<string, DataObject> dataCurr = m_CurrentLobby.Data ?? new Dictionary<string, DataObject>();

}
}
//We can still update the latest data to send to the service, but we will not send multiple UpdateLobbySyncCalls
if (m_UpdateLobbyCooldown.TaskQueued)
return;
await m_UpdateLobbyCooldown.QueueUntilCooldown();
Debug.Log("Lobby - Updating Lobby Data");
UpdateLobbyOptions updateOptions = new UpdateLobbyOptions { Data = dataCurr, IsLocked = shouldLock };
m_CurrentLobby = await LobbyService.Instance.UpdateLobbyAsync(m_CurrentLobby.Id, updateOptions);
}

if (!InLobby())
return;
await m_DeleteLobbyCooldown.WaitUntilCooldown();
await m_DeleteLobbyCooldown.QueueUntilCooldown();
Debug.Log("Lobby - Deleting Lobby");
await LobbyService.Instance.DeleteLobbyAsync(m_CurrentLobby.Id);

{
if (!InLobby())
return;
if (m_HeartBeatCooldown.IsInCooldown)
if (m_HeartBeatCooldown.IsCoolingDown)
await m_HeartBeatCooldown.WaitUntilCooldown();
await m_HeartBeatCooldown.QueueUntilCooldown();
Debug.Log("Lobby - Heartbeat");
await LobbyService.Instance.SendHeartbeatPingAsync(m_CurrentLobby.Id);

#endregion
}
//Manages the Cooldown for each service call.
//Manages the Amount of times you can hit a service call.
public class RateLimiter
//Will Queue the latest overflow task for when the cooldown ends.
//Created to mimic the way rate limits are implemented Here: https://docs.unity.com/lobby/rate-limits.html
public class ServiceRateLimiter
public readonly float cooldownSeconds;
public readonly int pingBufferMS;
public bool TaskQueued { get; private set; } = false;
readonly int m_ServiceCallTimes;
bool m_CoolingDown = false;
int m_TaskCounter;
public RateLimiter(float cooldownSeconds, int pingBuffer = 100)
public ServiceRateLimiter(int callTimes, float coolDown, int pingBuffer = 100)
this.cooldownSeconds = cooldownSeconds;
pingBufferMS = pingBuffer;
m_ServiceCallTimes = callTimes;
m_TaskCounter = m_ServiceCallTimes;
Mathf.CeilToInt(this.cooldownSeconds * 1000) +
pingBufferMS;
Mathf.CeilToInt(coolDown * 1000) +
pingBuffer;
public async Task WaitUntilCooldown()
public async Task QueueUntilCooldown()
//No Queue!
if (!m_IsInCooldown)
if (!m_CoolingDown)
CooldownAsync();
ParallelCooldownAsync();
}
m_TaskCounter--;
if (m_TaskCounter > 0)
{
while (m_IsInCooldown)
if (!TaskQueued)
TaskQueued = true;
else
return;
while (m_CoolingDown)
async Task CooldownAsync()
async Task ParallelCooldownAsync()
IsInCooldown = true;
IsCoolingDown = true;
IsInCooldown = false;
IsCoolingDown = false;
TaskQueued = false;
m_TaskCounter = m_ServiceCallTimes;
bool m_IsInCooldown = false;
public bool IsInCooldown
public bool IsCoolingDown
get => m_IsInCooldown;
get => m_CoolingDown;
if (m_IsInCooldown != value)
if (m_CoolingDown != value)
m_IsInCooldown = value;
onCooldownChange?.Invoke(m_IsInCooldown);
m_CoolingDown = value;
onCooldownChange?.Invoke(m_CoolingDown);
}
}
}

6
Assets/Scripts/GameLobby/Tests/PlayMode/LobbyRoundtripTests.cs


[UnityTest]
public IEnumerator CooldownTest()
{
var rateLimiter = new RateLimiter(3);
var rateLimiter = new ServiceRateLimiter(1, 3);
yield return AsyncTestHelper.Await(async () => await rateLimiter.WaitUntilCooldown());
yield return AsyncTestHelper.Await(async () => await rateLimiter.QueueUntilCooldown());
yield return AsyncTestHelper.Await(async () => await rateLimiter.WaitUntilCooldown());
yield return AsyncTestHelper.Await(async () => await rateLimiter.QueueUntilCooldown());
timer.Stop();
var elapsedMS = timer.ElapsedMilliseconds;
Debug.Log($"Cooldown took {elapsedMS}/{rateLimiter.coolDownMS} milliseconds.");

36
Assets/Scripts/GameLobby/UI/InLobbyUserUI.cs


public string UserId { get; set; }
LocalPlayer m_LocalPlayer;
public void SetUser(LocalPlayer myLocalPlayer)
public void SetUser(LocalPlayer localPlayer)
m_LocalPlayer = myLocalPlayer;
m_LocalPlayer = localPlayer;
UserId = localPlayer.ID.Value;
SetIsHost(localPlayer.IsHost.Value);
SetEmote(localPlayer.Emote.Value);
SetUserStatus(localPlayer.UserStatus.Value);
SetDisplayName(m_LocalPlayer.DisplayName.Value);
SetDisplayName(m_LocalPlayer.DisplayName.Value);
UserId = myLocalPlayer.ID.Value;
public void SubscribeToPlayerUpdates()
void SubscribeToPlayerUpdates()
{
m_LocalPlayer.DisplayName.onChanged += SetDisplayName;
m_LocalPlayer.UserStatus.onChanged += SetUserStatus;

public void UnsubscribeToPlayerUpdates()
void UnsubscribeToPlayerUpdates()
m_LocalPlayer.DisplayName.onChanged -= SetDisplayName;
m_LocalPlayer.UserStatus.onChanged -= SetUserStatus;
m_LocalPlayer.Emote.onChanged -= SetEmote;
m_LocalPlayer.IsHost.onChanged -= SetIsHost;
if (m_LocalPlayer == null)
return;
if (m_LocalPlayer.DisplayName?.onChanged != null)
m_LocalPlayer.DisplayName.onChanged -= SetDisplayName;
if (m_LocalPlayer.UserStatus?.onChanged != null)
m_LocalPlayer.UserStatus.onChanged -= SetUserStatus;
if (m_LocalPlayer.Emote?.onChanged != null)
m_LocalPlayer.Emote.onChanged -= SetEmote;
if (m_LocalPlayer.IsHost?.onChanged != null)
m_LocalPlayer.IsHost.onChanged -= SetIsHost;
if (m_LocalPlayer == null)
return;
SetEmote(EmoteType.None);
SetUserStatus(PlayerStatus.Lobby);
Hide();
UnsubscribeToPlayerUpdates();
m_LocalPlayer = null;

}
}
}
}
}

73
Assets/Scripts/GameLobby/UI/JoinMenuUI.cs


using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.Serialization;

/// </summary>
public class JoinMenuUI : UIPanelBase
{
[FormerlySerializedAs("m_LobbyButtonPrefab")]
[SerializeField]
LobbyEntryUI m_LobbyEntryPrefab;

/// Key: Lobby ID, Value Lobby UI
/// </summary>
Dictionary<string, LobbyEntryUI> m_LobbyButtons = new Dictionary<string, LobbyEntryUI>();
Dictionary<string, LocalLobby> m_LocalLobby = new Dictionary<string, LocalLobby>();
public override void Start()
{
base.Start();

void OnLobbyListChanged(Dictionary<string, LocalLobby> lobbyList)
{
///Check for new entries, We take CurrentLobbies as the source of truth
List<string> previousKeys = new List<string>(m_LobbyButtons.Keys);
foreach (var codeLobby in lobbyList)
{
var lobbyCodeKey = codeLobby.Key;
var lobbyData = codeLobby.Value;
if (!m_LobbyButtons.ContainsKey(lobbyCodeKey))
{
if (CanDisplay(lobbyData))
AddNewLobbyButton(lobbyCodeKey, lobbyData);
}
else
{
if (CanDisplay(lobbyData))
SetLobbyButton(lobbyCodeKey, lobbyData);
else
RemoveLobbyButton(lobbyData);
}
previousKeys.Remove(lobbyCodeKey);
}
foreach (string key in previousKeys) // Need to remove any lobbies from the list that no longer exist.
RemoveLobbyButton(m_LocalLobby[key]);
PruneMissingLobbies(lobbyList.Keys.ToList());
PopulateLobbyButtonList(lobbyList);
}
public void JoinMenuChangedVisibility(bool show)

Manager.QuickJoin();
}
void PruneMissingLobbies(List<string> lobbyIDs)
{
var removalList = new List<string>();
foreach (var lobbyID in lobbyIDs)
{
if (!lobbyIDs.Contains(lobbyID))
removalList.Add(lobbyID);
}
foreach (var lobbyID in removalList)
RemoveLobbyButton(lobbyID);
}
void PopulateLobbyButtonList(Dictionary<string, LocalLobby> lobbyList)
{
///Check for new entries, We take CurrentLobbies as the source of truth
foreach (var lobbyKVP in lobbyList)
{
var lobbyID = lobbyKVP.Key;
var lobby = lobbyKVP.Value;
if (!m_LobbyButtons.ContainsKey(lobbyID))
{
if (CanDisplay(lobby))
AddNewLobbyButton(lobbyID, lobby);
}
else
{
if (CanDisplay(lobby))
SetLobbyButton(lobbyID, lobby);
else
RemoveLobbyButton(lobbyID);
}
}
}
bool CanDisplay(LocalLobby lobby)
{
return lobby.LocalLobbyState.Value == LobbyState.Lobby && !lobby.Private.Value;

var lobbyButtonInstance = Instantiate(m_LobbyEntryPrefab, m_LobbyButtonParent);
lobbyButtonInstance.onLobbyPressed.AddListener(LobbyButtonSelected);
m_LobbyButtons.Add(lobbyCode, lobbyButtonInstance);
m_LocalLobby.Add(lobbyCode, lobby);
lobbyButtonInstance.SetLobby(lobby);
}
void SetLobbyButton(string lobbyCode, LocalLobby lobby)

void RemoveLobbyButton(LocalLobby lobby)
void RemoveLobbyButton(string lobbyID)
var lobbyID = lobby.LobbyID.Value;
m_LocalLobby.Remove(lobbyID);
}
}

4
Assets/Scripts/GameLobby/UI/LobbyEntryUI.cs


using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Events;

/// </summary>
public class LobbyEntryUI : MonoBehaviour
{
[SerializeField]
ColorLobbyUI m_ColorLobbyUI;
[SerializeField]
TMP_Text lobbyNameText;
[SerializeField]

m_Lobby = lobby;
SetLobbyname(m_Lobby.LobbyName.Value);
SetLobbyCount(m_Lobby.PlayerCount);
m_ColorLobbyUI.SetLobby(lobby);
m_Lobby.LobbyName.onChanged += SetLobbyname;
m_Lobby.onUserJoined += (_) =>
{

59
Assets/Scripts/GameLobby/UI/RateLimitVisibility.cs


namespace LobbyRelaySample.UI
{
/// <summary>
/// Observes the Lobby request rate limits and changes the visibility of a UIPanelBase to suit.
/// E.g. the refresh button on the Join menu should be inactive after a refresh for long enough to avoid the lobby query rate limit.
/// </summary>
public class RateLimitVisibility : MonoBehaviour
{
[SerializeField] UIPanelBase m_target;
[SerializeField] float m_alphaWhenHidden = 0.5f;
[SerializeField] LobbyManager.RequestType m_requestType;
/// <summary>
/// Observes the Lobby request rate limits and changes the visibility of a UIPanelBase to suit.
/// E.g. the refresh button on the Join menu should be inactive after a refresh for long enough to avoid the lobby query rate limit.
/// </summary>
public class RateLimitVisibility : MonoBehaviour
{
[SerializeField]
UIPanelBase m_target;
[SerializeField]
float m_alphaWhenHidden = 0.5f;
[SerializeField]
LobbyManager.RequestType m_requestType;
void Start()
{
GameManager.Instance.LobbyManager.GetRateLimit(m_requestType).onCooldownChange += UpdateVisibility;
}
void Start()
{
GameManager.Instance.LobbyManager.GetRateLimit(m_requestType).onCooldownChange += UpdateVisibility;
}
void OnDestroy()
{
if (GameManager.Instance == null || GameManager.Instance.LobbyManager == null)
return;
GameManager.Instance.LobbyManager.GetRateLimit(m_requestType).onCooldownChange -= UpdateVisibility;
}
void OnDestroy()
{
if (GameManager.Instance == null || GameManager.Instance.LobbyManager == null)
return;
GameManager.Instance.LobbyManager.GetRateLimit(m_requestType).onCooldownChange -= UpdateVisibility;
}
void UpdateVisibility(bool isCoolingDown)
{
if (isCoolingDown)
m_target.Hide(m_alphaWhenHidden);
else
m_target.Show();
}
}
}
void UpdateVisibility(bool isCoolingDown)
{
if (isCoolingDown)
m_target.Hide(m_alphaWhenHidden);
else
m_target.Show();
}
}
}

6
Assets/Scripts/GameLobby/UI/UserStateVisibilityUI.cs


{
base.Start();
var localUser = await Manager.AwaitLocalUserInitialization();
localUser.IsHost.onChanged += OnUserHostChanged;
localUser.UserStatus.onChanged += OnUserStatusChanged;

{
m_HasPermissions = true;
}
if (Permissions.HasFlag(UserPermission.Client) && !isHost)
{
m_HasPermissions = true;

void CheckVisibility()
{
}
}

71
Assets/Scripts/GameLobby/UI/ColorLobbyUI.cs


using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
namespace LobbyRelaySample.UI
{
/// <summary>
/// We want to illustrate filtering the lobby list by some arbitrary variable. This will allow the lobby host to choose a color for the lobby, and will display a lobby's current color.
/// (Note that this isn't sent over Relay to other clients for realtime updates.)
/// </summary>
public class ColorLobbyUI : MonoBehaviour
{
public bool m_UseLocalLobby;
static readonly Color s_orangeColor = new Color(0.83f, 0.36f, 0);
static readonly Color s_greenColor = new Color(0, 0.61f, 0.45f);
static readonly Color s_blueColor = new Color(0.0f, 0.44f, 0.69f);
static readonly Color[] s_colorsOrdered = new Color[]
{ new Color(0.9f, 0.9f, 0.9f, 0.7f), s_orangeColor, s_greenColor, s_blueColor };
[SerializeField]
Graphic[] m_toRecolor;
LocalLobby m_lobby;
void Start()
{
if (m_UseLocalLobby)
SetLobby(GameManager.Instance.LocalLobby);
}
public void SetLobby(LocalLobby lobby)
{
ChangeColors(lobby.LocalLobbyColor.Value);
lobby.LocalLobbyColor.onChanged += ChangeColors;
}
public void ToggleWhite(bool toggle)
{
if (!toggle)
return;
GameManager.Instance.SetLocalLobbyColor(0);
}
public void ToggleOrange(bool toggle)
{
if (!toggle)
return;
GameManager.Instance.SetLocalLobbyColor(1);
}
public void ToggleGreen(bool toggle)
{
if (!toggle)
return;
GameManager.Instance.SetLocalLobbyColor(2);
}
public void ToggleBlue(bool toggle)
{
if (!toggle)
return;
GameManager.Instance.SetLocalLobbyColor(3);
}
void ChangeColors(LobbyColor lobbyColor)
{
Color color = s_colorsOrdered[(int)lobbyColor];
foreach (Graphic graphic in m_toRecolor)
graphic.color = new Color(color.r, color.g, color.b, graphic.color.a);
}
}
}

44
Assets/Scripts/GameLobby/UI/RecolorForLobbyType.cs


using UnityEngine;
using UnityEngine.UI;
namespace LobbyRelaySample.UI
{
/// <summary>
/// We want to illustrate filtering the lobby list by some arbitrary variable. This will allow the lobby host to choose a color for the lobby, and will display a lobby's current color.
/// (Note that this isn't sent over Relay to other clients for realtime updates.)
/// </summary>
public class RecolorForLobbyType : MonoBehaviour
{
static readonly Color s_orangeColor = new Color(0.8352942f, 0.3686275f, 0);
static readonly Color s_greenColor = new Color(0, 0.6196079f, 0.4509804f);
static readonly Color s_blueColor = new Color(0.0f, 0.4470589f, 0.6980392f);
static readonly Color[] s_colorsOrdered = new Color[]
{ new Color(0.9f, 0.9f, 0.9f, 0.7f), s_orangeColor, s_greenColor, s_blueColor };
[SerializeField]
Graphic[] m_toRecolor;
LocalLobby m_lobby;
void Start()
{
m_lobby = GameManager.Instance.LocalLobby;
m_lobby.LocalLobbyColor.onChanged += ChangeColors;
}
/// <summary>
/// Called in-editor by toggles to set the color of the lobby.
/// Triggers the ChangeColors method above
/// </summary>
public void SetLobbyColor(int color)
{
GameManager.Instance.SetLocalLobbyColor(color);
}
void ChangeColors(LobbyColor lobbyColor)
{
Color color = s_colorsOrdered[(int)lobbyColor];
foreach (Graphic graphic in m_toRecolor)
graphic.color = new Color(color.r, color.g, color.b, graphic.color.a);
}
}
}

/Assets/Scripts/GameLobby/UI/RecolorForLobbyType.cs.meta → /Assets/Scripts/GameLobby/UI/ColorLobbyUI.cs.meta

正在加载...
取消
保存