Skip to content

Commit

Permalink
feat: HeadlessAutoStart and HeadlessFrameLimiter (#318)
Browse files Browse the repository at this point in the history
* feat: HeadlessAutoStart component

* feat: HeadlessFrameLimiter

* remove from NetMan and misc cleanup of useless virtual OnDestroy

* fix refs and tests

* fix poor comments

* remove useless ifdef and add required using

* fix potential NRE

* add simple tests

* fix smells
  • Loading branch information
uweeby committed Aug 1, 2020
1 parent dc8633f commit ce6ef50
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 75 deletions.
28 changes: 28 additions & 0 deletions Assets/Mirror/Components/HeadlessAutoStart.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using UnityEngine;
using UnityEngine.Rendering;

namespace Mirror
{
public class HeadlessAutoStart : MonoBehaviour
{
public NetworkServer server;

/// <summary>
/// Automatically invoke StartServer()
/// <para>If the application is a Server Build or run with the -batchMode ServerRpc line arguement, StartServer is automatically invoked.</para>
/// </summary>
[Tooltip("Should the server auto-start when the game is started in a headless build?")]
public bool startOnHeadless = true;

void Start()
{
// headless mode? then start the server
// can't do this in Awake because Awake is for initialization.
// some transports might not be ready until Start.
if (server && SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null && startOnHeadless)
{
_ = server.ListenAsync();
}
}
}
}
11 changes: 11 additions & 0 deletions Assets/Mirror/Components/HeadlessAutoStart.cs.meta

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

29 changes: 29 additions & 0 deletions Assets/Mirror/Components/HeadlessFrameLimiter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using UnityEngine;
using UnityEngine.Rendering;

namespace Mirror
{
public class HeadlessFrameLimiter : MonoBehaviour
{
static readonly ILogger logger = LogFactory.GetLogger<NetworkManager>();

/// <summary>
/// Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.
/// </summary>
[Tooltip("Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")]
public int serverTickRate = 30;

/// <summary>
/// Set the frame rate for a headless server.
/// </summary>
public void Start()
{
// set a fixed tick rate instead of updating as often as possible
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null)
{
Application.targetFrameRate = serverTickRate;
if (logger.logEnabled) logger.Log("Server Tick Rate set to: " + Application.targetFrameRate + " Hz.");
}
}
}
}
11 changes: 11 additions & 0 deletions Assets/Mirror/Components/HeadlessFrameLimiter.cs.meta

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

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class BenchmarkNetworkManager : NetworkManager

NetworkSceneManager sceneManager;

public override void Start()
public void Start()
{
sceneManager = GetComponent<NetworkSceneManager>();
}
Expand Down
8 changes: 8 additions & 0 deletions Assets/Mirror/Examples/Prefabs.meta

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

2 changes: 0 additions & 2 deletions Assets/Mirror/Runtime/INetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,5 @@ public interface INetworkManager
void StopServer();

void StopClient();

void OnDestroy();
}
}
69 changes: 0 additions & 69 deletions Assets/Mirror/Runtime/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;

