Skip to content

Commit

Permalink
feat: refactoring LobbyReady to use new features
Browse files Browse the repository at this point in the history
BREAKING CHANGE: LobbyReady and ReadyCheck components changed

fix: using Start instead so Server can be added by test

test: trying to fix lobby test

fix: fixing lobby ready

setting syncvar in another asm doesn't work all the time. Unity ILPP is weird
  • Loading branch information
James-Frowen committed Apr 24, 2023
1 parent 8bf12dd commit b9e13e3
Show file tree
Hide file tree
Showing 10 changed files with 431 additions and 143 deletions.
71 changes: 55 additions & 16 deletions Assets/Mirage/Components/LobbyReady.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,81 @@
using Mirage.Logging;
using UnityEngine;

namespace Mirage
namespace Mirage.Components
{
public class LobbyReady : MonoBehaviour
{
private static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkServer));
private static readonly ILogger logger = LogFactory.GetLogger<LobbyReady>();
private static readonly List<INetworkPlayer> sendCache = new List<INetworkPlayer>();

public List<ObjectReady> ObjectReadyList = new List<ObjectReady>();
public NetworkServer Server;
public Dictionary<NetworkIdentity, ReadyCheck> Players = new Dictionary<NetworkIdentity, ReadyCheck>();

// just a cached memory area where we can collect connections
// for broadcasting messages
private static readonly List<INetworkPlayer> playerCache = new List<INetworkPlayer>();
private void Start()
{
Server.Started.AddListener(OnServerStarted);
}

private void OnServerStarted()
{
Server.World.AddAndInvokeOnSpawn(OnSpawn);
Server.World.onUnspawn += OnUnspawn;
}

private void OnSpawn(NetworkIdentity obj)
{
if (obj.TryGetComponent<ReadyCheck>(out var readyCheck))
{
Players.Add(obj, readyCheck);
}
}

private void OnUnspawn(NetworkIdentity obj)
{
Players.Remove(obj);
}

public void SetAllClientsNotReady()
{
foreach (var obj in ObjectReadyList)
foreach (var obj in Players.Values)
{
obj.SetClientNotReady();
obj.SetReady(false);
}
}

public void SendToReady<T>(NetworkIdentity identity, T msg, bool includeOwner = true, Channel channelId = Channel.Reliable)
/// <summary>
/// Send a message to players that are ready on check, or not ready if <paramref name="sendToReady"/> fakse
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="msg"></param>
/// <param name="sendToReady">Use to send message no not ready players instead, not this doesn't check server for players with out character, only players with PlayerReadyCheck on their character</param>
/// <param name="exclude">Add Identity to exclude here, useful when you want to send to all players except the owner</param>
/// <param name="channelId"></param>
public void SendToReady<T>(T msg, bool sendToReady = true, NetworkIdentity exclude = null, Channel channelId = Channel.Reliable)
{
if (logger.LogEnabled()) logger.Log("Server.SendToReady msgType:" + typeof(T));
if (logger.LogEnabled()) logger.Log("LobbyReady.SendToReady msgType:" + typeof(T));

playerCache.Clear();
sendCache.Clear();

foreach (var objectReady in ObjectReadyList)
foreach (var kvp in Players)
{
var isOwner = objectReady.Identity == identity;
if ((!isOwner || includeOwner) && objectReady.IsReady)
var identity = kvp.Key;
var readyCheck = kvp.Value;

if (identity == exclude)
continue;
if (identity.Owner == null)
continue;

// check if IsReady is matching sendToReady
// if both are false we also want to send, eg sending too all not ready
if (readyCheck.IsReady == sendToReady)
{
playerCache.Add(objectReady.Identity.Owner);
sendCache.Add(identity.Owner);
}
}

NetworkServer.SendToMany(playerCache, msg, channelId);
NetworkServer.SendToMany(sendCache, msg, channelId);
}
}
}
32 changes: 0 additions & 32 deletions Assets/Mirage/Components/ObjectReady.cs

This file was deleted.

26 changes: 26 additions & 0 deletions Assets/Mirage/Components/ReadyCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;

namespace Mirage.Components
{
/// <summary>
/// Simple component to track if a player is ready in a lobby
/// <para>
/// To best use this component Set Sync Direction from owner to server
/// </para>
/// </summary>
public class ReadyCheck : NetworkBehaviour
{
public event Action<bool> OnReadyChanged;

[SyncVar(hook = nameof(OnReadyChanged), invokeHookOnServer = true)]
private bool _isReady;

public bool IsReady => _isReady;

// note need a methods to set syncvar, otherwise scripts in another asmdef will not set if via weaver
public void SetReady(bool ready)
{
_isReady = ready;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 77 additions & 0 deletions Assets/Mirage/Samples~/Snippets/LobbyReadyCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Linq;
using Mirage.Components;
using UnityEngine;
using UnityEngine.UI;

namespace Mirage.Snippets.LobbyReadyCheck
{
// CodeEmbed-Start: send-to-ready
[NetworkMessage]
// Make sure to regieter message on client
public struct MyMessage
{
public string message;
}

public class LobbyController : MonoBehaviour
{
public LobbyReady LobbyReady;

public void SendToReady()
{
var myMessage = new MyMessage { message = "Hello, world!" };
// Send message to ready players
LobbyReady.SendToReady(myMessage);
}
}
// CodeEmbed-End: send-to-ready

public class LobbyController2 : MonoBehaviour
{
public LobbyReady LobbyReady;

// CodeEmbed-Start: send-to-not-ready
public void SendToNotReady()
{
var myMessage = new MyMessage { message = "Hello, world!" };
// Send message to ready players
LobbyReady.SendToReady(myMessage, sendToReady: false);
}
// CodeEmbed-End: send-to-not-ready

// CodeEmbed-Start: set-all-not-ready
public void ClearReady()
{
LobbyReady.SetAllClientsNotReady();
}
// CodeEmbed-End: set-all-not-ready

public void SetReady()
{
var readyCheck = LobbyReady.Players.First().Value;
// CodeEmbed-Start: set-ready
readyCheck.SetReady(true);
// CodeEmbed-End: set-ready
}
}

// CodeEmbed-Start: ready-ui
public class ReadyUI : MonoBehaviour
{
public ReadyCheck ReadyCheck;
public Image Image;

public void Start()
{
ReadyCheck.OnReadyChanged += OnReadyChanged;
// invoke right away to set the current value
OnReadyChanged(ReadyCheck.IsReady);
}

private void OnReadyChanged(bool ready)
{
Image.color = ready ? Color.green : Color.red;
}
}
// CodeEmbed-End: ready-ui
}
11 changes: 11 additions & 0 deletions Assets/Mirage/Samples~/Snippets/LobbyReadyCheck.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b9e13e3

Please sign in to comment.