diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs index abc1f5e0fc..5cc3865bfd 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs @@ -174,7 +174,9 @@ protected override void OnNetworkPostSpawn() } m_ParentedText?.gameObject.SetActive(true); +#if !DEDICATED_SERVER UpdateParentedText(); +#endif base.OnNetworkPostSpawn(); } @@ -201,7 +203,9 @@ public override void OnNetworkObjectParentChanged(NetworkObject parentNetworkObj { Debug.Log($"Parented under {parentNetworkObject.name}"); } +#if !DEDICATED_SERVER UpdateParentedText(); +#endif base.OnNetworkObjectParentChanged(parentNetworkObject); } @@ -334,6 +338,7 @@ private void ApplyInput() m_PlayerBallMotion.HasMotion(moveMotion); } +#if !DEDICATED_SERVER /// /// Updates player TextMesh relative to each client's camera view /// @@ -373,4 +378,5 @@ private void UpdateParentedText() } } } +#endif } diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs index bedc3ed758..da858b14ef 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs @@ -1,13 +1,23 @@ +#if !DEDICATED_SERVER || (DEDICATED_SERVER && !UNITY_EDITOR) using System; +#endif using System.Collections.Generic; using System.Linq; +#if !DEDICATED_SERVER using System.Threading.Tasks; +#endif using Unity.Netcode; +#if !DEDICATED_SERVER using Unity.Services.Authentication; using Unity.Services.Core; using Unity.Services.Multiplayer; +#else +using Unity.Netcode.Transports.UTP; +#endif using UnityEngine; +#if !DEDICATED_SERVER using SessionState = Unity.Services.Multiplayer.SessionState; +#endif #region NetworkManagerBootstrapperEditor #if UNITY_EDITOR @@ -67,7 +77,7 @@ protected override void OnValidateComponent() base.OnValidateComponent(); } #endif - #endregion +#endregion #region Properties public static NetworkManagerBootstrapper Instance; @@ -98,12 +108,13 @@ private enum ConnectionStates [SerializeField] private bool m_ServicesRegistered; +#if !DEDICATED_SERVER private ISession m_CurrentSession; private string m_SessionName; private string m_ProfileName; private Task m_SessionTask; - - #endregion +#endif +#endregion #region Initialization and Destroy public static string GetRandomString(int length) @@ -120,12 +131,27 @@ public void SetFrameRate(int targetFrameRate, bool enableVsync) private void Awake() { +#if !DEDICATED_SERVER Screen.SetResolution((int)(Screen.currentResolution.width * 0.40f), (int)(Screen.currentResolution.height * 0.40f), FullScreenMode.Windowed); SetFrameRate(TargetFrameRate, EnableVSync); +#endif SetSingleton(); m_SceneBootstrapLoader = GetComponent(); } +#if DEDICATED_SERVER + private void Start() + { + m_SceneBootstrapLoader.OnMainMenuLoaded += OnMainMenuLoaded; + m_SceneBootstrapLoader.LoadMainMenu(); + } + + private void OnMainMenuLoaded() + { + m_SceneBootstrapLoader.OnMainMenuLoaded -= OnMainMenuLoaded; + StartDedicatedServer(); + } +#else private async void Start() { OnClientConnectedCallback += OnClientConnected; @@ -152,17 +178,20 @@ private async void Start() } } m_SceneBootstrapLoader.LoadMainMenu(); - } + } private void OnDestroy() { OnClientConnectedCallback -= OnClientConnected; OnClientDisconnectCallback -= OnClientDisconnect; OnConnectionEvent -= OnClientConnectionEvent; } - #endregion +#endif +#endregion #region Session and Connection Event Handling + +#if !DEDICATED_SERVER private void OnClientConnectionEvent(NetworkManager networkManager, ConnectionEventData eventData) { LogMessage($"[{Time.realtimeSinceStartup}] Connection event {eventData.EventType} for Client-{eventData.ClientId}."); @@ -235,9 +264,11 @@ private async Task ConnectThroughLiveService() } return null; } - #endregion +#endif +#endregion #region GUI Menu +#if !DEDICATED_SERVER public void StartOrConnectToDistributedAuthoritySession() { m_SessionTask = ConnectThroughLiveService(); @@ -364,9 +395,11 @@ private void OnGUI() } GUILayout.EndArea(); } - #endregion +#endif +#endregion #region Server Camera Handling +#if !DEDICATED_SERVER private Vector3 m_CameraOriginalPosition; private Quaternion m_CameraOriginalRotation; private int m_CurrentFollowPlayerIndex = -1; @@ -438,9 +471,159 @@ public void ClearFollowPlayer() SetCameraDefaults(); } } - #endregion +#endif +#endregion #region Update Methods and Properties +#if DEDICATED_SERVER + private UnityTransport m_UnityTransport; + /// + /// All of the dedicated server specific script logic is contained and only compiled when DEDICATED_SERVER is defined + /// + + private void StartDedicatedServer() + { + m_UnityTransport = NetworkConfig.NetworkTransport as UnityTransport; + if (m_UnityTransport != null) + { + // Always good to know what scenes are currently loaded since you might have + // different scenes to load for a DGS vs client + var scenesPreloaded = new System.Text.StringBuilder(); + scenesPreloaded.Append("Scenes Preloaded: "); + for (int i = 0; i < UnityEngine.SceneManagement.SceneManager.sceneCount; i++) + { + var scene = UnityEngine.SceneManagement.SceneManager.GetSceneAt(i); + scenesPreloaded.Append($"[{scene.name}]"); + } + Debug.Log(scenesPreloaded.ToString()); + + // Set the application frame rate to like 30 to reduce frame processing overhead + Application.targetFrameRate = 30; + + Debug.Log($"[Pre-Init] Server Address Endpoint: {m_UnityTransport.ConnectionData.ServerEndPoint}"); + Debug.Log($"[Pre-Init] Server Listen Endpoint: {m_UnityTransport.ConnectionData.ListenEndPoint}"); + // Setup your IP and port sepcific to your DGS + //unityTransport.SetConnectionData(ListenAddress, ListenPort, ListenAddress); + + //Debug.Log($"[Post-Init] Server Address Endpoint: {unityTransport.ConnectionData.ServerEndPoint}"); + //Debug.Log($"[Post-Init] Server Listen Endpoint: {unityTransport.ConnectionData.ListenEndPoint}"); + + // Get the server started notification + OnServerStarted += ServerStarted; + + // Start the server listening + m_SceneBootstrapLoader.StartSession(SceneBootstrapLoader.StartAsTypes.Server); + } + else + { + Debug.LogError("Failed to get the UnityTransport!"); + } + } + + /// + /// Register callbacks when the OnServerStarted callback is invoked. + /// This makes it easier to know you are registering for events only + /// when the server successfully has started. + /// + private void ServerStarted() + { + Debug.Log("Dedicated Server Started!"); + Debug.Log($"[Started] Server Address Endpoint: {m_UnityTransport.ConnectionData.ServerEndPoint}"); + Debug.Log($"[Started] Server Listen Endpoint: {m_UnityTransport.ConnectionData.ListenEndPoint}"); + Debug.Log("==============================================================="); + Debug.Log("[X] Exits session (Shutdown) | [ESC] Exits application instance"); + Debug.Log("==============================================================="); + OnServerStarted -= ServerStarted; + OnClientConnectedCallback += ClientConnectedCallback; + OnClientDisconnectCallback += ClientDisconnectCallback; + // Register for OnServerStopped + OnServerStopped += ServerStopped; + } + + private void ServerStopped(bool obj) + { + OnClientConnectedCallback -= ClientConnectedCallback; + OnClientDisconnectCallback -= ClientDisconnectCallback; + OnServerStopped -= ServerStopped; + Debug.Log("Dedicated Server Stopped!"); + Debug.Log("==============================================================="); + Debug.Log("[S] Starts new session (StartServer) | [ESC] Exits application"); + Debug.Log("==============================================================="); + } + + private void ClientConnectedCallback(ulong clientId) + { + Debug.Log($"Client-{clientId} connected and approved."); + } + + private void ClientDisconnectCallback(ulong clientId) + { + Debug.Log($"Client-{clientId} disconnected."); + } + +#if UNITY_EDITOR + private void HandleEditorKeyCommands() + { + // Shutdown/Stop the server + if (Input.GetKeyDown(KeyCode.X) && IsListening && !ShutdownInProgress) + { + Shutdown(); + } + else // Start the server (this example makes it automatically start when the application first starts) + if (Input.GetKeyDown(KeyCode.S) && !IsListening) + { + StartDedicatedServer(); + } + } +#else + private void HandleConsoleKeyCommands() + { + if (Console.KeyAvailable) + { + var networkManager = NetworkManager.Singleton; + var keyPressed = Console.ReadKey(true); + switch(keyPressed.Key) + { + case ConsoleKey.X: + { + if(networkManager.IsListening && !networkManager.ShutdownInProgress) + { + networkManager.Shutdown(); + } + break; + } + case ConsoleKey.S: + { + if (!networkManager.IsListening && !networkManager.ShutdownInProgress) + { + StartDedicatedServer(); + } + break; + } + case ConsoleKey.Escape: + { + Application.Quit(); + break; + } + } + } + } +#endif + + /// + /// Update that is only included in the build and invoked when running as a dedicated server + /// + private void DedicatedServerUpdate() + { +#if UNITY_EDITOR + HandleEditorKeyCommands(); +#else + HandleConsoleKeyCommands(); +#endif + } + +#else // End of DEDICATED_SERVER defined region + /// /// General update for server-side /// @@ -459,9 +642,13 @@ private void ClientSideUpdate() { } +#endif private void Update() { +#if DEDICATED_SERVER + DedicatedServerUpdate(); +#else if (IsListening) { if (IsServer) @@ -473,6 +660,7 @@ private void Update() ClientSideUpdate(); } } +#endif if (m_MessageLogs.Count == 0) { @@ -487,6 +675,7 @@ private void Update() } } } + #endregion #region Message Logging diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkPrefabOverrideHandler.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkPrefabOverrideHandler.cs index 7774f52d71..9bba90b13a 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkPrefabOverrideHandler.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkPrefabOverrideHandler.cs @@ -52,6 +52,7 @@ public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaterni public void Destroy(NetworkObject networkObject) { +#if !DEDICATED_SERVER // Another useful thing about handling this instantiation and destruction of a NetworkObject is that you can do house cleaning // prior to the object being destroyed. This handles the scenario where the server is following a player and the player disconnects. // Before destroying the player object, we want to unparent the camera and reset the player being followed. @@ -59,6 +60,7 @@ public void Destroy(NetworkObject networkObject) { m_NetworkManager.ClearFollowPlayer(); } +#endif Destroy(networkObject.gameObject); } } diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs index 08642c10e1..256122618e 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; using Unity.Netcode; - using UnityEngine; using UnityEngine.SceneManagement; #if UNITY_EDITOR @@ -105,6 +104,8 @@ private void Awake() m_NetworkManager = GetComponent(); } + public event Action OnMainMenuLoaded; + /// /// Should be invoked by bootstrap when first starting the applicaiton and should be loaded upon exiting /// a session and shutting down the . @@ -114,6 +115,7 @@ public void LoadMainMenu() if (!m_NetworkManager.IsListening) { SceneManager.LoadScene(m_MainMenuScene, LoadSceneMode.Single); + OnMainMenuLoaded?.Invoke(); } else { @@ -147,9 +149,6 @@ private void OnNetworkManagerShutdown(bool wasHost) } #region SCENE PRE & POST START LOADING METHODS - - - private IEnumerator PreSceneLoading(StartAsTypes startAsType) { var sceneDefines = startAsType == StartAsTypes.Client ? ClientSceneDefines : ServerSceneDefines; @@ -188,11 +187,14 @@ private IEnumerator PreSceneLoading(StartAsTypes startAsType) { m_NetworkManager.StartServer(); } +#if !DEDICATED_SERVER else { m_NetworkManager.StartHost(); } +#endif } +#if !DEDICATED_SERVER else { m_NetworkManager.OnClientStopped += OnNetworkManagerShutdown; @@ -209,6 +211,7 @@ private IEnumerator PreSceneLoading(StartAsTypes startAsType) m_NetworkManager.StartClient(); } } +#endif } /// @@ -265,7 +268,7 @@ private void SceneLoaded(Scene scene, LoadSceneMode loadSceneMode) { m_SceneJustLoaded = scene.name; } - #endregion +#endregion #region SERVER POST START CONFIGURATION AND ADDITIONAL SHARED SCENE LOADING /// diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerHostClientText.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerHostClientText.cs index 93e150b2ba..1319e54b85 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerHostClientText.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerHostClientText.cs @@ -63,7 +63,9 @@ public override void OnNetworkDespawn() base.OnNetworkDespawn(); } +#if !DEDICATED_SERVER private bool m_LastFocusedValue; + private void OnGUI() { if (!IsSpawned || m_LastFocusedValue == Application.isFocused) @@ -82,4 +84,5 @@ private void OnGUI() m_DisplayText.color = m_ColorAlpha; } } +#endif } diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerInfoDisplay.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerInfoDisplay.cs index ebc84d8d98..c4025fefc4 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerInfoDisplay.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/ServerInfoDisplay.cs @@ -1,4 +1,6 @@ +#if !DEDICATED_SERVER using Unity.Netcode; +#endif using UnityEngine; using UnityEngine.UI; @@ -6,7 +8,7 @@ public class ServerInfoDisplay : MonoBehaviour { public Text ServerTime; public Text PlayerCount; - +#if !DEDICATED_SERVER private void OnGUI() { if (!NetworkManager.Singleton || !NetworkManager.Singleton.IsListening) @@ -24,4 +26,5 @@ private void OnGUI() PlayerCount.text = $"Player Count: {NetworkManager.Singleton.ConnectedClients.Count}"; } } +#endif } diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Settings.meta b/Examples/OverridingScenesAndPrefabs/Assets/Settings.meta new file mode 100644 index 0000000000..bf54907342 --- /dev/null +++ b/Examples/OverridingScenesAndPrefabs/Assets/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f07d39c4f18773945af7943acf04dff7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles.meta b/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles.meta new file mode 100644 index 0000000000..c47c89da39 --- /dev/null +++ b/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38b8655f79da8bd4ea13982ac8833b71 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles/New Windows Server Profile.asset b/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles/New Windows Server Profile.asset new file mode 100644 index 0000000000..b5b4979d3e --- /dev/null +++ b/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles/New Windows Server Profile.asset @@ -0,0 +1,49 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0} + m_Name: New Windows Server Profile + m_EditorClassIdentifier: + m_AssetVersion: 1 + m_BuildTarget: 19 + m_Subtarget: 1 + m_PlatformId: 8d1e1bca926649cba89d37a4c66e8b3d + m_PlatformBuildProfile: + rid: 4481205133896843345 + m_OverrideGlobalSceneList: 0 + m_Scenes: [] + m_ScriptingDefines: + - DEDICATED_SERVER + m_PlayerSettingsYaml: + m_Settings: [] + references: + version: 2 + RefIds: + - rid: 4481205133896843345 + type: {class: WindowsPlatformSettings, ns: UnityEditor.WindowsStandalone, asm: UnityEditor.WindowsStandalone.Extensions} + data: + m_Development: 0 + m_ConnectProfiler: 0 + m_BuildWithDeepProfilingSupport: 0 + m_AllowDebugging: 0 + m_WaitForManagedDebugger: 0 + m_ManagedDebuggerFixedPort: 0 + m_ExplicitNullChecks: 0 + m_ExplicitDivideByZeroChecks: 0 + m_ExplicitArrayBoundsChecks: 0 + m_CompressionType: 0 + m_InstallInBuildFolder: 0 + m_WindowsBuildAndRunDeployTarget: 0 + m_Architecture: 0 + m_CreateSolution: 0 + m_CopyPDBFiles: 0 + m_WindowsDevicePortalAddress: + m_WindowsDevicePortalUsername: diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles/New Windows Server Profile.asset.meta b/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles/New Windows Server Profile.asset.meta new file mode 100644 index 0000000000..6543ae07a8 --- /dev/null +++ b/Examples/OverridingScenesAndPrefabs/Assets/Settings/Build Profiles/New Windows Server Profile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ceabbe1f96a84864d8cecdc70db0a1f8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: