Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dedicated server support first pass - part 2/2 New DGS flow [MTT-1936] #696

Draft
wants to merge 17 commits into
base: sam/feat/dedicated-server-support-review/1-manual-stripping
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
/[Ll]ogs/
/[Uu]ser[Ss]ettings/

/.Editor

# output dir
/Bin/

Expand Down
5 changes: 3 additions & 2 deletions .yamato/_triggers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ pull_request_trigger:
{% for platform in test_platforms -%}
# desktop platforms
- .yamato/project-tests.yml#test_{{ project.name }}_{{ project.test_editors.first }}_{{ platform.name }}
{% endfor -%}
{% endfor -%} # platform
# iOS
- .yamato/mobile-build-and-run.yml#mobile_test_ios_{{ project.name }}_{{ project.test_editors.first }}
# Android
- .yamato/mobile-build-and-run.yml#mobile_test_android_{{ project.name }}_{{ project.test_editors.first }}
{% endfor -%}
{% endfor -%} # projects

triggers:
cancel_old_ci: true
pull_requests:
Expand Down
2 changes: 1 addition & 1 deletion .yamato/project-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ test_{{ project.name }}_{{ editor }}_{{ platform.name }}:
- npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
- pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- unity-downloader-cli -u {{ editor }} -c editor -w --fast
- upm-ci project test -u {{ editor }} --project-path {{ project.path }} --type project-tests --extra-utr-arg=--testfilter=Unity.Multiplayer.Samples.BossRoom.Tests.Runtime
- upm-ci project test -u {{ editor }} --project-path {{ project.path }} --type project-tests --extra-utr-arg=--testfilter="Unity.BossRoom.*\;Unity.Multiplayer.Samples.Utilities.Tests.*" {{ platform.extra-utr-args }}
artifacts:
logs:
paths:
Expand Down
7 changes: 7 additions & 0 deletions .yamato/project.metafile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ test_platforms:
flavor: b1.large
editorpath: .Editor/Unity
utr: ./utr
- name: ubuntu-server
type: Unity::VM
image: package-ci/ubuntu:stable
flavor: b1.large
editorpath: .Editor/Unity
utr: ./utr
extra-utr-args: --extra-editor-arg="-standaloneBuildSubtarget" --extra-editor-arg="Server"

# Projects within the repository that will be tested. Name will be used
# for job ids, so it should not contain spaces/non-supported characters
Expand Down
50 changes: 50 additions & 0 deletions Assets/Prefabs/State/DSLobbyManagementState.prefab
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &483784040165852385
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8317007143651163113}
- component: {fileID: 8885455575253120871}
m_Layer: 0
m_Name: DSLobbyManagementState
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8317007143651163113
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 483784040165852385}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 27.0119, y: -29.155869, z: 13.674866}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8885455575253120871
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 483784040165852385}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0d0b37f76122149628ae8450dde334a4, type: 3}
m_Name:
m_EditorClassIdentifier:
parentReference:
TypeName: Unity.Multiplayer.Samples.BossRoom.Shared.ApplicationController
autoRun: 1
autoInjectGameObjects: []
7 changes: 7 additions & 0 deletions Assets/Prefabs/State/DSLobbyManagementState.prefab.meta

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

3 changes: 3 additions & 0 deletions Assets/Scenes/DedicatedServerLobbyManagement.unity
Git LFS file not shown
7 changes: 7 additions & 0 deletions Assets/Scenes/DedicatedServerLobbyManagement.unity.meta

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

4 changes: 2 additions & 2 deletions Assets/Scenes/PostGame.unity
Git LFS file not shown
25 changes: 24 additions & 1 deletion Assets/Scripts/ApplicationLifecycle/ApplicationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ protected override void Configure(IContainerBuilder builder)
builder.RegisterEntryPoint<LobbyServiceFacade>(Lifetime.Singleton).AsSelf();
}

#if UNITY_EDITOR && UNITY_SERVER
void OnGUI()
{
var styleToUse = GUI.skin.label;
styleToUse.fontSize = 50;
styleToUse.alignment = TextAnchor.LowerLeft;
var textToDisplay = "Dedicated Server Running";
var textWidth = styleToUse.fontSize * textToDisplay.Length;
GUI.Label(new Rect(10, 10, textWidth, styleToUse.fontSize * 2), textToDisplay, styleToUse);
}
#endif

private void Start()
{
m_LocalLobby = Container.Resolve<LocalLobby>();
Expand All @@ -82,13 +94,24 @@ private void Start()
DontDestroyOnLoad(gameObject);
DontDestroyOnLoad(m_UpdateRunner.gameObject);
Application.targetFrameRate = 120;
SceneManager.LoadScene("MainMenu");

if (DedicatedServerUtilities.IsServerBuildTarget)
{
// skip main menu and start IP server directly
SceneManager.LoadScene(SceneNames.DedicatedServerLobbyManagement);
}
else
{
SceneManager.LoadScene(SceneNames.StartupClient, LoadSceneMode.Additive);
SceneManager.LoadScene(SceneNames.MainMenu);
}
}

protected override void OnDestroy()
{
m_Subscriptions?.Dispose();
m_LobbyServiceFacade?.EndTracking();

base.OnDestroy();
}

Expand Down
39 changes: 35 additions & 4 deletions Assets/Scripts/ConnectionManagement/ConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ public class ConnectionPayload
/// </summary>
public class ConnectionManager : MonoBehaviour
{
public enum ServerType : byte
{
Undefined = 0,
DedicatedServer,
ClientHostedServer
}

ConnectionState m_CurrentState;

[SerializeField]
Expand All @@ -74,8 +81,12 @@ public class ConnectionManager : MonoBehaviour
internal readonly ClientConnectedState m_ClientConnected = new ClientConnectedState();
internal readonly ClientReconnectingState m_ClientReconnecting = new ClientReconnectingState();
internal readonly DisconnectingWithReasonState m_DisconnectingWithReason = new DisconnectingWithReasonState();
internal readonly StartingHostState m_StartingHost = new StartingHostState();
internal readonly HostingState m_Hosting = new HostingState();
internal readonly ServerStartingState m_ServerStarting = new ServerStartingState();
internal readonly ServerListeningState m_ServerListening = new ServerListeningState();
internal readonly HostStartingState m_HostStarting = new HostStartingState();
internal readonly HostListeningState m_HostListening = new HostListeningState();

public ServerType IsConnectedToHost { get; set; }

void Awake()
{
Expand All @@ -84,7 +95,7 @@ void Awake()

void Start()
{
List<ConnectionState> states = new() { m_Offline, m_ClientConnecting, m_ClientConnected, m_ClientReconnecting, m_DisconnectingWithReason, m_StartingHost, m_Hosting };
List<ConnectionState> states = new() { m_Offline, m_ClientConnecting, m_ClientConnected, m_ClientReconnecting, m_DisconnectingWithReason, m_HostStarting, m_HostListening, m_ServerListening, m_ServerStarting };
foreach (var connectionState in states)
{
m_Resolver.Inject(connectionState);
Expand All @@ -104,7 +115,6 @@ void OnDestroy()
NetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback;
NetworkManager.OnServerStarted -= OnServerStarted;
NetworkManager.ConnectionApprovalCallback -= ApprovalCheck;

}

internal void ChangeState(ConnectionState nextState)
Expand All @@ -115,6 +125,7 @@ internal void ChangeState(ConnectionState nextState)
{
m_CurrentState.Exit();
}

m_CurrentState = nextState;
m_CurrentState.Enter();
}
Expand Down Expand Up @@ -159,6 +170,11 @@ public void StartHostIp(string playerName, string ipaddress, int port)
m_CurrentState.StartHostIP(playerName, ipaddress, port);
}

public void StartServerIP(string ipaddress, int port)
{
m_CurrentState.StartServerIP(ipaddress, port);
}

public void RequestShutdown()
{
m_CurrentState.OnUserRequestedShutdown();
Expand All @@ -167,10 +183,12 @@ public void RequestShutdown()
/// <summary>
/// Registers the message handler for custom named messages. This should only be done once StartClient has been
/// called (start client will initialize NetworkSceneManager and CustomMessagingManager)
/// This will override the message handler each time and will use this instance's method.
/// </summary>
public void RegisterCustomMessages()
{
NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), ReceiveServerToClientSetDisconnectReason_CustomMessage);
NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler(nameof(ReceiveServertoClientSuccessPayload_CustomMessage), ReceiveServertoClientSuccessPayload_CustomMessage);
}

void ReceiveServerToClientSetDisconnectReason_CustomMessage(ulong clientID, FastBufferReader reader)
Expand Down Expand Up @@ -201,5 +219,18 @@ public static void SendServerToClientSetDisconnectReason(ulong clientID, Connect
writer.WriteValueSafe(status);
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), clientID, writer);
}

internal void ReceiveServertoClientSuccessPayload_CustomMessage(ulong clientID, FastBufferReader reader)
{
reader.ReadValueSafe(out ServerType isHost);
IsConnectedToHost = isHost;
}

internal static void SendServertoClientSuccessPayload(ulong clientID, ServerType isHost)
{
var writer = new FastBufferWriter(sizeof(bool), Allocator.Temp);
writer.WriteValueSafe(isHost);
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(nameof(ReceiveServertoClientSuccessPayload_CustomMessage), clientID, writer);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ class ClientConnectedState : ConnectionState
{
public override void Enter() { }

public override void Exit() { }
public override void Exit()
{
m_ConnectionManager.IsConnectedToHost = ConnectionManager.ServerType.Undefined;
}

public override void OnClientDisconnect(ulong _)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public virtual void StartClientLobby(string playerName) { }

public virtual void StartHostIP(string playerName, string ipaddress, int port) { }

public virtual void StartServerIP(string ipaddress, int port) { }

public virtual void StartHostLobby(string playerName) { }

public virtual void OnUserRequestedShutdown() { }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Collections;
using UnityEngine;

namespace Unity.Multiplayer.Samples.BossRoom
{
/// <summary>
/// Connection state corresponding to a listening host. Handles incoming client connections. When shutting down or
/// being timed out, transitions to the Offline state.
/// </summary>
class HostListeningState : ServerListeningState
{
public override void OnUserRequestedShutdown()
{
ConnectionManager.SendServerToAllClientsSetDisconnectReason(ConnectStatus.HostEndedSession);
// Wait before shutting down to make sure clients receive that message before they are disconnected
m_ConnectionManager.StartCoroutine(WaitToShutdown());
}

IEnumerator WaitToShutdown()
{
yield return null;
m_ConnectionManager.ChangeState(m_ConnectionManager.m_Offline);
}

public override void OnClientDisconnect(ulong clientId)
{
if (clientId == m_ConnectionManager.NetworkManager.LocalClientId)
{
m_ConnectionManager.ChangeState(m_ConnectionManager.m_Offline);
}
else
{
base.OnClientDisconnect(clientId);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Unity.Multiplayer.Samples.BossRoom.Shared.Net.UnityServices.Lobbies;
using Unity.Multiplayer.Samples.Utilities;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using UnityEngine;
Expand All @@ -11,7 +12,7 @@ namespace Unity.Multiplayer.Samples.BossRoom
/// Connection state corresponding to a host starting up. Starts the host when entering the state. If successful,
/// transitions to the Hosting state, if not, transitions back to the Offline state.
/// </summary>
class StartingHostState : ConnectionState
class HostStartingState : ConnectionState
{
[Inject]
LobbyServiceFacade m_LobbyServiceFacade;
Expand Down Expand Up @@ -42,7 +43,7 @@ public override void OnClientDisconnect(ulong clientId)
public override void OnServerStarted()
{
m_ConnectStatusPublisher.Publish(ConnectStatus.Success);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_Hosting);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_HostListening);
}

public override void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ class OfflineState : ConnectionState
[Inject]
ProfileManager m_ProfileManager;

const string k_MainMenuSceneName = "MainMenu";

public override void Enter()
{
m_LobbyServiceFacade.EndTracking();
m_ConnectionManager.NetworkManager.Shutdown();
if (SceneManager.GetActiveScene().name != k_MainMenuSceneName)
if (SceneManager.GetActiveScene().name != SceneNames.MainMenu)
{
SceneLoaderWrapper.Instance.LoadScene(k_MainMenuSceneName, useNetworkSceneManager: false);
SceneLoaderWrapper.Instance.LoadScene(SceneNames.MainMenu, useNetworkSceneManager: false);
}
}

Expand All @@ -58,13 +56,20 @@ public override void StartHostIP(string playerName, string ipaddress, int port)
utp.SetConnectionData(ipaddress, (ushort)port);

SetConnectionPayload(GetPlayerId(), playerName);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_StartingHost);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_HostStarting);
}

public override void StartServerIP(string ip, int port)
{
var utp = (UnityTransport)NetworkManager.Singleton.NetworkConfig.NetworkTransport;
utp.SetConnectionData(ip, (ushort)port);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_ServerStarting);
}

public override void StartHostLobby(string playerName)
{
SetConnectionPayload(GetPlayerId(), playerName);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_StartingHost);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_HostStarting);
}

void SetConnectionPayload(string playerId, string playerName)
Expand Down
Loading