namespace Mirror
{
Expand All @@ -17,19 +16,6 @@ public class NetworkManager : MonoBehaviour, INetworkManager
{
static readonly ILogger logger = LogFactory.GetLogger<NetworkManager>();

/// <summary>
/// Automatically invoke StartServer()
/// <para>If the application is a Server Build or run with the -batchMode ServerRpc line arguement, StartServer is automatically invoked.</para>
/// </summary>
[Tooltip("Should the server auto-start when the game is started in a headless build?")]
public bool startOnHeadless = true;

/// <summary>
/// Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.
/// </summary>
[Tooltip("Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")]
public int serverTickRate = 30;

public NetworkServer server;
public NetworkClient client;

Expand All @@ -50,37 +36,11 @@ public class NetworkManager : MonoBehaviour, INetworkManager
/// </summary>
public UnityEvent OnStopHost = new UnityEvent();

#region Unity Callbacks

/// <summary>
/// virtual so that inheriting classes' Start() can call base.Start() too
/// </summary>
public virtual void Start()
{
logger.Log("Thank you for using Mirror! https://mirror-networking.com");

// headless mode? then start the server
// can't do this in Awake because Awake is for initialization.
// some transports might not be ready until Start.
//
// (tick rate is applied in StartServer!)
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null && startOnHeadless)
{
_ = StartServer();
}
}

#endregion

#region Start & Stop

// full server setup code, without spawning objects yet
async Task SetupServer()
{
logger.Log("NetworkManager SetupServer");

ConfigureServerFrameRate();

// start listening to network connections
await server.ListenAsync();
}
Expand Down Expand Up @@ -167,34 +127,5 @@ public void StopClient()
{
client.Disconnect();
}

/// <summary>
/// Set the frame rate for a headless server.
/// <para>Override if you wish to disable the behavior or set your own tick rate.</para>
/// </summary>
public virtual void ConfigureServerFrameRate()
{
// set a fixed tick rate instead of updating as often as possible
// * if not in Editor (it doesn't work in the Editor)
// * if not in Host mode
#if !UNITY_EDITOR
if (!client.Active && SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null)
{
Application.targetFrameRate = serverTickRate;
if (logger.logEnabled) logger.Log("Server Tick Rate set to: " + Application.targetFrameRate + " Hz.");
}
#endif
}

/// <summary>
/// virtual so that inheriting classes' OnDestroy() can call base.OnDestroy() too
/// </summary>
public virtual void OnDestroy()
{
logger.Log("NetworkManager destroyed");
}

#endregion

}
}
32 changes: 32 additions & 0 deletions Assets/Mirror/Tests/Editor/HeadlessAutoStartTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using UnityEngine;
using NUnit.Framework;
using Object = UnityEngine.Object;

namespace Mirror.Tests
{
[TestFixture]
public class HeadlessAutoStartTest : MonoBehaviour
{
protected GameObject testGO;
protected HeadlessAutoStart comp;

[SetUp]
public void Setup()
{
testGO = new GameObject();
comp = testGO.AddComponent<HeadlessAutoStart>();
}

[TearDown]
public void Teardown()
{
Object.DestroyImmediate(testGO);
}

[Test]
public void StartOnHeadlessValue()
{
Assert.That(comp.startOnHeadless, Is.True);
}
}
}
11 changes: 11 additions & 0 deletions Assets/Mirror/Tests/Editor/HeadlessAutoStartTest.cs.meta

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

32 changes: 32 additions & 0 deletions Assets/Mirror/Tests/Editor/HeadlessFrameLimiterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using UnityEngine;
using NUnit.Framework;
using Object = UnityEngine.Object;

namespace Mirror.Tests
{
[TestFixture]
public class HeadlessFrameLimiterTest : MonoBehaviour
{
protected GameObject testGO;
protected HeadlessFrameLimiter comp;

[SetUp]
public void Setup()
{
testGO = new GameObject();
comp = testGO.AddComponent<HeadlessFrameLimiter>();
}

[TearDown]
public void Teardown()
{
Object.DestroyImmediate(testGO);
}

[Test]
public void StartOnHeadlessValue()
{
Assert.That(comp.serverTickRate, Is.EqualTo(30));
}
}
}
11 changes: 11 additions & 0 deletions Assets/Mirror/Tests/Editor/HeadlessFrameLimiterTest.cs.meta

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

1 change: 0 additions & 1 deletion Assets/Mirror/Tests/Runtime/HostSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public class HostSetup<T> where T : NetworkBehaviour
manager.server = networkManagerGo.GetComponent<NetworkServer>();
server = manager.server;
client = manager.client;
manager.startOnHeadless = false;
sceneManager.client = client;
sceneManager.server = server;
Expand Down
2 changes: 0 additions & 2 deletions Assets/Mirror/Tests/Runtime/NetworkManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ public class NetworkManagerTest : HostSetup<MockComponent>
[Test]
public void VariableTest()
{
Assert.That(manager.startOnHeadless, Is.False);
Assert.That(manager.serverTickRate, Is.EqualTo(30));
Assert.That(manager.server.MaxConnections, Is.EqualTo(4));
}

Expand Down

0 comments on commit ce6ef50

Please sign in to comment.