diff --git a/.vsconfig b/.vsconfig new file mode 100644 index 0000000..d70cd98 --- /dev/null +++ b/.vsconfig @@ -0,0 +1,6 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Workload.ManagedGame" + ] +} diff --git a/Assets/EOSManager.prefab b/Assets/EOSManager.prefab new file mode 100644 index 0000000..9d871ee --- /dev/null +++ b/Assets/EOSManager.prefab @@ -0,0 +1,59 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2209092976737935735 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 901605347204557884} + - component: {fileID: 1404666848870070223} + m_Layer: 0 + m_Name: EOSManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &901605347204557884 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2209092976737935735} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1404666848870070223 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2209092976737935735} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 016d8460ff2ae644db4fc92d25ce1a79, type: 3} + m_Name: + m_EditorClassIdentifier: + apiKeys: {fileID: 11400000, guid: bc676c2f8679fc348bdd5b0422e4f235, type: 2} + authInterfaceLogin: 0 + authInterfaceCredentialType: 6 + devAuthToolPort: 7878 + devAuthToolCredentialName: + connectInterfaceCredentialType: 0 + deviceModel: PC Windows 64bit + displayName: User + epicLoggerLevel: 200 + collectPlayerMetrics: 1 + checkForEpicLauncherAndRestart: 0 + delayedInitialization: 1 + platformTickIntervalInSeconds: 0 + tickBudgetInMilliseconds: 0 diff --git a/Assets/EOSManager.prefab.meta b/Assets/EOSManager.prefab.meta new file mode 100644 index 0000000..b8534b4 --- /dev/null +++ b/Assets/EOSManager.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 023dc204246f92344887fd8ce2ea894c +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/EosApiKey.asset b/Assets/EosApiKey.asset new file mode 100644 index 0000000..f2ccb5a --- /dev/null +++ b/Assets/EosApiKey.asset @@ -0,0 +1,21 @@ +%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: 11500000, guid: 2006c7a2843279e4598781ed39185dd0, type: 3} + m_Name: EosApiKey + m_EditorClassIdentifier: + epicProductName: 'Trouble in Terrorist Town: Source Crossed' + epicProductVersion: 1.0 + epicProductId: cefb3408547045fcb28a9dbd58d48ed7 + epicSandboxId: 739f95d42e6748379737c4ff061114c7 + epicDeploymentId: ff56985eeafc4dcbbbd63a0cd079bee9 + epicClientId: xyza7891oqIuT2qadgDUXnl76eBKgaI0 + epicClientSecret: AfGaldrVkjgxQD6eY1PlfsejJFhNs6QXmmzDSTL4QIk diff --git a/Assets/EosApiKey.asset.meta b/Assets/EosApiKey.asset.meta new file mode 100644 index 0000000..c250c0d --- /dev/null +++ b/Assets/EosApiKey.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc676c2f8679fc348bdd5b0422e4f235 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameEventManager.prefab b/Assets/GameEventManager.prefab new file mode 100644 index 0000000..f0c3d8f --- /dev/null +++ b/Assets/GameEventManager.prefab @@ -0,0 +1,69 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7721659157930599325 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7721659157930599327} + - component: {fileID: 7721659157930599326} + m_Layer: 0 + m_Name: GameEventManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7721659157930599327 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7721659157930599325} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -5.6973567, y: -3.0732017, z: -6.5618863} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &7721659157930599326 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7721659157930599325} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 951fe6b63c12fbd4f9534e38455dd24f, type: 3} + m_Name: + m_EditorClassIdentifier: + GameEvents: + - gameEventName: EnterMainMenu + GameEventFunctions: + - functionName: + gameEventData: {fileID: 0} + searchType: 2 + objectToTriggerTag: + objectToTriggerName: + objectToTriggerReffrence: {fileID: 0} + GameEventSender: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 0} + m_TargetAssemblyTypeName: + m_MethodName: + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 diff --git a/Assets/GameEventManager.prefab.meta b/Assets/GameEventManager.prefab.meta new file mode 100644 index 0000000..9b3ce39 --- /dev/null +++ b/Assets/GameEventManager.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8ddff08131f454045911a3bc0d9aa1d9 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameEvents.meta b/Assets/GameEvents.meta new file mode 100644 index 0000000..1c01945 --- /dev/null +++ b/Assets/GameEvents.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d778e0d29a089ab46b1cf785a3711f00 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameEvents/EnterMainMenu_DataSet.asset b/Assets/GameEvents/EnterMainMenu_DataSet.asset new file mode 100644 index 0000000..fa2d504 --- /dev/null +++ b/Assets/GameEvents/EnterMainMenu_DataSet.asset @@ -0,0 +1,23 @@ +%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: 11500000, guid: 7685f2f713382e34ea4c6fe7c820838f, type: 3} + m_Name: EnterMainMenu_DataSet + m_EditorClassIdentifier: + gameEventData: + - valueNameInList: presence_gamemode + valueType: 1 + returnBool: 0 + returnString: In main menu + returnInt: 0 + returnFloat: 0 + returnVector2: {x: 0, y: 0} + returnVector3: {x: 0, y: 0, z: 0} diff --git a/Assets/GameEvents/EnterMainMenu_DataSet.asset.meta b/Assets/GameEvents/EnterMainMenu_DataSet.asset.meta new file mode 100644 index 0000000..f7a734f --- /dev/null +++ b/Assets/GameEvents/EnterMainMenu_DataSet.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f2dee930d6bbe0d448b1617004d5954a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror.meta b/Assets/Mirror.meta new file mode 100644 index 0000000..2413777 --- /dev/null +++ b/Assets/Mirror.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ceaedceb7baaf174a801e62d64e05713 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Authenticators.meta b/Assets/Mirror/Authenticators.meta new file mode 100644 index 0000000..ff0eac4 --- /dev/null +++ b/Assets/Mirror/Authenticators.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b2f9d254154cd942ba40b06b869b8f3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Authenticators/BasicAuthenticator.cs b/Assets/Mirror/Authenticators/BasicAuthenticator.cs new file mode 100644 index 0000000..6a89e7a --- /dev/null +++ b/Assets/Mirror/Authenticators/BasicAuthenticator.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using UnityEngine; + +namespace Mirror.Authenticators +{ + [AddComponentMenu("Network/Authenticators/BasicAuthenticator")] + public class BasicAuthenticator : NetworkAuthenticator + { + [Header("Custom Properties")] + + // set these in the inspector + public string username; + public string password; + + #region Messages + + public struct AuthRequestMessage : NetworkMessage + { + // use whatever credentials make sense for your game + // for example, you might want to pass the accessToken if using oauth + public string authUsername; + public string authPassword; + } + + public struct AuthResponseMessage : NetworkMessage + { + public byte code; + public string message; + } + + #endregion + + #region Server + + /// + /// Called on server from StartServer to initialize the Authenticator + /// Server message handlers should be registered in this method. + /// + public override void OnStartServer() + { + // register a handler for the authentication request we expect from client + NetworkServer.RegisterHandler(OnAuthRequestMessage, false); + } + + /// + /// Called on server from StopServer to reset the Authenticator + /// Server message handlers should be registered in this method. + /// + public override void OnStopServer() + { + // unregister the handler for the authentication request + NetworkServer.UnregisterHandler(); + } + + /// + /// Called on server from OnServerAuthenticateInternal when a client needs to authenticate + /// + /// Connection to client. + public override void OnServerAuthenticate(NetworkConnection conn) + { + // do nothing...wait for AuthRequestMessage from client + } + + /// + /// Called on server when the client's AuthRequestMessage arrives + /// + /// Connection to client. + /// The message payload + public void OnAuthRequestMessage(NetworkConnection conn, AuthRequestMessage msg) + { + // Debug.LogFormat(LogType.Log, "Authentication Request: {0} {1}", msg.authUsername, msg.authPassword); + + // check the credentials by calling your web server, database table, playfab api, or any method appropriate. + if (msg.authUsername == username && msg.authPassword == password) + { + // create and send msg to client so it knows to proceed + AuthResponseMessage authResponseMessage = new AuthResponseMessage + { + code = 100, + message = "Success" + }; + + conn.Send(authResponseMessage); + + // Accept the successful authentication + ServerAccept(conn); + } + else + { + // create and send msg to client so it knows to disconnect + AuthResponseMessage authResponseMessage = new AuthResponseMessage + { + code = 200, + message = "Invalid Credentials" + }; + + conn.Send(authResponseMessage); + + // must set NetworkConnection isAuthenticated = false + conn.isAuthenticated = false; + + // disconnect the client after 1 second so that response message gets delivered + StartCoroutine(DelayedDisconnect(conn, 1)); + } + } + + IEnumerator DelayedDisconnect(NetworkConnection conn, float waitTime) + { + yield return new WaitForSeconds(waitTime); + + // Reject the unsuccessful authentication + ServerReject(conn); + } + + #endregion + + #region Client + + /// + /// Called on client from StartClient to initialize the Authenticator + /// Client message handlers should be registered in this method. + /// + public override void OnStartClient() + { + // register a handler for the authentication response we expect from server + NetworkClient.RegisterHandler((Action)OnAuthResponseMessage, false); + } + + /// + /// Called on client from StopClient to reset the Authenticator + /// Client message handlers should be unregistered in this method. + /// + public override void OnStopClient() + { + // unregister the handler for the authentication response + NetworkClient.UnregisterHandler(); + } + + /// + /// Called on client from OnClientAuthenticateInternal when a client needs to authenticate + /// + public override void OnClientAuthenticate() + { + AuthRequestMessage authRequestMessage = new AuthRequestMessage + { + authUsername = username, + authPassword = password + }; + + NetworkClient.connection.Send(authRequestMessage); + } + + // Deprecated 2021-04-29 + [Obsolete("Call OnAuthResponseMessage without the NetworkConnection parameter. It always points to NetworkClient.connection anyway.")] + public void OnAuthResponseMessage(NetworkConnection conn, AuthResponseMessage msg) => OnAuthResponseMessage(msg); + + /// + /// Called on client when the server's AuthResponseMessage arrives + /// + /// The message payload + public void OnAuthResponseMessage(AuthResponseMessage msg) + { + if (msg.code == 100) + { + // Debug.LogFormat(LogType.Log, "Authentication Response: {0}", msg.message); + + // Authentication has been accepted + ClientAccept(); + } + else + { + Debug.LogError($"Authentication Response: {msg.message}"); + + // Authentication has been rejected + ClientReject(); + } + } + + #endregion + } +} diff --git a/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta b/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta new file mode 100644 index 0000000..74b9134 --- /dev/null +++ b/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28496b776660156428f00cf78289c1ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef new file mode 100644 index 0000000..16cdfbc --- /dev/null +++ b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Mirror.Authenticators", + "references": [ + "Mirror" + ], + "optionalUnityReferences": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta new file mode 100644 index 0000000..0fa1014 --- /dev/null +++ b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e720aa64e3f58fb4880566a322584340 +AssemblyDefinitionImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs new file mode 100644 index 0000000..28f989b --- /dev/null +++ b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs @@ -0,0 +1,70 @@ +using System.Collections; +using UnityEngine; + +namespace Mirror.Authenticators +{ + /// + /// An authenticator that disconnects connections if they don't + /// authenticate within a specified time limit. + /// + [AddComponentMenu("Network/Authenticators/TimeoutAuthenticator")] + public class TimeoutAuthenticator : NetworkAuthenticator + { + public NetworkAuthenticator authenticator; + + [Range(0, 600), Tooltip("Timeout to auto-disconnect in seconds. Set to 0 for no timeout.")] + public float timeout = 60; + + public void Awake() + { + authenticator.OnServerAuthenticated.AddListener(connection => OnServerAuthenticated.Invoke(connection)); + authenticator.OnClientAuthenticated.AddListener(connection => OnClientAuthenticated.Invoke(connection)); + } + + public override void OnStartServer() + { + authenticator.OnStartServer(); + } + + public override void OnStopServer() + { + authenticator.OnStopServer(); + } + + public override void OnStartClient() + { + authenticator.OnStartClient(); + } + + public override void OnStopClient() + { + authenticator.OnStopClient(); + } + + public override void OnServerAuthenticate(NetworkConnection conn) + { + authenticator.OnServerAuthenticate(conn); + if (timeout > 0) + StartCoroutine(BeginAuthentication(conn)); + } + + public override void OnClientAuthenticate() + { + authenticator.OnClientAuthenticate(); + if (timeout > 0) + StartCoroutine(BeginAuthentication(NetworkClient.connection)); + } + + IEnumerator BeginAuthentication(NetworkConnection conn) + { + // Debug.Log($"Authentication countdown started {conn} {timeout}"); + yield return new WaitForSecondsRealtime(timeout); + + if (!conn.isAuthenticated) + { + // Debug.Log($"Authentication Timeout {conn}"); + conn.Disconnect(); + } + } + } +} diff --git a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta new file mode 100644 index 0000000..433d094 --- /dev/null +++ b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24d8269a07b8e4edfa374753a91c946e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/CompilerSymbols.meta b/Assets/Mirror/CompilerSymbols.meta new file mode 100644 index 0000000..8d0dedc --- /dev/null +++ b/Assets/Mirror/CompilerSymbols.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f8b918bcd89f5c488b06f5574f34760 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef new file mode 100644 index 0000000..af25622 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Mirror.CompilerSymbols", + "references": [], + "optionalUnityReferences": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta new file mode 100644 index 0000000..98ac7a0 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 325984b52e4128546bc7558552f8b1d2 +AssemblyDefinitionImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs new file mode 100644 index 0000000..779a687 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using UnityEditor; + +namespace Mirror +{ + static class PreprocessorDefine + { + /// + /// Add define symbols as soon as Unity gets done compiling. + /// + [InitializeOnLoadMethod] + public static void AddDefineSymbols() + { + string currentDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + HashSet defines = new HashSet(currentDefines.Split(';')) + { + "MIRROR", + "MIRROR_17_0_OR_NEWER", + "MIRROR_18_0_OR_NEWER", + "MIRROR_24_0_OR_NEWER", + "MIRROR_26_0_OR_NEWER", + "MIRROR_27_0_OR_NEWER", + "MIRROR_28_0_OR_NEWER", + "MIRROR_29_0_OR_NEWER", + "MIRROR_30_0_OR_NEWER", + "MIRROR_30_5_2_OR_NEWER", + "MIRROR_32_1_2_OR_NEWER", + "MIRROR_32_1_4_OR_NEWER", + "MIRROR_35_0_OR_NEWER", + "MIRROR_35_1_OR_NEWER", + "MIRROR_37_0_OR_NEWER", + "MIRROR_38_0_OR_NEWER", + "MIRROR_39_0_OR_NEWER", + "MIRROR_40_0_OR_NEWER", + "MIRROR_41_0_OR_NEWER", + "MIRROR_42_0_OR_NEWER", + "MIRROR_43_0_OR_NEWER", + "MIRROR_44_0_OR_NEWER" + }; + + // only touch PlayerSettings if we actually modified it. + // otherwise it shows up as changed in git each time. + string newDefines = string.Join(";", defines); + if (newDefines != currentDefines) + { + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newDefines); + } + } + } +} diff --git a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta new file mode 100644 index 0000000..248f00b --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1d66fe74ec6f42dd974cba37d25d453 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components.meta b/Assets/Mirror/Components.meta new file mode 100644 index 0000000..a257fe6 --- /dev/null +++ b/Assets/Mirror/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9bee879fbc8ef4b1a9a9f7088bfbf726 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/AssemblyInfo.cs b/Assets/Mirror/Components/AssemblyInfo.cs new file mode 100644 index 0000000..f342716 --- /dev/null +++ b/Assets/Mirror/Components/AssemblyInfo.cs @@ -0,0 +1,12 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Mirror.Tests.Common")] +[assembly: InternalsVisibleTo("Mirror.Tests")] +// need to use Unity.*.CodeGen assembly name to import Unity.CompilationPipeline +// for ILPostProcessor tests. +[assembly: InternalsVisibleTo("Unity.Mirror.Tests.CodeGen")] +[assembly: InternalsVisibleTo("Mirror.Tests.Generated")] +[assembly: InternalsVisibleTo("Mirror.Tests.Runtime")] +[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Editor")] +[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Runtime")] +[assembly: InternalsVisibleTo("Mirror.Editor")] diff --git a/Assets/Mirror/Components/AssemblyInfo.cs.meta b/Assets/Mirror/Components/AssemblyInfo.cs.meta new file mode 100644 index 0000000..d50ab80 --- /dev/null +++ b/Assets/Mirror/Components/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a65b9283f7a724e70b8e17cb277f4c1e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Discovery.meta b/Assets/Mirror/Components/Discovery.meta new file mode 100644 index 0000000..28e0327 --- /dev/null +++ b/Assets/Mirror/Components/Discovery.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5dcf9618f5e14a4eb60bff5480284a6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs new file mode 100644 index 0000000..5d90087 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs @@ -0,0 +1,114 @@ +using System; +using System.Net; +using UnityEngine; +using UnityEngine.Events; + +namespace Mirror.Discovery +{ + [Serializable] + public class ServerFoundUnityEvent : UnityEvent {}; + + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkDiscovery")] + public class NetworkDiscovery : NetworkDiscoveryBase + { + #region Server + + public long ServerId { get; private set; } + + [Tooltip("Transport to be advertised during discovery")] + public Transport transport; + + [Tooltip("Invoked when a server is found")] + public ServerFoundUnityEvent OnServerFound; + + public override void Start() + { + ServerId = RandomLong(); + + // active transport gets initialized in awake + // so make sure we set it here in Start() (after awakes) + // Or just let the user assign it in the inspector + if (transport == null) + transport = Transport.activeTransport; + + base.Start(); + } + + /// + /// Process the request from a client + /// + /// + /// Override if you wish to provide more information to the clients + /// such as the name of the host player + /// + /// Request coming from client + /// Address of the client that sent the request + /// The message to be sent back to the client or null + protected override ServerResponse ProcessRequest(ServerRequest request, IPEndPoint endpoint) + { + // In this case we don't do anything with the request + // but other discovery implementations might want to use the data + // in there, This way the client can ask for + // specific game mode or something + + try + { + // this is an example reply message, return your own + // to include whatever is relevant for your game + return new ServerResponse + { + serverId = ServerId, + uri = transport.ServerUri() + }; + } + catch (NotImplementedException) + { + Debug.LogError($"Transport {transport} does not support network discovery"); + throw; + } + } + + #endregion + + #region Client + + /// + /// Create a message that will be broadcasted on the network to discover servers + /// + /// + /// Override if you wish to include additional data in the discovery message + /// such as desired game mode, language, difficulty, etc... + /// An instance of ServerRequest with data to be broadcasted + protected override ServerRequest GetRequest() => new ServerRequest(); + + /// + /// Process the answer from a server + /// + /// + /// A client receives a reply from a server, this method processes the + /// reply and raises an event + /// + /// Response that came from the server + /// Address of the server that replied + protected override void ProcessResponse(ServerResponse response, IPEndPoint endpoint) + { + // we received a message from the remote endpoint + response.EndPoint = endpoint; + + // although we got a supposedly valid url, we may not be able to resolve + // the provided host + // However we know the real ip address of the server because we just + // received a packet from it, so use that as host. + UriBuilder realUri = new UriBuilder(response.uri) + { + Host = response.EndPoint.Address.ToString() + }; + response.uri = realUri.Uri; + + OnServerFound.Invoke(response); + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta new file mode 100644 index 0000000..f6c8bcd --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c761308e733c51245b2e8bb4201f46dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs new file mode 100644 index 0000000..f83ebd2 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs @@ -0,0 +1,385 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; +using UnityEngine; + +// Based on https://github.com/EnlightenedOne/MirrorNetworkDiscovery +// forked from https://github.com/in0finite/MirrorNetworkDiscovery +// Both are MIT Licensed + +namespace Mirror.Discovery +{ + /// + /// Base implementation for Network Discovery. Extend this component + /// to provide custom discovery with game specific data + /// NetworkDiscovery for a sample implementation + /// + [DisallowMultipleComponent] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-discovery")] + public abstract class NetworkDiscoveryBase : MonoBehaviour + where Request : NetworkMessage + where Response : NetworkMessage + { + public static bool SupportedOnThisPlatform { get { return Application.platform != RuntimePlatform.WebGLPlayer; } } + + // each game should have a random unique handshake, this way you can tell if this is the same game or not + [HideInInspector] + public long secretHandshake; + + [SerializeField] + [Tooltip("The UDP port the server will listen for multi-cast messages")] + protected int serverBroadcastListenPort = 47777; + + [SerializeField] + [Tooltip("If true, broadcasts a discovery request every ActiveDiscoveryInterval seconds")] + public bool enableActiveDiscovery = true; + + [SerializeField] + [Tooltip("Time in seconds between multi-cast messages")] + [Range(1, 60)] + float ActiveDiscoveryInterval = 3; + + protected UdpClient serverUdpClient; + protected UdpClient clientUdpClient; + +#if UNITY_EDITOR + void OnValidate() + { + if (secretHandshake == 0) + { + secretHandshake = RandomLong(); + UnityEditor.Undo.RecordObject(this, "Set secret handshake"); + } + } +#endif + + public static long RandomLong() + { + int value1 = UnityEngine.Random.Range(int.MinValue, int.MaxValue); + int value2 = UnityEngine.Random.Range(int.MinValue, int.MaxValue); + return value1 + ((long)value2 << 32); + } + + /// + /// virtual so that inheriting classes' Start() can call base.Start() too + /// + public virtual void Start() + { + // Server mode? then start advertising +#if UNITY_SERVER + AdvertiseServer(); +#endif + } + + // Ensure the ports are cleared no matter when Game/Unity UI exits + void OnApplicationQuit() + { + //Debug.Log("NetworkDiscoveryBase OnApplicationQuit"); + Shutdown(); + } + + void OnDisable() + { + //Debug.Log("NetworkDiscoveryBase OnDisable"); + Shutdown(); + } + + void OnDestroy() + { + //Debug.Log("NetworkDiscoveryBase OnDestroy"); + Shutdown(); + } + + void Shutdown() + { + if (serverUdpClient != null) + { + try + { + serverUdpClient.Close(); + } + catch (Exception) + { + // it is just close, swallow the error + } + + serverUdpClient = null; + } + + if (clientUdpClient != null) + { + try + { + clientUdpClient.Close(); + } + catch (Exception) + { + // it is just close, swallow the error + } + + clientUdpClient = null; + } + + CancelInvoke(); + } + + #region Server + + /// + /// Advertise this server in the local network + /// + public void AdvertiseServer() + { + if (!SupportedOnThisPlatform) + throw new PlatformNotSupportedException("Network discovery not supported in this platform"); + + StopDiscovery(); + + // Setup port -- may throw exception + serverUdpClient = new UdpClient(serverBroadcastListenPort) + { + EnableBroadcast = true, + MulticastLoopback = false + }; + + // listen for client pings + _ = ServerListenAsync(); + } + + public async Task ServerListenAsync() + { + while (true) + { + try + { + await ReceiveRequestAsync(serverUdpClient); + } + catch (ObjectDisposedException) + { + // socket has been closed + break; + } + catch (Exception) + { + } + } + } + + async Task ReceiveRequestAsync(UdpClient udpClient) + { + // only proceed if there is available data in network buffer, or otherwise Receive() will block + // average time for UdpClient.Available : 10 us + + UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); + + using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(udpReceiveResult.Buffer)) + { + long handshake = networkReader.ReadLong(); + if (handshake != secretHandshake) + { + // message is not for us + throw new ProtocolViolationException("Invalid handshake"); + } + + Request request = networkReader.Read(); + + ProcessClientRequest(request, udpReceiveResult.RemoteEndPoint); + } + } + + /// + /// Reply to the client to inform it of this server + /// + /// + /// Override if you wish to ignore server requests based on + /// custom criteria such as language, full server game mode or difficulty + /// + /// Request coming from client + /// Address of the client that sent the request + protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint) + { + Response info = ProcessRequest(request, endpoint); + + if (info == null) + return; + + using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) + { + try + { + writer.WriteLong(secretHandshake); + + writer.Write(info); + + ArraySegment data = writer.ToArraySegment(); + // signature matches + // send response + serverUdpClient.Send(data.Array, data.Count, endpoint); + } + catch (Exception ex) + { + Debug.LogException(ex, this); + } + } + } + + /// + /// Process the request from a client + /// + /// + /// Override if you wish to provide more information to the clients + /// such as the name of the host player + /// + /// Request coming from client + /// Address of the client that sent the request + /// The message to be sent back to the client or null + protected abstract Response ProcessRequest(Request request, IPEndPoint endpoint); + + #endregion + + #region Client + + /// + /// Start Active Discovery + /// + public void StartDiscovery() + { + if (!SupportedOnThisPlatform) + throw new PlatformNotSupportedException("Network discovery not supported in this platform"); + + StopDiscovery(); + + try + { + // Setup port + clientUdpClient = new UdpClient(0) + { + EnableBroadcast = true, + MulticastLoopback = false + }; + } + catch (Exception) + { + // Free the port if we took it + //Debug.LogError("NetworkDiscoveryBase StartDiscovery Exception"); + Shutdown(); + throw; + } + + _ = ClientListenAsync(); + + if (enableActiveDiscovery) InvokeRepeating(nameof(BroadcastDiscoveryRequest), 0, ActiveDiscoveryInterval); + } + + /// + /// Stop Active Discovery + /// + public void StopDiscovery() + { + //Debug.Log("NetworkDiscoveryBase StopDiscovery"); + Shutdown(); + } + + /// + /// Awaits for server response + /// + /// ClientListenAsync Task + public async Task ClientListenAsync() + { + while (true) + { + try + { + await ReceiveGameBroadcastAsync(clientUdpClient); + } + catch (ObjectDisposedException) + { + // socket was closed, no problem + return; + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + } + + /// + /// Sends discovery request from client + /// + public void BroadcastDiscoveryRequest() + { + if (clientUdpClient == null) + return; + + if (NetworkClient.isConnected) + { + StopDiscovery(); + return; + } + + IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, serverBroadcastListenPort); + + using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) + { + writer.WriteLong(secretHandshake); + + try + { + Request request = GetRequest(); + + writer.Write(request); + + ArraySegment data = writer.ToArraySegment(); + + clientUdpClient.SendAsync(data.Array, data.Count, endPoint); + } + catch (Exception) + { + // It is ok if we can't broadcast to one of the addresses + } + } + } + + /// + /// Create a message that will be broadcasted on the network to discover servers + /// + /// + /// Override if you wish to include additional data in the discovery message + /// such as desired game mode, language, difficulty, etc... + /// An instance of ServerRequest with data to be broadcasted + protected virtual Request GetRequest() => default; + + async Task ReceiveGameBroadcastAsync(UdpClient udpClient) + { + // only proceed if there is available data in network buffer, or otherwise Receive() will block + // average time for UdpClient.Available : 10 us + + UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); + + using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(udpReceiveResult.Buffer)) + { + if (networkReader.ReadLong() != secretHandshake) + return; + + Response response = networkReader.Read(); + + ProcessResponse(response, udpReceiveResult.RemoteEndPoint); + } + } + + /// + /// Process the answer from a server + /// + /// + /// A client receives a reply from a server, this method processes the + /// reply and raises an event + /// + /// Response that came from the server + /// Address of the server that replied + protected abstract void ProcessResponse(Response response, IPEndPoint endpoint); + + #endregion + } +} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta new file mode 100644 index 0000000..e51d40a --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9971d60ce61f4e39b07cd9e7e0c68fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs new file mode 100644 index 0000000..f707146 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs @@ -0,0 +1,132 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror.Discovery +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkDiscoveryHUD")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-discovery")] + [RequireComponent(typeof(NetworkDiscovery))] + public class NetworkDiscoveryHUD : MonoBehaviour + { + readonly Dictionary discoveredServers = new Dictionary(); + Vector2 scrollViewPos = Vector2.zero; + + public NetworkDiscovery networkDiscovery; + +#if UNITY_EDITOR + void OnValidate() + { + if (networkDiscovery == null) + { + networkDiscovery = GetComponent(); + UnityEditor.Events.UnityEventTools.AddPersistentListener(networkDiscovery.OnServerFound, OnDiscoveredServer); + UnityEditor.Undo.RecordObjects(new Object[] { this, networkDiscovery }, "Set NetworkDiscovery"); + } + } +#endif + + void OnGUI() + { + if (NetworkManager.singleton == null) + return; + + if (!NetworkClient.isConnected && !NetworkServer.active && !NetworkClient.active) + DrawGUI(); + + if (NetworkServer.active || NetworkClient.active) + StopButtons(); + } + + void DrawGUI() + { + GUILayout.BeginArea(new Rect(10, 10, 300, 500)); + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("Find Servers")) + { + discoveredServers.Clear(); + networkDiscovery.StartDiscovery(); + } + + // LAN Host + if (GUILayout.Button("Start Host")) + { + discoveredServers.Clear(); + NetworkManager.singleton.StartHost(); + networkDiscovery.AdvertiseServer(); + } + + // Dedicated server + if (GUILayout.Button("Start Server")) + { + discoveredServers.Clear(); + NetworkManager.singleton.StartServer(); + networkDiscovery.AdvertiseServer(); + } + + GUILayout.EndHorizontal(); + + // show list of found server + + GUILayout.Label($"Discovered Servers [{discoveredServers.Count}]:"); + + // servers + scrollViewPos = GUILayout.BeginScrollView(scrollViewPos); + + foreach (ServerResponse info in discoveredServers.Values) + if (GUILayout.Button(info.EndPoint.Address.ToString())) + Connect(info); + + GUILayout.EndScrollView(); + GUILayout.EndArea(); + } + + void StopButtons() + { + GUILayout.BeginArea(new Rect(10, 40, 100, 25)); + + // stop host if host mode + if (NetworkServer.active && NetworkClient.isConnected) + { + if (GUILayout.Button("Stop Host")) + { + NetworkManager.singleton.StopHost(); + networkDiscovery.StopDiscovery(); + } + } + // stop client if client-only + else if (NetworkClient.isConnected) + { + if (GUILayout.Button("Stop Client")) + { + NetworkManager.singleton.StopClient(); + networkDiscovery.StopDiscovery(); + } + } + // stop server if server-only + else if (NetworkServer.active) + { + if (GUILayout.Button("Stop Server")) + { + NetworkManager.singleton.StopServer(); + networkDiscovery.StopDiscovery(); + } + } + + GUILayout.EndArea(); + } + + void Connect(ServerResponse info) + { + networkDiscovery.StopDiscovery(); + NetworkManager.singleton.StartClient(info.uri); + } + + public void OnDiscoveredServer(ServerResponse info) + { + // Note that you can check the versioning to decide if you can connect to the server or not using this method + discoveredServers[info.serverId] = info; + } + } +} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta new file mode 100644 index 0000000..375a0d8 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88c37d3deca7a834d80cfd8d3cfcc510 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Discovery/ServerRequest.cs b/Assets/Mirror/Components/Discovery/ServerRequest.cs new file mode 100644 index 0000000..647b619 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerRequest.cs @@ -0,0 +1,4 @@ +namespace Mirror.Discovery +{ + public struct ServerRequest : NetworkMessage {} +} diff --git a/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta b/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta new file mode 100644 index 0000000..0bbe3ef --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea7254bf7b9454da4adad881d94cd141 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Discovery/ServerResponse.cs b/Assets/Mirror/Components/Discovery/ServerResponse.cs new file mode 100644 index 0000000..7465783 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Net; + +namespace Mirror.Discovery +{ + public struct ServerResponse : NetworkMessage + { + // The server that sent this + // this is a property so that it is not serialized, but the + // client fills this up after we receive it + public IPEndPoint EndPoint { get; set; } + + public Uri uri; + + // Prevent duplicate server appearance when a connection can be made via LAN on multiple NICs + public long serverId; + } +} \ No newline at end of file diff --git a/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta b/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta new file mode 100644 index 0000000..09532c4 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36f97227fdf2d7a4e902db5bfc43039c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Experimental.meta b/Assets/Mirror/Components/Experimental.meta new file mode 100644 index 0000000..ebf1efd --- /dev/null +++ b/Assets/Mirror/Components/Experimental.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bfbf2a1f2b300c5489dcab219ef2846e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs new file mode 100644 index 0000000..41a4d6a --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs @@ -0,0 +1,93 @@ +using UnityEngine; + +namespace Mirror.Experimental +{ + [AddComponentMenu("Network/Experimental/NetworkLerpRigidbody")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-lerp-rigidbody")] + public class NetworkLerpRigidbody : NetworkBehaviour + { + [Header("Settings")] + [SerializeField] internal Rigidbody target = null; + [Tooltip("How quickly current velocity approaches target velocity")] + [SerializeField] float lerpVelocityAmount = 0.5f; + [Tooltip("How quickly current position approaches target position")] + [SerializeField] float lerpPositionAmount = 0.5f; + + [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] + [SerializeField] bool clientAuthority = false; + + float nextSyncTime; + + + [SyncVar()] + Vector3 targetVelocity; + + [SyncVar()] + Vector3 targetPosition; + + /// + /// Ignore value if is host or client with Authority + /// + /// + bool IgnoreSync => isServer || ClientWithAuthority; + + bool ClientWithAuthority => clientAuthority && hasAuthority; + + void OnValidate() + { + if (target == null) + { + target = GetComponent(); + } + } + + void Update() + { + if (isServer) + { + SyncToClients(); + } + else if (ClientWithAuthority) + { + SendToServer(); + } + } + + void SyncToClients() + { + targetVelocity = target.velocity; + targetPosition = target.position; + } + + void SendToServer() + { + float now = Time.time; + if (now > nextSyncTime) + { + nextSyncTime = now + syncInterval; + CmdSendState(target.velocity, target.position); + } + } + + [Command] + void CmdSendState(Vector3 velocity, Vector3 position) + { + target.velocity = velocity; + target.position = position; + targetVelocity = velocity; + targetPosition = position; + } + + void FixedUpdate() + { + if (IgnoreSync) { return; } + + target.velocity = Vector3.Lerp(target.velocity, targetVelocity, lerpVelocityAmount); + target.position = Vector3.Lerp(target.position, targetPosition, lerpPositionAmount); + // add velocity to position as position would have moved on server at that velocity + targetPosition += target.velocity * Time.fixedDeltaTime; + + // TODO does this also need to sync acceleration so and update velocity? + } + } +} diff --git a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs.meta b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs.meta new file mode 100644 index 0000000..1c006ab --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f032128052c95a46afb0ddd97d994cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs new file mode 100644 index 0000000..939d336 --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs @@ -0,0 +1,361 @@ +using UnityEngine; + +namespace Mirror.Experimental +{ + [AddComponentMenu("Network/Experimental/NetworkRigidbody")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-rigidbody")] + public class NetworkRigidbody : NetworkBehaviour + { + [Header("Settings")] + [SerializeField] internal Rigidbody target = null; + + [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] + public bool clientAuthority = false; + + [Header("Velocity")] + + [Tooltip("Syncs Velocity every SyncInterval")] + [SerializeField] bool syncVelocity = true; + + [Tooltip("Set velocity to 0 each frame (only works if syncVelocity is false")] + [SerializeField] bool clearVelocity = false; + + [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] + [SerializeField] float velocitySensitivity = 0.1f; + + + [Header("Angular Velocity")] + + [Tooltip("Syncs AngularVelocity every SyncInterval")] + [SerializeField] bool syncAngularVelocity = true; + + [Tooltip("Set angularVelocity to 0 each frame (only works if syncAngularVelocity is false")] + [SerializeField] bool clearAngularVelocity = false; + + [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] + [SerializeField] float angularVelocitySensitivity = 0.1f; + + /// + /// Values sent on client with authority after they are sent to the server + /// + readonly ClientSyncState previousValue = new ClientSyncState(); + + void OnValidate() + { + if (target == null) + { + target = GetComponent(); + } + } + + + #region Sync vars + [SyncVar(hook = nameof(OnVelocityChanged))] + Vector3 velocity; + + [SyncVar(hook = nameof(OnAngularVelocityChanged))] + Vector3 angularVelocity; + + [SyncVar(hook = nameof(OnIsKinematicChanged))] + bool isKinematic; + + [SyncVar(hook = nameof(OnUseGravityChanged))] + bool useGravity; + + [SyncVar(hook = nameof(OnuDragChanged))] + float drag; + + [SyncVar(hook = nameof(OnAngularDragChanged))] + float angularDrag; + + /// + /// Ignore value if is host or client with Authority + /// + /// + bool IgnoreSync => isServer || ClientWithAuthority; + + bool ClientWithAuthority => clientAuthority && hasAuthority; + + void OnVelocityChanged(Vector3 _, Vector3 newValue) + { + if (IgnoreSync) + return; + + target.velocity = newValue; + } + + + void OnAngularVelocityChanged(Vector3 _, Vector3 newValue) + { + if (IgnoreSync) + return; + + target.angularVelocity = newValue; + } + + void OnIsKinematicChanged(bool _, bool newValue) + { + if (IgnoreSync) + return; + + target.isKinematic = newValue; + } + + void OnUseGravityChanged(bool _, bool newValue) + { + if (IgnoreSync) + return; + + target.useGravity = newValue; + } + + void OnuDragChanged(float _, float newValue) + { + if (IgnoreSync) + return; + + target.drag = newValue; + } + + void OnAngularDragChanged(float _, float newValue) + { + if (IgnoreSync) + return; + + target.angularDrag = newValue; + } + #endregion + + + internal void Update() + { + if (isServer) + { + SyncToClients(); + } + else if (ClientWithAuthority) + { + SendToServer(); + } + } + + internal void FixedUpdate() + { + if (clearAngularVelocity && !syncAngularVelocity) + { + target.angularVelocity = Vector3.zero; + } + + if (clearVelocity && !syncVelocity) + { + target.velocity = Vector3.zero; + } + } + + /// + /// Updates sync var values on server so that they sync to the client + /// + [Server] + void SyncToClients() + { + // only update if they have changed more than Sensitivity + + Vector3 currentVelocity = syncVelocity ? target.velocity : default; + Vector3 currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; + + bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); + bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity); + + if (velocityChanged) + { + velocity = currentVelocity; + previousValue.velocity = currentVelocity; + } + + if (angularVelocityChanged) + { + angularVelocity = currentAngularVelocity; + previousValue.angularVelocity = currentAngularVelocity; + } + + // other rigidbody settings + isKinematic = target.isKinematic; + useGravity = target.useGravity; + drag = target.drag; + angularDrag = target.angularDrag; + } + + /// + /// Uses Command to send values to server + /// + [Client] + void SendToServer() + { + if (!hasAuthority) + { + Debug.LogWarning("SendToServer called without authority"); + return; + } + + SendVelocity(); + SendRigidBodySettings(); + } + + [Client] + void SendVelocity() + { + float now = Time.time; + if (now < previousValue.nextSyncTime) + return; + + Vector3 currentVelocity = syncVelocity ? target.velocity : default; + Vector3 currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; + + bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); + bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity); + + // if angularVelocity has changed it is likely that velocity has also changed so just sync both values + // however if only velocity has changed just send velocity + if (angularVelocityChanged) + { + CmdSendVelocityAndAngular(currentVelocity, currentAngularVelocity); + previousValue.velocity = currentVelocity; + previousValue.angularVelocity = currentAngularVelocity; + } + else if (velocityChanged) + { + CmdSendVelocity(currentVelocity); + previousValue.velocity = currentVelocity; + } + + + // only update syncTime if either has changed + if (angularVelocityChanged || velocityChanged) + { + previousValue.nextSyncTime = now + syncInterval; + } + } + + [Client] + void SendRigidBodySettings() + { + // These shouldn't change often so it is ok to send in their own Command + if (previousValue.isKinematic != target.isKinematic) + { + CmdSendIsKinematic(target.isKinematic); + previousValue.isKinematic = target.isKinematic; + } + if (previousValue.useGravity != target.useGravity) + { + CmdSendUseGravity(target.useGravity); + previousValue.useGravity = target.useGravity; + } + if (previousValue.drag != target.drag) + { + CmdSendDrag(target.drag); + previousValue.drag = target.drag; + } + if (previousValue.angularDrag != target.angularDrag) + { + CmdSendAngularDrag(target.angularDrag); + previousValue.angularDrag = target.angularDrag; + } + } + + /// + /// Called when only Velocity has changed on the client + /// + [Command] + void CmdSendVelocity(Vector3 velocity) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.velocity = velocity; + target.velocity = velocity; + } + + /// + /// Called when angularVelocity has changed on the client + /// + [Command] + void CmdSendVelocityAndAngular(Vector3 velocity, Vector3 angularVelocity) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + if (syncVelocity) + { + this.velocity = velocity; + + target.velocity = velocity; + + } + this.angularVelocity = angularVelocity; + target.angularVelocity = angularVelocity; + } + + [Command] + void CmdSendIsKinematic(bool isKinematic) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.isKinematic = isKinematic; + target.isKinematic = isKinematic; + } + + [Command] + void CmdSendUseGravity(bool useGravity) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.useGravity = useGravity; + target.useGravity = useGravity; + } + + [Command] + void CmdSendDrag(float drag) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.drag = drag; + target.drag = drag; + } + + [Command] + void CmdSendAngularDrag(float angularDrag) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.angularDrag = angularDrag; + target.angularDrag = angularDrag; + } + + /// + /// holds previously synced values + /// + public class ClientSyncState + { + /// + /// Next sync time that velocity will be synced, based on syncInterval. + /// + public float nextSyncTime; + public Vector3 velocity; + public Vector3 angularVelocity; + public bool isKinematic; + public bool useGravity; + public float drag; + public float angularDrag; + } + } +} diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs.meta b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs.meta new file mode 100644 index 0000000..9a05405 --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83392ae5c1b731446909f252fd494ae4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs new file mode 100644 index 0000000..ca19361 --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs @@ -0,0 +1,360 @@ +using UnityEngine; + +namespace Mirror.Experimental +{ + [AddComponentMenu("Network/Experimental/NetworkRigidbody2D")] + public class NetworkRigidbody2D : NetworkBehaviour + { + [Header("Settings")] + [SerializeField] internal Rigidbody2D target = null; + + [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] + public bool clientAuthority = false; + + [Header("Velocity")] + + [Tooltip("Syncs Velocity every SyncInterval")] + [SerializeField] bool syncVelocity = true; + + [Tooltip("Set velocity to 0 each frame (only works if syncVelocity is false")] + [SerializeField] bool clearVelocity = false; + + [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] + [SerializeField] float velocitySensitivity = 0.1f; + + + [Header("Angular Velocity")] + + [Tooltip("Syncs AngularVelocity every SyncInterval")] + [SerializeField] bool syncAngularVelocity = true; + + [Tooltip("Set angularVelocity to 0 each frame (only works if syncAngularVelocity is false")] + [SerializeField] bool clearAngularVelocity = false; + + [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] + [SerializeField] float angularVelocitySensitivity = 0.1f; + + /// + /// Values sent on client with authority after they are sent to the server + /// + readonly ClientSyncState previousValue = new ClientSyncState(); + + void OnValidate() + { + if (target == null) + { + target = GetComponent(); + } + } + + + #region Sync vars + [SyncVar(hook = nameof(OnVelocityChanged))] + Vector2 velocity; + + [SyncVar(hook = nameof(OnAngularVelocityChanged))] + float angularVelocity; + + [SyncVar(hook = nameof(OnIsKinematicChanged))] + bool isKinematic; + + [SyncVar(hook = nameof(OnGravityScaleChanged))] + float gravityScale; + + [SyncVar(hook = nameof(OnuDragChanged))] + float drag; + + [SyncVar(hook = nameof(OnAngularDragChanged))] + float angularDrag; + + /// + /// Ignore value if is host or client with Authority + /// + /// + bool IgnoreSync => isServer || ClientWithAuthority; + + bool ClientWithAuthority => clientAuthority && hasAuthority; + + void OnVelocityChanged(Vector2 _, Vector2 newValue) + { + if (IgnoreSync) + return; + + target.velocity = newValue; + } + + + void OnAngularVelocityChanged(float _, float newValue) + { + if (IgnoreSync) + return; + + target.angularVelocity = newValue; + } + + void OnIsKinematicChanged(bool _, bool newValue) + { + if (IgnoreSync) + return; + + target.isKinematic = newValue; + } + + void OnGravityScaleChanged(float _, float newValue) + { + if (IgnoreSync) + return; + + target.gravityScale = newValue; + } + + void OnuDragChanged(float _, float newValue) + { + if (IgnoreSync) + return; + + target.drag = newValue; + } + + void OnAngularDragChanged(float _, float newValue) + { + if (IgnoreSync) + return; + + target.angularDrag = newValue; + } + #endregion + + + internal void Update() + { + if (isServer) + { + SyncToClients(); + } + else if (ClientWithAuthority) + { + SendToServer(); + } + } + + internal void FixedUpdate() + { + if (clearAngularVelocity && !syncAngularVelocity) + { + target.angularVelocity = 0f; + } + + if (clearVelocity && !syncVelocity) + { + target.velocity = Vector2.zero; + } + } + + /// + /// Updates sync var values on server so that they sync to the client + /// + [Server] + void SyncToClients() + { + // only update if they have changed more than Sensitivity + + Vector2 currentVelocity = syncVelocity ? target.velocity : default; + float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; + + bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); + bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity) > angularVelocitySensitivity); + + if (velocityChanged) + { + velocity = currentVelocity; + previousValue.velocity = currentVelocity; + } + + if (angularVelocityChanged) + { + angularVelocity = currentAngularVelocity; + previousValue.angularVelocity = currentAngularVelocity; + } + + // other rigidbody settings + isKinematic = target.isKinematic; + gravityScale = target.gravityScale; + drag = target.drag; + angularDrag = target.angularDrag; + } + + /// + /// Uses Command to send values to server + /// + [Client] + void SendToServer() + { + if (!hasAuthority) + { + Debug.LogWarning("SendToServer called without authority"); + return; + } + + SendVelocity(); + SendRigidBodySettings(); + } + + [Client] + void SendVelocity() + { + float now = Time.time; + if (now < previousValue.nextSyncTime) + return; + + Vector2 currentVelocity = syncVelocity ? target.velocity : default; + float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; + + bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); + bool angularVelocityChanged = syncAngularVelocity && previousValue.angularVelocity != currentAngularVelocity;//((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity); + + // if angularVelocity has changed it is likely that velocity has also changed so just sync both values + // however if only velocity has changed just send velocity + if (angularVelocityChanged) + { + CmdSendVelocityAndAngular(currentVelocity, currentAngularVelocity); + previousValue.velocity = currentVelocity; + previousValue.angularVelocity = currentAngularVelocity; + } + else if (velocityChanged) + { + CmdSendVelocity(currentVelocity); + previousValue.velocity = currentVelocity; + } + + + // only update syncTime if either has changed + if (angularVelocityChanged || velocityChanged) + { + previousValue.nextSyncTime = now + syncInterval; + } + } + + [Client] + void SendRigidBodySettings() + { + // These shouldn't change often so it is ok to send in their own Command + if (previousValue.isKinematic != target.isKinematic) + { + CmdSendIsKinematic(target.isKinematic); + previousValue.isKinematic = target.isKinematic; + } + if (previousValue.gravityScale != target.gravityScale) + { + CmdChangeGravityScale(target.gravityScale); + previousValue.gravityScale = target.gravityScale; + } + if (previousValue.drag != target.drag) + { + CmdSendDrag(target.drag); + previousValue.drag = target.drag; + } + if (previousValue.angularDrag != target.angularDrag) + { + CmdSendAngularDrag(target.angularDrag); + previousValue.angularDrag = target.angularDrag; + } + } + + /// + /// Called when only Velocity has changed on the client + /// + [Command] + void CmdSendVelocity(Vector2 velocity) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.velocity = velocity; + target.velocity = velocity; + } + + /// + /// Called when angularVelocity has changed on the client + /// + [Command] + void CmdSendVelocityAndAngular(Vector2 velocity, float angularVelocity) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + if (syncVelocity) + { + this.velocity = velocity; + + target.velocity = velocity; + + } + this.angularVelocity = angularVelocity; + target.angularVelocity = angularVelocity; + } + + [Command] + void CmdSendIsKinematic(bool isKinematic) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.isKinematic = isKinematic; + target.isKinematic = isKinematic; + } + + [Command] + void CmdChangeGravityScale(float gravityScale) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.gravityScale = gravityScale; + target.gravityScale = gravityScale; + } + + [Command] + void CmdSendDrag(float drag) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.drag = drag; + target.drag = drag; + } + + [Command] + void CmdSendAngularDrag(float angularDrag) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + this.angularDrag = angularDrag; + target.angularDrag = angularDrag; + } + + /// + /// holds previously synced values + /// + public class ClientSyncState + { + /// + /// Next sync time that velocity will be synced, based on syncInterval. + /// + public float nextSyncTime; + public Vector2 velocity; + public float angularVelocity; + public bool isKinematic; + public float gravityScale; + public float drag; + public float angularDrag; + } + } +} diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs.meta b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs.meta new file mode 100644 index 0000000..f092db7 --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab2cbc52526ea384ba280d13cd1a57b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Experimental/NetworkTransform.cs b/Assets/Mirror/Components/Experimental/NetworkTransform.cs new file mode 100644 index 0000000..495518e --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkTransform.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +namespace Mirror.Experimental +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/Experimental/NetworkTransformExperimental")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-transform")] + public class NetworkTransform : NetworkTransformBase + { + protected override Transform targetTransform => transform; + } +} diff --git a/Assets/Mirror/Components/Experimental/NetworkTransform.cs.meta b/Assets/Mirror/Components/Experimental/NetworkTransform.cs.meta new file mode 100644 index 0000000..412dcbf --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 741bbe11f5357b44593b15c0d11b16bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs b/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs new file mode 100644 index 0000000..6e1fc9a --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs @@ -0,0 +1,529 @@ +// vis2k: +// base class for NetworkTransform and NetworkTransformChild. +// New method is simple and stupid. No more 1500 lines of code. +// +// Server sends current data. +// Client saves it and interpolates last and latest data points. +// Update handles transform movement / rotation +// FixedUpdate handles rigidbody movement / rotation +// +// Notes: +// * Built-in Teleport detection in case of lags / teleport / obstacles +// * Quaternion > EulerAngles because gimbal lock and Quaternion.Slerp +// * Syncs XYZ. Works 3D and 2D. Saving 4 bytes isn't worth 1000 lines of code. +// * Initial delay might happen if server sends packet immediately after moving +// just 1cm, hence we move 1cm and then wait 100ms for next packet +// * Only way for smooth movement is to use a fixed movement speed during +// interpolation. interpolation over time is never that good. +// +using System; +using UnityEngine; + +namespace Mirror.Experimental +{ + public abstract class NetworkTransformBase : NetworkBehaviour + { + // target transform to sync. can be on a child. + protected abstract Transform targetTransform { get; } + + [Header("Authority")] + + [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] + [SyncVar] + public bool clientAuthority; + + [Tooltip("Set to true if updates from server should be ignored by owner")] + [SyncVar] + public bool excludeOwnerUpdate = true; + + [Header("Synchronization")] + + [Tooltip("Set to true if position should be synchronized")] + [SyncVar] + public bool syncPosition = true; + + [Tooltip("Set to true if rotation should be synchronized")] + [SyncVar] + public bool syncRotation = true; + + [Tooltip("Set to true if scale should be synchronized")] + [SyncVar] + public bool syncScale = true; + + [Header("Interpolation")] + + [Tooltip("Set to true if position should be interpolated")] + [SyncVar] + public bool interpolatePosition = true; + + [Tooltip("Set to true if rotation should be interpolated")] + [SyncVar] + public bool interpolateRotation = true; + + [Tooltip("Set to true if scale should be interpolated")] + [SyncVar] + public bool interpolateScale = true; + + // Sensitivity is added for VR where human players tend to have micro movements so this can quiet down + // the network traffic. Additionally, rigidbody drift should send less traffic, e.g very slow sliding / rolling. + [Header("Sensitivity")] + + [Tooltip("Changes to the transform must exceed these values to be transmitted on the network.")] + [SyncVar] + public float localPositionSensitivity = .01f; + + [Tooltip("If rotation exceeds this angle, it will be transmitted on the network")] + [SyncVar] + public float localRotationSensitivity = .01f; + + [Tooltip("Changes to the transform must exceed these values to be transmitted on the network.")] + [SyncVar] + public float localScaleSensitivity = .01f; + + [Header("Diagnostics")] + + // server + public Vector3 lastPosition; + public Quaternion lastRotation; + public Vector3 lastScale; + + // client + // use local position/rotation for VR support + [Serializable] + public struct DataPoint + { + public float timeStamp; + public Vector3 localPosition; + public Quaternion localRotation; + public Vector3 localScale; + public float movementSpeed; + + public bool isValid => timeStamp != 0; + } + + // Is this a client with authority over this transform? + // This component could be on the player object or any object that has been assigned authority to this client. + bool IsOwnerWithClientAuthority => hasAuthority && clientAuthority; + + // interpolation start and goal + public DataPoint start = new DataPoint(); + public DataPoint goal = new DataPoint(); + + // We need to store this locally on the server so clients can't request Authority when ever they like + bool clientAuthorityBeforeTeleport; + + void FixedUpdate() + { + // if server then always sync to others. + // let the clients know that this has moved + if (isServer && HasEitherMovedRotatedScaled()) + { + ServerUpdate(); + } + + if (isClient) + { + // send to server if we have local authority (and aren't the server) + // -> only if connectionToServer has been initialized yet too + if (IsOwnerWithClientAuthority) + { + ClientAuthorityUpdate(); + } + else if (goal.isValid) + { + ClientRemoteUpdate(); + } + } + } + + void ServerUpdate() + { + RpcMove(targetTransform.localPosition, Compression.CompressQuaternion(targetTransform.localRotation), targetTransform.localScale); + } + + void ClientAuthorityUpdate() + { + if (!isServer && HasEitherMovedRotatedScaled()) + { + // serialize + // local position/rotation for VR support + // send to server + CmdClientToServerSync(targetTransform.localPosition, Compression.CompressQuaternion(targetTransform.localRotation), targetTransform.localScale); + } + } + + void ClientRemoteUpdate() + { + // teleport or interpolate + if (NeedsTeleport()) + { + // local position/rotation for VR support + ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale); + + // reset data points so we don't keep interpolating + start = new DataPoint(); + goal = new DataPoint(); + } + else + { + // local position/rotation for VR support + ApplyPositionRotationScale(InterpolatePosition(start, goal, targetTransform.localPosition), + InterpolateRotation(start, goal, targetTransform.localRotation), + InterpolateScale(start, goal, targetTransform.localScale)); + } + } + + // moved or rotated or scaled since last time we checked it? + bool HasEitherMovedRotatedScaled() + { + // Save last for next frame to compare only if change was detected, otherwise + // slow moving objects might never sync because of C#'s float comparison tolerance. + // See also: https://github.com/vis2k/Mirror/pull/428) + bool changed = HasMoved || HasRotated || HasScaled; + if (changed) + { + // local position/rotation for VR support + if (syncPosition) lastPosition = targetTransform.localPosition; + if (syncRotation) lastRotation = targetTransform.localRotation; + if (syncScale) lastScale = targetTransform.localScale; + } + return changed; + } + + // local position/rotation for VR support + // SqrMagnitude is faster than Distance per Unity docs + // https://docs.unity3d.com/ScriptReference/Vector3-sqrMagnitude.html + + bool HasMoved => syncPosition && Vector3.SqrMagnitude(lastPosition - targetTransform.localPosition) > localPositionSensitivity * localPositionSensitivity; + bool HasRotated => syncRotation && Quaternion.Angle(lastRotation, targetTransform.localRotation) > localRotationSensitivity; + bool HasScaled => syncScale && Vector3.SqrMagnitude(lastScale - targetTransform.localScale) > localScaleSensitivity * localScaleSensitivity; + + // teleport / lag / stuck detection + // - checking distance is not enough since there could be just a tiny fence between us and the goal + // - checking time always works, this way we just teleport if we still didn't reach the goal after too much time has elapsed + bool NeedsTeleport() + { + // calculate time between the two data points + float startTime = start.isValid ? start.timeStamp : Time.time - Time.fixedDeltaTime; + float goalTime = goal.isValid ? goal.timeStamp : Time.time; + float difference = goalTime - startTime; + float timeSinceGoalReceived = Time.time - goalTime; + return timeSinceGoalReceived > difference * 5; + } + + // local authority client sends sync message to server for broadcasting + [Command(channel = Channels.Unreliable)] + void CmdClientToServerSync(Vector3 position, uint packedRotation, Vector3 scale) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // deserialize payload + SetGoal(position, Compression.DecompressQuaternion(packedRotation), scale); + + // server-only mode does no interpolation to save computations, but let's set the position directly + if (isServer && !isClient) + ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale); + + RpcMove(position, packedRotation, scale); + } + + [ClientRpc(channel = Channels.Unreliable)] + void RpcMove(Vector3 position, uint packedRotation, Vector3 scale) + { + if (hasAuthority && excludeOwnerUpdate) return; + + if (!isServer) + SetGoal(position, Compression.DecompressQuaternion(packedRotation), scale); + } + + // serialization is needed by OnSerialize and by manual sending from authority + void SetGoal(Vector3 position, Quaternion rotation, Vector3 scale) + { + // put it into a data point immediately + DataPoint temp = new DataPoint + { + // deserialize position + localPosition = position, + localRotation = rotation, + localScale = scale, + timeStamp = Time.time + }; + + // movement speed: based on how far it moved since last time has to be calculated before 'start' is overwritten + temp.movementSpeed = EstimateMovementSpeed(goal, temp, targetTransform, Time.fixedDeltaTime); + + // reassign start wisely + // first ever data point? then make something up for previous one so that we can start interpolation without waiting for next. + if (start.timeStamp == 0) + { + start = new DataPoint + { + timeStamp = Time.time - Time.fixedDeltaTime, + // local position/rotation for VR support + localPosition = targetTransform.localPosition, + localRotation = targetTransform.localRotation, + localScale = targetTransform.localScale, + movementSpeed = temp.movementSpeed + }; + } + // second or nth data point? then update previous + // but: we start at where ever we are right now, so that it's perfectly smooth and we don't jump anywhere + // + // example if we are at 'x': + // + // A--x->B + // + // and then receive a new point C: + // + // A--x--B + // | + // | + // C + // + // then we don't want to just jump to B and start interpolation: + // + // x + // | + // | + // C + // + // we stay at 'x' and interpolate from there to C: + // + // x..B + // \ . + // \. + // C + // + else + { + float oldDistance = Vector3.Distance(start.localPosition, goal.localPosition); + float newDistance = Vector3.Distance(goal.localPosition, temp.localPosition); + + start = goal; + + // local position/rotation for VR support + // teleport / lag / obstacle detection: only continue at current position if we aren't too far away + // XC < AB + BC (see comments above) + if (Vector3.Distance(targetTransform.localPosition, start.localPosition) < oldDistance + newDistance) + { + start.localPosition = targetTransform.localPosition; + start.localRotation = targetTransform.localRotation; + start.localScale = targetTransform.localScale; + } + } + + // set new destination in any case. new data is best data. + goal = temp; + } + + // try to estimate movement speed for a data point based on how far it moved since the previous one + // - if this is the first time ever then we use our best guess: + // - delta based on transform.localPosition + // - elapsed based on send interval hoping that it roughly matches + static float EstimateMovementSpeed(DataPoint from, DataPoint to, Transform transform, float sendInterval) + { + Vector3 delta = to.localPosition - (from.localPosition != transform.localPosition ? from.localPosition : transform.localPosition); + float elapsed = from.isValid ? to.timeStamp - from.timeStamp : sendInterval; + + // avoid NaN + return elapsed > 0 ? delta.magnitude / elapsed : 0; + } + + // set position carefully depending on the target component + void ApplyPositionRotationScale(Vector3 position, Quaternion rotation, Vector3 scale) + { + // local position/rotation for VR support + if (syncPosition) targetTransform.localPosition = position; + if (syncRotation) targetTransform.localRotation = rotation; + if (syncScale) targetTransform.localScale = scale; + } + + // where are we in the timeline between start and goal? [0,1] + Vector3 InterpolatePosition(DataPoint start, DataPoint goal, Vector3 currentPosition) + { + if (!interpolatePosition) + return currentPosition; + + if (start.movementSpeed != 0) + { + // Option 1: simply interpolate based on time, but stutter will happen, it's not that smooth. + // This is especially noticeable if the camera automatically follows the player + // - Tell SonarCloud this isn't really commented code but actual comments and to stfu about it + // - float t = CurrentInterpolationFactor(); + // - return Vector3.Lerp(start.position, goal.position, t); + + // Option 2: always += speed + // speed is 0 if we just started after idle, so always use max for best results + float speed = Mathf.Max(start.movementSpeed, goal.movementSpeed); + return Vector3.MoveTowards(currentPosition, goal.localPosition, speed * Time.deltaTime); + } + + return currentPosition; + } + + Quaternion InterpolateRotation(DataPoint start, DataPoint goal, Quaternion defaultRotation) + { + if (!interpolateRotation) + return defaultRotation; + + if (start.localRotation != goal.localRotation) + { + float t = CurrentInterpolationFactor(start, goal); + return Quaternion.Slerp(start.localRotation, goal.localRotation, t); + } + + return defaultRotation; + } + + Vector3 InterpolateScale(DataPoint start, DataPoint goal, Vector3 currentScale) + { + if (!interpolateScale) + return currentScale; + + if (start.localScale != goal.localScale) + { + float t = CurrentInterpolationFactor(start, goal); + return Vector3.Lerp(start.localScale, goal.localScale, t); + } + + return currentScale; + } + + static float CurrentInterpolationFactor(DataPoint start, DataPoint goal) + { + if (start.isValid) + { + float difference = goal.timeStamp - start.timeStamp; + + // the moment we get 'goal', 'start' is supposed to start, so elapsed time is based on: + float elapsed = Time.time - goal.timeStamp; + + // avoid NaN + return difference > 0 ? elapsed / difference : 1; + } + return 1; + } + + #region Server Teleport (force move player) + + /// + /// This method will override this GameObject's current Transform.localPosition to the specified Vector3 and update all clients. + /// NOTE: position must be in LOCAL space if the transform has a parent + /// + /// Where to teleport this GameObject + [Server] + public void ServerTeleport(Vector3 localPosition) + { + Quaternion localRotation = targetTransform.localRotation; + ServerTeleport(localPosition, localRotation); + } + + /// + /// This method will override this GameObject's current Transform.localPosition and Transform.localRotation + /// to the specified Vector3 and Quaternion and update all clients. + /// NOTE: localPosition must be in LOCAL space if the transform has a parent + /// NOTE: localRotation must be in LOCAL space if the transform has a parent + /// + /// Where to teleport this GameObject + /// Which rotation to set this GameObject + [Server] + public void ServerTeleport(Vector3 localPosition, Quaternion localRotation) + { + // To prevent applying the position updates received from client (if they have ClientAuth) while being teleported. + // clientAuthorityBeforeTeleport defaults to false when not teleporting, if it is true then it means that teleport + // was previously called but not finished therefore we should keep it as true so that 2nd teleport call doesn't clear authority + clientAuthorityBeforeTeleport = clientAuthority || clientAuthorityBeforeTeleport; + clientAuthority = false; + + DoTeleport(localPosition, localRotation); + + // tell all clients about new values + RpcTeleport(localPosition, Compression.CompressQuaternion(localRotation), clientAuthorityBeforeTeleport); + } + + void DoTeleport(Vector3 newLocalPosition, Quaternion newLocalRotation) + { + targetTransform.localPosition = newLocalPosition; + targetTransform.localRotation = newLocalRotation; + + // Since we are overriding the position we don't need a goal and start. + // Reset them to null for fresh start + goal = new DataPoint(); + start = new DataPoint(); + lastPosition = newLocalPosition; + lastRotation = newLocalRotation; + } + + [ClientRpc(channel = Channels.Unreliable)] + void RpcTeleport(Vector3 newPosition, uint newPackedRotation, bool isClientAuthority) + { + DoTeleport(newPosition, Compression.DecompressQuaternion(newPackedRotation)); + + // only send finished if is owner and is ClientAuthority on server + if (hasAuthority && isClientAuthority) + CmdTeleportFinished(); + } + + /// + /// This RPC will be invoked on server after client finishes overriding the position. + /// + /// + [Command(channel = Channels.Unreliable)] + void CmdTeleportFinished() + { + if (clientAuthorityBeforeTeleport) + { + clientAuthority = true; + + // reset value so doesn't effect future calls, see note in ServerTeleport + clientAuthorityBeforeTeleport = false; + } + else + { + Debug.LogWarning("Client called TeleportFinished when clientAuthority was false on server", this); + } + } + + #endregion + + #region Debug Gizmos + + // draw the data points for easier debugging + void OnDrawGizmos() + { + // draw start and goal points and a line between them + if (start.localPosition != goal.localPosition) + { + DrawDataPointGizmo(start, Color.yellow); + DrawDataPointGizmo(goal, Color.green); + DrawLineBetweenDataPoints(start, goal, Color.cyan); + } + } + + static void DrawDataPointGizmo(DataPoint data, Color color) + { + // use a little offset because transform.localPosition might be in the ground in many cases + Vector3 offset = Vector3.up * 0.01f; + + // draw position + Gizmos.color = color; + Gizmos.DrawSphere(data.localPosition + offset, 0.5f); + + // draw forward and up like unity move tool + Gizmos.color = Color.blue; + Gizmos.DrawRay(data.localPosition + offset, data.localRotation * Vector3.forward); + Gizmos.color = Color.green; + Gizmos.DrawRay(data.localPosition + offset, data.localRotation * Vector3.up); + } + + static void DrawLineBetweenDataPoints(DataPoint data1, DataPoint data2, Color color) + { + Gizmos.color = color; + Gizmos.DrawLine(data1.localPosition, data2.localPosition); + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs.meta b/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs.meta new file mode 100644 index 0000000..adf3755 --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea7c690c4fbf8c4439726f4c62eda6d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs b/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs new file mode 100644 index 0000000..44c49bd --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +namespace Mirror.Experimental +{ + /// + /// A component to synchronize the position of child transforms of networked objects. + /// There must be a NetworkTransform on the root object of the hierarchy. There can be multiple NetworkTransformChild components on an object. This does not use physics for synchronization, it simply synchronizes the localPosition and localRotation of the child transform and lerps towards the received values. + /// + [AddComponentMenu("Network/Experimental/NetworkTransformChildExperimentalExperimental")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-transform-child")] + public class NetworkTransformChild : NetworkTransformBase + { + [Header("Target")] + public Transform target; + + protected override Transform targetTransform => target; + } +} diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs.meta b/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs.meta new file mode 100644 index 0000000..2ed4212 --- /dev/null +++ b/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f65214da13a861f4a8ae309d3daea1c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/GUIConsole.cs b/Assets/Mirror/Components/GUIConsole.cs new file mode 100644 index 0000000..c738cae --- /dev/null +++ b/Assets/Mirror/Components/GUIConsole.cs @@ -0,0 +1,112 @@ +// People should be able to see and report errors to the developer very easily. +// +// Unity's Developer Console only works in development builds and it only shows +// errors. This class provides a console that works in all builds and also shows +// log and warnings in development builds. +// +// Note: we don't include the stack trace, because that can also be grabbed from +// the log files if needed. +// +// Note: there is no 'hide' button because we DO want people to see those errors +// and report them back to us. +// +// Note: normal Debug.Log messages can be shown by building in Debug/Development +// mode. +using UnityEngine; +using System.Collections.Generic; + +namespace Mirror +{ + struct LogEntry + { + public string message; + public LogType type; + + public LogEntry(string message, LogType type) + { + this.message = message; + this.type = type; + } + } + + public class GUIConsole : MonoBehaviour + { + public int height = 150; + + // only keep the recent 'n' entries. otherwise memory would grow forever + // and drawing would get slower and slower. + public int maxLogCount = 50; + + // log as queue so we can remove the first entry easily + Queue log = new Queue(); + + // hotkey to show/hide at runtime for easier debugging + // (sometimes we need to temporarily hide/show it) + // => F12 makes sense. nobody can find ^ in other games. + public KeyCode hotKey = KeyCode.F12; + + // GUI + bool visible; + Vector2 scroll = Vector2.zero; + + void Awake() + { + Application.logMessageReceived += OnLog; + } + + // OnLog logs everything, even Debug.Log messages in release builds + // => this makes a lot of things easier. e.g. addon initialization logs. + // => it's really better to have than not to have those + void OnLog(string message, string stackTrace, LogType type) + { + // is this important? + bool isImportant = type == LogType.Error || type == LogType.Exception; + + // use stack trace only if important + // (otherwise users would have to find and search the log file. + // seeing it in the console directly is way easier to deal with.) + // => only add \n if stack trace is available (only in debug builds) + if (isImportant && !string.IsNullOrWhiteSpace(stackTrace)) + message += "\n" + stackTrace; + + // add to queue + log.Enqueue(new LogEntry(message, type)); + + // respect max entries + if (log.Count > maxLogCount) + log.Dequeue(); + + // become visible if it was important + // (no need to become visible for regular log. let the user decide.) + if (isImportant) + visible = true; + + // auto scroll + scroll.y = float.MaxValue; + } + + void Update() + { + if (Input.GetKeyDown(hotKey)) + visible = !visible; + } + + void OnGUI() + { + if (!visible) return; + + scroll = GUILayout.BeginScrollView(scroll, "Box", GUILayout.Width(Screen.width), GUILayout.Height(height)); + foreach (LogEntry entry in log) + { + if (entry.type == LogType.Error || entry.type == LogType.Exception) + GUI.color = Color.red; + else if (entry.type == LogType.Warning) + GUI.color = Color.yellow; + + GUILayout.Label(entry.message); + GUI.color = Color.white; + } + GUILayout.EndScrollView(); + } + } +} diff --git a/Assets/Mirror/Components/GUIConsole.cs.meta b/Assets/Mirror/Components/GUIConsole.cs.meta new file mode 100644 index 0000000..933dd05 --- /dev/null +++ b/Assets/Mirror/Components/GUIConsole.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9021b6cc314944290986ab6feb48db79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/InterestManagement.meta b/Assets/Mirror/Components/InterestManagement.meta new file mode 100644 index 0000000..1b7a972 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c66f27e006ab94253b39a55a3b213651 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/InterestManagement/Distance.meta b/Assets/Mirror/Components/InterestManagement/Distance.meta new file mode 100644 index 0000000..832357e --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa4cbc6b9c584db4971985cb9f369077 +timeCreated: 1613110605 diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs new file mode 100644 index 0000000..111054a --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs @@ -0,0 +1,69 @@ +// straight forward Vector3.Distance based interest management. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public class DistanceInterestManagement : InterestManagement + { + [Tooltip("The maximum range that objects will be visible at. Add DistanceInterestManagementCustomRange onto NetworkIdentities for custom ranges.")] + public int visRange = 10; + + [Tooltip("Rebuild all every 'rebuildInterval' seconds.")] + public float rebuildInterval = 1; + double lastRebuildTime; + + // helper function to get vis range for a given object, or default. + int GetVisRange(NetworkIdentity identity) + { + DistanceInterestManagementCustomRange custom = identity.GetComponent(); + return custom != null ? custom.visRange : visRange; + } + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnection newObserver) + { + int range = GetVisRange(identity); + return Vector3.Distance(identity.transform.position, newObserver.identity.transform.position) < range; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers, bool initialize) + { + // cache range and .transform because both call GetComponent. + int range = GetVisRange(identity); + Vector3 position = identity.transform.position; + + // brute force distance check + // -> only player connections can be observers, so it's enough if we + // go through all connections instead of all spawned identities. + // -> compared to UNET's sphere cast checking, this one is orders of + // magnitude faster. if we have 10k monsters and run a sphere + // cast 10k times, we will see a noticeable lag even with physics + // layers. but checking to every connection is fast. + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + // authenticated and joined world with a player? + if (conn != null && conn.isAuthenticated && conn.identity != null) + { + // check distance + if (Vector3.Distance(conn.identity.transform.position, position) < range) + { + newObservers.Add(conn); + } + } + } + } + + void Update() + { + // only on server + if (!NetworkServer.active) return; + + // rebuild all spawned NetworkIdentity's observers every interval + if (NetworkTime.localTime >= lastRebuildTime + rebuildInterval) + { + RebuildAll(); + lastRebuildTime = NetworkTime.localTime; + } + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs.meta new file mode 100644 index 0000000..6adbd65 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f60becab051427fbdd3c8ac9ab4712b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs new file mode 100644 index 0000000..03b1fc5 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs @@ -0,0 +1,14 @@ +// add this to NetworkIdentities for custom range if needed. +// only works with DistanceInterestManagement. +using UnityEngine; + +namespace Mirror +{ + [RequireComponent(typeof(NetworkIdentity))] + [DisallowMultipleComponent] + public class DistanceInterestManagementCustomRange : MonoBehaviour + { + [Tooltip("The maximum range that objects will be visible at.")] + public int visRange = 20; + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs.meta b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs.meta new file mode 100644 index 0000000..2915984 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2e242ee38a14076a39934172a19079b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/InterestManagement/Match.meta b/Assets/Mirror/Components/InterestManagement/Match.meta new file mode 100644 index 0000000..2cfaabc --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5eca5245ae6bb460e9a92f7e14d5493a +timeCreated: 1622649517 diff --git a/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs new file mode 100644 index 0000000..2f0be4d --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; + +namespace Mirror +{ + public class MatchInterestManagement : InterestManagement + { + readonly Dictionary> matchObjects = + new Dictionary>(); + + readonly Dictionary lastObjectMatch = + new Dictionary(); + + HashSet dirtyMatches = new HashSet(); + + public override void OnSpawned(NetworkIdentity identity) + { + Guid currentMatch = identity.GetComponent().matchId; + lastObjectMatch[identity] = currentMatch; + + // Guid.Empty is never a valid matchId...do not add to matchObjects collection + if (currentMatch == Guid.Empty) return; + + // Debug.Log($"MatchInterestManagement.OnSpawned({identity.name}) currentMatch: {currentMatch}"); + if (!matchObjects.TryGetValue(currentMatch, out HashSet objects)) + { + objects = new HashSet(); + matchObjects.Add(currentMatch, objects); + } + + objects.Add(identity); + } + + public override void OnDestroyed(NetworkIdentity identity) + { + Guid currentMatch = lastObjectMatch[identity]; + lastObjectMatch.Remove(identity); + if (currentMatch != Guid.Empty && matchObjects.TryGetValue(currentMatch, out HashSet objects) && objects.Remove(identity)) + RebuildMatchObservers(currentMatch); + } + + void Update() + { + // only on server + if (!NetworkServer.active) return; + + // for each spawned: + // if match changed: + // add previous to dirty + // add new to dirty + foreach (NetworkIdentity netIdentity in NetworkServer.spawned.Values) + { + Guid currentMatch = lastObjectMatch[netIdentity]; + Guid newMatch = netIdentity.GetComponent().matchId; + if (newMatch == currentMatch) continue; + + // Mark new/old scenes as dirty so they get rebuilt + // Guid.Empty is never a valid matchId + if (currentMatch != Guid.Empty) + dirtyMatches.Add(currentMatch); + dirtyMatches.Add(newMatch); + + // This object is in a new match so observers in the prior match + // and the new scene need to rebuild their respective observers lists. + + // Remove this object from the hashset of the match it just left + // Guid.Empty is never a valid matchId + if (currentMatch != Guid.Empty) + matchObjects[currentMatch].Remove(netIdentity); + + // Set this to the new match this object just entered + lastObjectMatch[netIdentity] = newMatch; + + // Guid.Empty is never a valid matchId...do not add to matchObjects collection + if (newMatch == Guid.Empty) continue; + + + // Make sure this new match is in the dictionary + if (!matchObjects.ContainsKey(newMatch)) + matchObjects.Add(newMatch, new HashSet()); + + // Add this object to the hashset of the new match + matchObjects[newMatch].Add(netIdentity); + } + + // rebuild all dirty matchs + foreach (Guid dirtyMatch in dirtyMatches) + { + RebuildMatchObservers(dirtyMatch); + } + + dirtyMatches.Clear(); + } + + void RebuildMatchObservers(Guid matchId) + { + foreach (NetworkIdentity netIdentity in matchObjects[matchId]) + if (netIdentity != null) + NetworkServer.RebuildObservers(netIdentity, false); + } + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnection newObserver) + { + return identity.GetComponent().matchId == + newObserver.identity.GetComponent().matchId; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers, + bool initialize) + { + Guid matchId = identity.GetComponent().matchId; + + // Guid.Empty is never a valid matchId + if (matchId == Guid.Empty) return; + + if (!matchObjects.TryGetValue(matchId, out HashSet objects)) + return; + + // Add everything in the hashset for this object's current match + foreach (NetworkIdentity networkIdentity in objects) + if (networkIdentity != null && networkIdentity.connectionToClient != null) + newObservers.Add(networkIdentity.connectionToClient); + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs.meta new file mode 100644 index 0000000..c7dbf1d --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d09f5c8bf2f4747b7a9284ef5d9ce2a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/InterestManagement/Scene.meta b/Assets/Mirror/Components/InterestManagement/Scene.meta new file mode 100644 index 0000000..f1fa700 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Scene.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7655d309a46a4bd4860edf964228b3f6 +timeCreated: 1622649517 diff --git a/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs new file mode 100644 index 0000000..fca09ff --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using UnityEngine.SceneManagement; + +namespace Mirror +{ + public class SceneInterestManagement : InterestManagement + { + // Use Scene instead of string scene.name because when additively + // loading multiples of a subscene the name won't be unique + readonly Dictionary> sceneObjects = + new Dictionary>(); + + readonly Dictionary lastObjectScene = + new Dictionary(); + + HashSet dirtyScenes = new HashSet(); + + public override void OnSpawned(NetworkIdentity identity) + { + Scene currentScene = identity.gameObject.scene; + lastObjectScene[identity] = currentScene; + // Debug.Log($"SceneInterestManagement.OnSpawned({identity.name}) currentScene: {currentScene}"); + if (!sceneObjects.TryGetValue(currentScene, out HashSet objects)) + { + objects = new HashSet(); + sceneObjects.Add(currentScene, objects); + } + + objects.Add(identity); + } + + public override void OnDestroyed(NetworkIdentity identity) + { + Scene currentScene = lastObjectScene[identity]; + lastObjectScene.Remove(identity); + if (sceneObjects.TryGetValue(currentScene, out HashSet objects) && objects.Remove(identity)) + RebuildSceneObservers(currentScene); + } + + void Update() + { + // only on server + if (!NetworkServer.active) return; + + // for each spawned: + // if scene changed: + // add previous to dirty + // add new to dirty + foreach (NetworkIdentity identity in NetworkServer.spawned.Values) + { + Scene currentScene = lastObjectScene[identity]; + Scene newScene = identity.gameObject.scene; + if (newScene == currentScene) continue; + + // Mark new/old scenes as dirty so they get rebuilt + dirtyScenes.Add(currentScene); + dirtyScenes.Add(newScene); + + // This object is in a new scene so observers in the prior scene + // and the new scene need to rebuild their respective observers lists. + + // Remove this object from the hashset of the scene it just left + sceneObjects[currentScene].Remove(identity); + + // Set this to the new scene this object just entered + lastObjectScene[identity] = newScene; + + // Make sure this new scene is in the dictionary + if (!sceneObjects.ContainsKey(newScene)) + sceneObjects.Add(newScene, new HashSet()); + + // Add this object to the hashset of the new scene + sceneObjects[newScene].Add(identity); + } + + // rebuild all dirty scenes + foreach (Scene dirtyScene in dirtyScenes) + { + RebuildSceneObservers(dirtyScene); + } + + dirtyScenes.Clear(); + } + + void RebuildSceneObservers(Scene scene) + { + foreach (NetworkIdentity netIdentity in sceneObjects[scene]) + if (netIdentity != null) + NetworkServer.RebuildObservers(netIdentity, false); + } + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnection newObserver) + { + return identity.gameObject.scene == newObserver.identity.gameObject.scene; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers, + bool initialize) + { + if (!sceneObjects.TryGetValue(identity.gameObject.scene, out HashSet objects)) + return; + + // Add everything in the hashset for this object's current scene + foreach (NetworkIdentity networkIdentity in objects) + if (networkIdentity != null && networkIdentity.connectionToClient != null) + newObservers.Add(networkIdentity.connectionToClient); + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs.meta new file mode 100644 index 0000000..dee4865 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b979f26c95d34324ba005bfacfa9c4fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing.meta new file mode 100644 index 0000000..6a35e1e --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cfa12b73503344d49b398b01bcb07967 +timeCreated: 1613110634 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs new file mode 100644 index 0000000..88f7197 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs @@ -0,0 +1,88 @@ +// Grid2D from uMMORPG: get/set values of type T at any point +// -> not named 'Grid' because Unity already has a Grid type. causes warnings. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public class Grid2D + { + // the grid + // note that we never remove old keys. + // => over time, HashSets will be allocated for every possible + // grid position in the world + // => Clear() doesn't clear them so we don't constantly reallocate the + // entries when populating the grid in every Update() call + // => makes the code a lot easier too + // => this is FINE because in the worst case, every grid position in the + // game world is filled with a player anyway! + Dictionary> grid = new Dictionary>(); + + // cache a 9 neighbor grid of vector2 offsets so we can use them more easily + Vector2Int[] neighbourOffsets = + { + Vector2Int.up, + Vector2Int.up + Vector2Int.left, + Vector2Int.up + Vector2Int.right, + Vector2Int.left, + Vector2Int.zero, + Vector2Int.right, + Vector2Int.down, + Vector2Int.down + Vector2Int.left, + Vector2Int.down + Vector2Int.right + }; + + // helper function so we can add an entry without worrying + public void Add(Vector2Int position, T value) + { + // initialize set in grid if it's not in there yet + if (!grid.TryGetValue(position, out HashSet hashSet)) + { + hashSet = new HashSet(); + grid[position] = hashSet; + } + + // add to it + hashSet.Add(value); + } + + // helper function to get set at position without worrying + // -> result is passed as parameter to avoid allocations + // -> result is not cleared before. this allows us to pass the HashSet from + // GetWithNeighbours and avoid .UnionWith which is very expensive. + void GetAt(Vector2Int position, HashSet result) + { + // return the set at position + if (grid.TryGetValue(position, out HashSet hashSet)) + { + foreach (T entry in hashSet) + result.Add(entry); + } + } + + // helper function to get at position and it's 8 neighbors without worrying + // -> result is passed as parameter to avoid allocations + public void GetWithNeighbours(Vector2Int position, HashSet result) + { + // clear result first + result.Clear(); + + // add neighbours + foreach (Vector2Int offset in neighbourOffsets) + GetAt(position + offset, result); + } + + // clear: clears the whole grid + // IMPORTANT: we already allocated HashSets and don't want to do + // reallocate every single update when we rebuild the grid. + // => so simply remove each position's entries, but keep + // every position in there + // => see 'grid' comments above! + // => named ClearNonAlloc to make it more obvious! + public void ClearNonAlloc() + { + foreach (HashSet hashSet in grid.Values) + hashSet.Clear(); + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs.meta new file mode 100644 index 0000000..4448994 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c5232a4d2854116a35d52b80ec07752 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs new file mode 100644 index 0000000..f204a8d --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs @@ -0,0 +1,139 @@ +// extremely fast spatial hashing interest management based on uMMORPG GridChecker. +// => 30x faster in initial tests +// => scales way higher +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public class SpatialHashingInterestManagement : InterestManagement + { + [Tooltip("The maximum range that objects will be visible at.")] + public int visRange = 30; + + // if we see 8 neighbors then 1 entry is visRange/3 + public int resolution => visRange / 3; + + [Tooltip("Rebuild all every 'rebuildInterval' seconds.")] + public float rebuildInterval = 1; + double lastRebuildTime; + + public enum CheckMethod + { + XZ_FOR_3D, + XY_FOR_2D + } + [Tooltip("Spatial Hashing supports 3D (XZ) and 2D (XY) games.")] + public CheckMethod checkMethod = CheckMethod.XZ_FOR_3D; + + // debugging + public bool showSlider; + + // the grid + Grid2D grid = new Grid2D(); + + // project 3d world position to grid position + Vector2Int ProjectToGrid(Vector3 position) => + checkMethod == CheckMethod.XZ_FOR_3D + ? Vector2Int.RoundToInt(new Vector2(position.x, position.z) / resolution) + : Vector2Int.RoundToInt(new Vector2(position.x, position.y) / resolution); + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnection newObserver) + { + // calculate projected positions + Vector2Int projected = ProjectToGrid(identity.transform.position); + Vector2Int observerProjected = ProjectToGrid(newObserver.identity.transform.position); + + // distance needs to be at max one of the 8 neighbors, which is + // 1 for the direct neighbors + // 1.41 for the diagonal neighbors (= sqrt(2)) + // => use sqrMagnitude and '2' to avoid computations. same result. + return (projected - observerProjected).sqrMagnitude <= 2; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers, bool initialize) + { + // add everyone in 9 neighbour grid + // -> pass observers to GetWithNeighbours directly to avoid allocations + // and expensive .UnionWith computations. + Vector2Int current = ProjectToGrid(identity.transform.position); + grid.GetWithNeighbours(current, newObservers); + } + + // update everyone's position in the grid + // (internal so we can update from tests) + internal void Update() + { + // only on server + if (!NetworkServer.active) return; + + // NOTE: unlike Scene/MatchInterestManagement, this rebuilds ALL + // entities every INTERVAL. consider the other approach later. + + // IMPORTANT: refresh grid every update! + // => newly spawned entities get observers assigned via + // OnCheckObservers. this can happen any time and we don't want + // them broadcast to old (moved or destroyed) connections. + // => players do move all the time. we want them to always be in the + // correct grid position. + // => note that the actual 'rebuildall' doesn't need to happen all + // the time. + // NOTE: consider refreshing grid only every 'interval' too. but not + // for now. stability & correctness matter. + + // clear old grid results before we update everyone's position. + // (this way we get rid of destroyed connections automatically) + // + // NOTE: keeps allocated HashSets internally. + // clearing & populating every frame works without allocations + grid.ClearNonAlloc(); + + // put every connection into the grid at it's main player's position + // NOTE: player sees in a radius around him. NOT around his pet too. + foreach (NetworkConnectionToClient connection in NetworkServer.connections.Values) + { + // authenticated and joined world with a player? + if (connection.isAuthenticated && connection.identity != null) + { + // calculate current grid position + Vector2Int position = ProjectToGrid(connection.identity.transform.position); + + // put into grid + grid.Add(position, connection); + } + } + + // rebuild all spawned entities' observers every 'interval' + // this will call OnRebuildObservers which then returns the + // observers at grid[position] for each entity. + if (NetworkTime.localTime >= lastRebuildTime + rebuildInterval) + { + RebuildAll(); + lastRebuildTime = NetworkTime.localTime; + } + } + +// OnGUI allocates even if it does nothing. avoid in release. +#if UNITY_EDITOR || DEVELOPMENT_BUILD + // slider from dotsnet. it's nice to play around with in the benchmark + // demo. + void OnGUI() + { + if (!showSlider) return; + + // only show while server is running. not on client, etc. + if (!NetworkServer.active) return; + + int height = 30; + int width = 250; + GUILayout.BeginArea(new Rect(Screen.width / 2 - width / 2, Screen.height - height, width, height)); + GUILayout.BeginHorizontal("Box"); + GUILayout.Label("Radius:"); + visRange = Mathf.RoundToInt(GUILayout.HorizontalSlider(visRange, 0, 200, GUILayout.Width(150))); + GUILayout.Label(visRange.ToString()); + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } +#endif + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs.meta new file mode 100644 index 0000000..5f5007e --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 39adc6e09d5544ed955a50ce8600355a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/Mirror.Components.asmdef b/Assets/Mirror/Components/Mirror.Components.asmdef new file mode 100644 index 0000000..a61c7db --- /dev/null +++ b/Assets/Mirror/Components/Mirror.Components.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Mirror.Components", + "references": [ + "Mirror" + ], + "optionalUnityReferences": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Mirror/Components/Mirror.Components.asmdef.meta b/Assets/Mirror/Components/Mirror.Components.asmdef.meta new file mode 100644 index 0000000..59c31c8 --- /dev/null +++ b/Assets/Mirror/Components/Mirror.Components.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 72872094b21c16e48b631b2224833d49 +AssemblyDefinitionImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkAnimator.cs b/Assets/Mirror/Components/NetworkAnimator.cs new file mode 100644 index 0000000..b69458a --- /dev/null +++ b/Assets/Mirror/Components/NetworkAnimator.cs @@ -0,0 +1,634 @@ +using System.Linq; +using UnityEngine; +using UnityEngine.Serialization; + +namespace Mirror +{ + /// + /// A component to synchronize Mecanim animation states for networked objects. + /// + /// + /// The animation of game objects can be networked by this component. There are two models of authority for networked movement: + /// If the object has authority on the client, then it should be animated locally on the owning client. The animation state information will be sent from the owning client to the server, then broadcast to all of the other clients. This is common for player objects. + /// If the object has authority on the server, then it should be animated on the server and state information will be sent to all clients. This is common for objects not related to a specific client, such as an enemy unit. + /// The NetworkAnimator synchronizes all animation parameters of the selected Animator. It does not automatically synchronize triggers. The function SetTrigger can by used by an object with authority to fire an animation trigger on other clients. + /// + [AddComponentMenu("Network/NetworkAnimator")] + [RequireComponent(typeof(NetworkIdentity))] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-animator")] + public class NetworkAnimator : NetworkBehaviour + { + [Header("Authority")] + [Tooltip("Set to true if animations come from owner client, set to false if animations always come from server")] + public bool clientAuthority; + + /// + /// The animator component to synchronize. + /// + [FormerlySerializedAs("m_Animator")] + [Header("Animator")] + [Tooltip("Animator that will have parameters synchronized")] + public Animator animator; + + /// + /// Syncs animator.speed + /// + [SyncVar(hook = nameof(OnAnimatorSpeedChanged))] + float animatorSpeed; + float previousSpeed; + + // Note: not an object[] array because otherwise initialization is real annoying + int[] lastIntParameters; + float[] lastFloatParameters; + bool[] lastBoolParameters; + AnimatorControllerParameter[] parameters; + + // multiple layers + int[] animationHash; + int[] transitionHash; + float[] layerWeight; + double nextSendTime; + + bool SendMessagesAllowed + { + get + { + if (isServer) + { + if (!clientAuthority) + return true; + + // This is a special case where we have client authority but we have not assigned the client who has + // authority over it, no animator data will be sent over the network by the server. + // + // So we check here for a connectionToClient and if it is null we will + // let the server send animation data until we receive an owner. + if (netIdentity != null && netIdentity.connectionToClient == null) + return true; + } + + return (hasAuthority && clientAuthority); + } + } + + void Awake() + { + // store the animator parameters in a variable - the "Animator.parameters" getter allocates + // a new parameter array every time it is accessed so we should avoid doing it in a loop + parameters = animator.parameters + .Where(par => !animator.IsParameterControlledByCurve(par.nameHash)) + .ToArray(); + lastIntParameters = new int[parameters.Length]; + lastFloatParameters = new float[parameters.Length]; + lastBoolParameters = new bool[parameters.Length]; + + animationHash = new int[animator.layerCount]; + transitionHash = new int[animator.layerCount]; + layerWeight = new float[animator.layerCount]; + } + + void FixedUpdate() + { + if (!SendMessagesAllowed) + return; + + if (!animator.enabled) + return; + + CheckSendRate(); + + for (int i = 0; i < animator.layerCount; i++) + { + int stateHash; + float normalizedTime; + if (!CheckAnimStateChanged(out stateHash, out normalizedTime, i)) + { + continue; + } + + using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) + { + WriteParameters(writer); + SendAnimationMessage(stateHash, normalizedTime, i, layerWeight[i], writer.ToArray()); + } + } + + CheckSpeed(); + } + + void CheckSpeed() + { + float newSpeed = animator.speed; + if (Mathf.Abs(previousSpeed - newSpeed) > 0.001f) + { + previousSpeed = newSpeed; + if (isServer) + { + animatorSpeed = newSpeed; + } + else if (isClient) + { + CmdSetAnimatorSpeed(newSpeed); + } + } + } + + void OnAnimatorSpeedChanged(float _, float value) + { + // skip if host or client with authority + // they will have already set the speed so don't set again + if (isServer || (hasAuthority && clientAuthority)) + return; + + animator.speed = value; + } + + bool CheckAnimStateChanged(out int stateHash, out float normalizedTime, int layerId) + { + bool change = false; + stateHash = 0; + normalizedTime = 0; + + float lw = animator.GetLayerWeight(layerId); + if (Mathf.Abs(lw - layerWeight[layerId]) > 0.001f) + { + layerWeight[layerId] = lw; + change = true; + } + + if (animator.IsInTransition(layerId)) + { + AnimatorTransitionInfo tt = animator.GetAnimatorTransitionInfo(layerId); + if (tt.fullPathHash != transitionHash[layerId]) + { + // first time in this transition + transitionHash[layerId] = tt.fullPathHash; + animationHash[layerId] = 0; + return true; + } + return change; + } + + AnimatorStateInfo st = animator.GetCurrentAnimatorStateInfo(layerId); + if (st.fullPathHash != animationHash[layerId]) + { + // first time in this animation state + if (animationHash[layerId] != 0) + { + // came from another animation directly - from Play() + stateHash = st.fullPathHash; + normalizedTime = st.normalizedTime; + } + transitionHash[layerId] = 0; + animationHash[layerId] = st.fullPathHash; + return true; + } + return change; + } + + void CheckSendRate() + { + double now = NetworkTime.localTime; + if (SendMessagesAllowed && syncInterval >= 0 && now > nextSendTime) + { + nextSendTime = now + syncInterval; + + using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) + { + if (WriteParameters(writer)) + SendAnimationParametersMessage(writer.ToArray()); + } + } + } + + void SendAnimationMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) + { + if (isServer) + { + RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters); + } + else if (isClient) + { + CmdOnAnimationServerMessage(stateHash, normalizedTime, layerId, weight, parameters); + } + } + + void SendAnimationParametersMessage(byte[] parameters) + { + if (isServer) + { + RpcOnAnimationParametersClientMessage(parameters); + } + else if (isClient) + { + CmdOnAnimationParametersServerMessage(parameters); + } + } + + void HandleAnimMsg(int stateHash, float normalizedTime, int layerId, float weight, NetworkReader reader) + { + if (hasAuthority && clientAuthority) + return; + + // usually transitions will be triggered by parameters, if not, play anims directly. + // NOTE: this plays "animations", not transitions, so any transitions will be skipped. + // NOTE: there is no API to play a transition(?) + if (stateHash != 0 && animator.enabled) + { + animator.Play(stateHash, layerId, normalizedTime); + } + + animator.SetLayerWeight(layerId, weight); + + ReadParameters(reader); + } + + void HandleAnimParamsMsg(NetworkReader reader) + { + if (hasAuthority && clientAuthority) + return; + + ReadParameters(reader); + } + + void HandleAnimTriggerMsg(int hash) + { + if (animator.enabled) + animator.SetTrigger(hash); + } + + void HandleAnimResetTriggerMsg(int hash) + { + if (animator.enabled) + animator.ResetTrigger(hash); + } + + ulong NextDirtyBits() + { + ulong dirtyBits = 0; + for (int i = 0; i < parameters.Length; i++) + { + AnimatorControllerParameter par = parameters[i]; + bool changed = false; + if (par.type == AnimatorControllerParameterType.Int) + { + int newIntValue = animator.GetInteger(par.nameHash); + changed = newIntValue != lastIntParameters[i]; + if (changed) + lastIntParameters[i] = newIntValue; + } + else if (par.type == AnimatorControllerParameterType.Float) + { + float newFloatValue = animator.GetFloat(par.nameHash); + changed = Mathf.Abs(newFloatValue - lastFloatParameters[i]) > 0.001f; + // only set lastValue if it was changed, otherwise value could slowly drift within the 0.001f limit each frame + if (changed) + lastFloatParameters[i] = newFloatValue; + } + else if (par.type == AnimatorControllerParameterType.Bool) + { + bool newBoolValue = animator.GetBool(par.nameHash); + changed = newBoolValue != lastBoolParameters[i]; + if (changed) + lastBoolParameters[i] = newBoolValue; + } + if (changed) + { + dirtyBits |= 1ul << i; + } + } + return dirtyBits; + } + + bool WriteParameters(NetworkWriter writer, bool forceAll = false) + { + ulong dirtyBits = forceAll ? (~0ul) : NextDirtyBits(); + writer.WriteULong(dirtyBits); + for (int i = 0; i < parameters.Length; i++) + { + if ((dirtyBits & (1ul << i)) == 0) + continue; + + AnimatorControllerParameter par = parameters[i]; + if (par.type == AnimatorControllerParameterType.Int) + { + int newIntValue = animator.GetInteger(par.nameHash); + writer.WriteInt(newIntValue); + } + else if (par.type == AnimatorControllerParameterType.Float) + { + float newFloatValue = animator.GetFloat(par.nameHash); + writer.WriteFloat(newFloatValue); + } + else if (par.type == AnimatorControllerParameterType.Bool) + { + bool newBoolValue = animator.GetBool(par.nameHash); + writer.WriteBool(newBoolValue); + } + } + return dirtyBits != 0; + } + + void ReadParameters(NetworkReader reader) + { + bool animatorEnabled = animator.enabled; + // need to read values from NetworkReader even if animator is disabled + + ulong dirtyBits = reader.ReadULong(); + for (int i = 0; i < parameters.Length; i++) + { + if ((dirtyBits & (1ul << i)) == 0) + continue; + + AnimatorControllerParameter par = parameters[i]; + if (par.type == AnimatorControllerParameterType.Int) + { + int newIntValue = reader.ReadInt(); + if (animatorEnabled) + animator.SetInteger(par.nameHash, newIntValue); + } + else if (par.type == AnimatorControllerParameterType.Float) + { + float newFloatValue = reader.ReadFloat(); + if (animatorEnabled) + animator.SetFloat(par.nameHash, newFloatValue); + } + else if (par.type == AnimatorControllerParameterType.Bool) + { + bool newBoolValue = reader.ReadBool(); + if (animatorEnabled) + animator.SetBool(par.nameHash, newBoolValue); + } + } + } + + /// + /// Custom Serialization + /// + /// + /// + /// + public override bool OnSerialize(NetworkWriter writer, bool initialState) + { + bool changed = base.OnSerialize(writer, initialState); + if (initialState) + { + for (int i = 0; i < animator.layerCount; i++) + { + if (animator.IsInTransition(i)) + { + AnimatorStateInfo st = animator.GetNextAnimatorStateInfo(i); + writer.WriteInt(st.fullPathHash); + writer.WriteFloat(st.normalizedTime); + } + else + { + AnimatorStateInfo st = animator.GetCurrentAnimatorStateInfo(i); + writer.WriteInt(st.fullPathHash); + writer.WriteFloat(st.normalizedTime); + } + writer.WriteFloat(animator.GetLayerWeight(i)); + } + WriteParameters(writer, initialState); + return true; + } + return changed; + } + + /// + /// Custom Deserialization + /// + /// + /// + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + base.OnDeserialize(reader, initialState); + if (initialState) + { + for (int i = 0; i < animator.layerCount; i++) + { + int stateHash = reader.ReadInt(); + float normalizedTime = reader.ReadFloat(); + animator.SetLayerWeight(i, reader.ReadFloat()); + animator.Play(stateHash, i, normalizedTime); + } + + ReadParameters(reader); + } + } + + /// + /// Causes an animation trigger to be invoked for a networked object. + /// If local authority is set, and this is called from the client, then the trigger will be invoked on the server and all clients. If not, then this is called on the server, and the trigger will be called on all clients. + /// + /// Name of trigger. + public void SetTrigger(string triggerName) + { + SetTrigger(Animator.StringToHash(triggerName)); + } + + /// + /// Causes an animation trigger to be invoked for a networked object. + /// + /// Hash id of trigger (from the Animator). + public void SetTrigger(int hash) + { + if (clientAuthority) + { + if (!isClient) + { + Debug.LogWarning("Tried to set animation in the server for a client-controlled animator"); + return; + } + + if (!hasAuthority) + { + Debug.LogWarning("Only the client with authority can set animations"); + return; + } + + if (isClient) + CmdOnAnimationTriggerServerMessage(hash); + + // call on client right away + HandleAnimTriggerMsg(hash); + } + else + { + if (!isServer) + { + Debug.LogWarning("Tried to set animation in the client for a server-controlled animator"); + return; + } + + HandleAnimTriggerMsg(hash); + RpcOnAnimationTriggerClientMessage(hash); + } + } + + /// + /// Causes an animation trigger to be reset for a networked object. + /// If local authority is set, and this is called from the client, then the trigger will be reset on the server and all clients. If not, then this is called on the server, and the trigger will be reset on all clients. + /// + /// Name of trigger. + public void ResetTrigger(string triggerName) + { + ResetTrigger(Animator.StringToHash(triggerName)); + } + + /// + /// Causes an animation trigger to be reset for a networked object. + /// + /// Hash id of trigger (from the Animator). + public void ResetTrigger(int hash) + { + if (clientAuthority) + { + if (!isClient) + { + Debug.LogWarning("Tried to reset animation in the server for a client-controlled animator"); + return; + } + + if (!hasAuthority) + { + Debug.LogWarning("Only the client with authority can reset animations"); + return; + } + + if (isClient) + CmdOnAnimationResetTriggerServerMessage(hash); + + // call on client right away + HandleAnimResetTriggerMsg(hash); + } + else + { + if (!isServer) + { + Debug.LogWarning("Tried to reset animation in the client for a server-controlled animator"); + return; + } + + HandleAnimResetTriggerMsg(hash); + RpcOnAnimationResetTriggerClientMessage(hash); + } + } + + #region server message handlers + + [Command] + void CmdOnAnimationServerMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // Debug.Log("OnAnimationMessage for netId=" + netId); + + // handle and broadcast + using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) + { + HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader); + RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters); + } + } + + [Command] + void CmdOnAnimationParametersServerMessage(byte[] parameters) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // handle and broadcast + using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) + { + HandleAnimParamsMsg(networkReader); + RpcOnAnimationParametersClientMessage(parameters); + } + } + + [Command] + void CmdOnAnimationTriggerServerMessage(int hash) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // handle and broadcast + // host should have already the trigger + bool isHostOwner = isClient && hasAuthority; + if (!isHostOwner) + { + HandleAnimTriggerMsg(hash); + } + + RpcOnAnimationTriggerClientMessage(hash); + } + + [Command] + void CmdOnAnimationResetTriggerServerMessage(int hash) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // handle and broadcast + // host should have already the trigger + bool isHostOwner = isClient && hasAuthority; + if (!isHostOwner) + { + HandleAnimResetTriggerMsg(hash); + } + + RpcOnAnimationResetTriggerClientMessage(hash); + } + + [Command] + void CmdSetAnimatorSpeed(float newSpeed) + { + // set animator + animator.speed = newSpeed; + animatorSpeed = newSpeed; + } + + #endregion + + #region client message handlers + + [ClientRpc] + void RpcOnAnimationClientMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) + { + using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) + HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader); + } + + [ClientRpc] + void RpcOnAnimationParametersClientMessage(byte[] parameters) + { + using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) + HandleAnimParamsMsg(networkReader); + } + + [ClientRpc] + void RpcOnAnimationTriggerClientMessage(int hash) + { + // host/owner handles this before it is sent + if (isServer || (clientAuthority && hasAuthority)) return; + + HandleAnimTriggerMsg(hash); + } + + [ClientRpc] + void RpcOnAnimationResetTriggerClientMessage(int hash) + { + // host/owner handles this before it is sent + if (isServer || (clientAuthority && hasAuthority)) return; + + HandleAnimResetTriggerMsg(hash); + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/NetworkAnimator.cs.meta b/Assets/Mirror/Components/NetworkAnimator.cs.meta new file mode 100644 index 0000000..7b0d8d1 --- /dev/null +++ b/Assets/Mirror/Components/NetworkAnimator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f6f3bf89aa97405989c802ba270f815 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkLobbyManager.cs b/Assets/Mirror/Components/NetworkLobbyManager.cs new file mode 100644 index 0000000..6ea069a --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyManager.cs @@ -0,0 +1,18 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// This is a specialized NetworkManager that includes a networked lobby. + /// + /// + /// The lobby has slots that track the joined players, and a maximum player count that is enforced. It requires that the NetworkLobbyPlayer component be on the lobby player objects. + /// NetworkLobbyManager is derived from NetworkManager, and so it implements many of the virtual functions provided by the NetworkManager class. To avoid accidentally replacing functionality of the NetworkLobbyManager, there are new virtual functions on the NetworkLobbyManager that begin with "OnLobby". These should be used on classes derived from NetworkLobbyManager instead of the virtual functions on NetworkManager. + /// The OnLobby*() functions have empty implementations on the NetworkLobbyManager base class, so the base class functions do not have to be called. + /// + [AddComponentMenu("Network/NetworkLobbyManager")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-manager")] + [Obsolete("Use / inherit from NetworkRoomManager instead")] + public class NetworkLobbyManager : NetworkRoomManager {} +} diff --git a/Assets/Mirror/Components/NetworkLobbyManager.cs.meta b/Assets/Mirror/Components/NetworkLobbyManager.cs.meta new file mode 100644 index 0000000..7fdd9ef --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4c96e6dd99826849ab1431f94547141 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkLobbyPlayer.cs b/Assets/Mirror/Components/NetworkLobbyPlayer.cs new file mode 100644 index 0000000..cf18566 --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyPlayer.cs @@ -0,0 +1,15 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// This component works in conjunction with the NetworkLobbyManager to make up the multiplayer lobby system. + /// The LobbyPrefab object of the NetworkLobbyManager must have this component on it. This component holds basic lobby player data required for the lobby to function. Game specific data for lobby players can be put in other components on the LobbyPrefab or in scripts derived from NetworkLobbyPlayer. + /// + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkLobbyPlayer")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-player")] + [Obsolete("Use / inherit from NetworkRoomPlayer instead")] + public class NetworkLobbyPlayer : NetworkRoomPlayer {} +} diff --git a/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta b/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta new file mode 100644 index 0000000..7dfc205 --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 777a368af85f2e84da7ea5666581921b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkMatch.cs b/Assets/Mirror/Components/NetworkMatch.cs new file mode 100644 index 0000000..70cdfa4 --- /dev/null +++ b/Assets/Mirror/Components/NetworkMatch.cs @@ -0,0 +1,11 @@ +// simple component that holds match information +using System; + +namespace Mirror +{ + public class NetworkMatch : NetworkBehaviour + { + ///Set this to the same value on all networked objects that belong to a given match + public Guid matchId; + } +} diff --git a/Assets/Mirror/Components/NetworkMatch.cs.meta b/Assets/Mirror/Components/NetworkMatch.cs.meta new file mode 100644 index 0000000..d655ca1 --- /dev/null +++ b/Assets/Mirror/Components/NetworkMatch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d17e718851449a6879986e45c458fb7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkMatchChecker.cs b/Assets/Mirror/Components/NetworkMatchChecker.cs new file mode 100644 index 0000000..8743337 --- /dev/null +++ b/Assets/Mirror/Components/NetworkMatchChecker.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + /// + /// Component that controls visibility of networked objects based on match id. + /// Any object with this component on it will only be visible to other objects in the same match. + /// This would be used to isolate players to their respective matches within a single game server instance. + /// + // Deprecated 2021-02-17 + [Obsolete(NetworkVisibilityObsoleteMessage.Message)] + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkMatchChecker")] + [RequireComponent(typeof(NetworkIdentity))] + [RequireComponent(typeof(NetworkMatch))] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-match-checker")] + public class NetworkMatchChecker : NetworkVisibility + { + // internal for tests + internal static readonly Dictionary> matchPlayers = + new Dictionary>(); + + // internal for tests + internal Guid currentMatch + { + get => GetComponent().matchId; + set => GetComponent().matchId = value; + } + + internal Guid lastMatch; + + public override void OnStartServer() + { + if (currentMatch == Guid.Empty) return; + + if (!matchPlayers.ContainsKey(currentMatch)) + matchPlayers.Add(currentMatch, new HashSet()); + + matchPlayers[currentMatch].Add(netIdentity); + + // No need to rebuild anything here. + // identity.RebuildObservers is called right after this from NetworkServer.SpawnObject + } + + public override void OnStopServer() + { + if (currentMatch == Guid.Empty) return; + + if (matchPlayers.ContainsKey(currentMatch) && matchPlayers[currentMatch].Remove(netIdentity)) + RebuildMatchObservers(currentMatch); + } + + void RebuildMatchObservers(Guid specificMatch) + { + foreach (NetworkIdentity networkIdentity in matchPlayers[specificMatch]) + networkIdentity?.RebuildObservers(false); + } + + #region Observers + + /// + /// Callback used by the visibility system to determine if an observer (player) can see this object. + /// If this function returns true, the network connection will be added as an observer. + /// + /// Network connection of a player. + /// True if the player can see this object. + public override bool OnCheckObserver(NetworkConnection conn) + { + // Not Visible if not in a match + if (currentMatch == Guid.Empty) + return false; + + NetworkMatchChecker networkMatchChecker = conn.identity.GetComponent(); + + if (networkMatchChecker == null) + return false; + + return networkMatchChecker.currentMatch == currentMatch; + } + + /// + /// Callback used by the visibility system to (re)construct the set of observers that can see this object. + /// Implementations of this callback should add network connections of players that can see this object to the observers set. + /// + /// The new set of observers for this object. + /// True if the set of observers is being built for the first time. + public override void OnRebuildObservers(HashSet observers, bool initialize) + { + if (currentMatch == Guid.Empty) return; + + foreach (NetworkIdentity networkIdentity in matchPlayers[currentMatch]) + if (networkIdentity != null && networkIdentity.connectionToClient != null) + observers.Add(networkIdentity.connectionToClient); + } + + #endregion + + [ServerCallback] + void Update() + { + // only if changed + if (currentMatch == lastMatch) + return; + + // This object is in a new match so observers in the prior match + // and the new match need to rebuild their respective observers lists. + + // Remove this object from the hashset of the match it just left + if (lastMatch != Guid.Empty) + { + matchPlayers[lastMatch].Remove(netIdentity); + + // RebuildObservers of all NetworkIdentity's in the match this + // object just left + RebuildMatchObservers(lastMatch); + } + + if (currentMatch != Guid.Empty) + { + // Make sure this new match is in the dictionary + if (!matchPlayers.ContainsKey(currentMatch)) + matchPlayers.Add(currentMatch, new HashSet()); + + // Add this object to the hashset of the new match + matchPlayers[currentMatch].Add(netIdentity); + + // RebuildObservers of all NetworkIdentity's in the match this object just entered + RebuildMatchObservers(currentMatch); + } + else + { + // Not in any match now...RebuildObservers will clear and add self + netIdentity.RebuildObservers(false); + } + + // save last rebuild's match + lastMatch = currentMatch; + } + } +} diff --git a/Assets/Mirror/Components/NetworkMatchChecker.cs.meta b/Assets/Mirror/Components/NetworkMatchChecker.cs.meta new file mode 100644 index 0000000..adf2a61 --- /dev/null +++ b/Assets/Mirror/Components/NetworkMatchChecker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1020a74962faada4b807ac5dc053a4cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkOwnerChecker.cs b/Assets/Mirror/Components/NetworkOwnerChecker.cs new file mode 100644 index 0000000..b82c6d9 --- /dev/null +++ b/Assets/Mirror/Components/NetworkOwnerChecker.cs @@ -0,0 +1,43 @@ +using System; +using UnityEngine; +using System.Collections.Generic; + +namespace Mirror +{ + /// + /// Component that limits visibility of networked objects to the authority client. + /// Any object with this component on it will only be visible to the client that has been assigned authority for it. + /// This would be used for spawning a non-player networked object for single client to interact with, e.g. in-game puzzles. + /// + // Deprecated 2021-02-17 + [Obsolete(NetworkVisibilityObsoleteMessage.Message)] + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkOwnerChecker")] + [RequireComponent(typeof(NetworkIdentity))] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-owner-checker")] + public class NetworkOwnerChecker : NetworkVisibility + { + /// + /// Callback used by the visibility system to determine if an observer (player) can see this object. + /// If this function returns true, the network connection will be added as an observer. + /// + /// Network connection of a player. + /// True if the client is the owner of this object. + public override bool OnCheckObserver(NetworkConnection conn) + { + // Debug.Log($"OnCheckObserver {netIdentity.connectionToClient} {conn}"); + + return (netIdentity.connectionToClient == conn); + } + + /// + /// Callback used by the visibility system to (re)construct the set of observers that can see this object. + /// + /// The new set of observers for this object. + /// True if the set of observers is being built for the first time. + public override void OnRebuildObservers(HashSet observers, bool initialize) + { + // Do nothing here because the authority client is always added as an observer internally. + } + } +} diff --git a/Assets/Mirror/Components/NetworkOwnerChecker.cs.meta b/Assets/Mirror/Components/NetworkOwnerChecker.cs.meta new file mode 100644 index 0000000..060154e --- /dev/null +++ b/Assets/Mirror/Components/NetworkOwnerChecker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 25fd0c51bbe07c140bc30978b91e9182 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkPingDisplay.cs b/Assets/Mirror/Components/NetworkPingDisplay.cs new file mode 100644 index 0000000..ca3527b --- /dev/null +++ b/Assets/Mirror/Components/NetworkPingDisplay.cs @@ -0,0 +1,33 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// Component that will display the clients ping in milliseconds + /// + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkPingDisplay")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-ping-display")] + public class NetworkPingDisplay : MonoBehaviour + { + public Color color = Color.white; + public int padding = 2; + int width = 150; + int height = 25; + + void OnGUI() + { + // only while client is active + if (!NetworkClient.active) return; + + // show rtt in bottom right corner, right aligned + GUI.color = color; + Rect rect = new Rect(Screen.width - width - padding, Screen.height - height - padding, width, height); + GUIStyle style = GUI.skin.GetStyle("Label"); + style.alignment = TextAnchor.MiddleRight; + GUI.Label(rect, $"RTT: {Math.Round(NetworkTime.rtt * 1000)}ms", style); + GUI.color = Color.white; + } + } +} diff --git a/Assets/Mirror/Components/NetworkPingDisplay.cs.meta b/Assets/Mirror/Components/NetworkPingDisplay.cs.meta new file mode 100644 index 0000000..826d5d3 --- /dev/null +++ b/Assets/Mirror/Components/NetworkPingDisplay.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc654f29862fc2643b948f772ebb9e68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkProximityChecker.cs b/Assets/Mirror/Components/NetworkProximityChecker.cs new file mode 100644 index 0000000..9a4411d --- /dev/null +++ b/Assets/Mirror/Components/NetworkProximityChecker.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + /// + /// Component that controls visibility of networked objects for players. + /// Any object with this component on it will not be visible to players more than a (configurable) distance away. + /// + // Deprecated 2021-02-17 + [Obsolete(NetworkVisibilityObsoleteMessage.Message)] + [AddComponentMenu("Network/NetworkProximityChecker")] + [RequireComponent(typeof(NetworkIdentity))] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-proximity-checker")] + public class NetworkProximityChecker : NetworkVisibility + { + /// + /// The maximum range that objects will be visible at. + /// + [Tooltip("The maximum range that objects will be visible at.")] + public int visRange = 10; + + /// + /// How often (in seconds) that this object should update the list of observers that can see it. + /// + [Tooltip("How often (in seconds) that this object should update the list of observers that can see it.")] + public float visUpdateInterval = 1; + + /// + /// Flag to force this object to be hidden for players. + /// If this object is a player object, it will not be hidden for that player. + /// + // Deprecated 2021-02-17 + [Obsolete("Use NetworkIdentity.visible mode instead of forceHidden!")] + public bool forceHidden + { + get => netIdentity.visible == Visibility.ForceHidden; + set => netIdentity.visible = value ? Visibility.ForceHidden : Visibility.Default; + } + + public override void OnStartServer() + { + InvokeRepeating(nameof(RebuildObservers), 0, visUpdateInterval); + } + public override void OnStopServer() + { + CancelInvoke(nameof(RebuildObservers)); + } + + void RebuildObservers() + { + netIdentity.RebuildObservers(false); + } + + /// + /// Callback used by the visibility system to determine if an observer (player) can see this object. + /// If this function returns true, the network connection will be added as an observer. + /// + /// Network connection of a player. + /// True if the player can see this object. + public override bool OnCheckObserver(NetworkConnection conn) + { + if (forceHidden) + return false; + + return Vector3.Distance(conn.identity.transform.position, transform.position) < visRange; + } + + /// + /// Callback used by the visibility system to (re)construct the set of observers that can see this object. + /// Implementations of this callback should add network connections of players that can see this object to the observers set. + /// + /// The new set of observers for this object. + /// True if the set of observers is being built for the first time. + public override void OnRebuildObservers(HashSet observers, bool initialize) + { + // if force hidden then return without adding any observers. + if (forceHidden) + return; + + // 'transform.' calls GetComponent, only do it once + Vector3 position = transform.position; + + // brute force distance check + // -> only player connections can be observers, so it's enough if we + // go through all connections instead of all spawned identities. + // -> compared to UNET's sphere cast checking, this one is orders of + // magnitude faster. if we have 10k monsters and run a sphere + // cast 10k times, we will see a noticeable lag even with physics + // layers. but checking to every connection is fast. + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + if (conn != null && conn.identity != null) + { + // check distance + if (Vector3.Distance(conn.identity.transform.position, position) < visRange) + { + observers.Add(conn); + } + } + } + } + } +} diff --git a/Assets/Mirror/Components/NetworkProximityChecker.cs.meta b/Assets/Mirror/Components/NetworkProximityChecker.cs.meta new file mode 100644 index 0000000..0131b73 --- /dev/null +++ b/Assets/Mirror/Components/NetworkProximityChecker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1731d8de2d0c84333b08ebe1e79f4118 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkRoomManager.cs b/Assets/Mirror/Components/NetworkRoomManager.cs new file mode 100644 index 0000000..c730e8f --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomManager.cs @@ -0,0 +1,699 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Serialization; + +namespace Mirror +{ + /// + /// This is a specialized NetworkManager that includes a networked room. + /// + /// + /// The room has slots that track the joined players, and a maximum player count that is enforced. It requires that the NetworkRoomPlayer component be on the room player objects. + /// NetworkRoomManager is derived from NetworkManager, and so it implements many of the virtual functions provided by the NetworkManager class. To avoid accidentally replacing functionality of the NetworkRoomManager, there are new virtual functions on the NetworkRoomManager that begin with "OnRoom". These should be used on classes derived from NetworkRoomManager instead of the virtual functions on NetworkManager. + /// The OnRoom*() functions have empty implementations on the NetworkRoomManager base class, so the base class functions do not have to be called. + /// + [AddComponentMenu("Network/NetworkRoomManager")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-manager")] + public class NetworkRoomManager : NetworkManager + { + public struct PendingPlayer + { + public NetworkConnection conn; + public GameObject roomPlayer; + } + + [Header("Room Settings")] + + [FormerlySerializedAs("m_ShowRoomGUI")] + [SerializeField] + [Tooltip("This flag controls whether the default UI is shown for the room")] + public bool showRoomGUI = true; + + [FormerlySerializedAs("m_MinPlayers")] + [SerializeField] + [Tooltip("Minimum number of players to auto-start the game")] + public int minPlayers = 1; + + [FormerlySerializedAs("m_RoomPlayerPrefab")] + [SerializeField] + [Tooltip("Prefab to use for the Room Player")] + public NetworkRoomPlayer roomPlayerPrefab; + + /// + /// The scene to use for the room. This is similar to the offlineScene of the NetworkManager. + /// + [Scene] + public string RoomScene; + + /// + /// The scene to use for the playing the game from the room. This is similar to the onlineScene of the NetworkManager. + /// + [Scene] + public string GameplayScene; + + /// + /// List of players that are in the Room + /// + [FormerlySerializedAs("m_PendingPlayers")] + public List pendingPlayers = new List(); + + [Header("Diagnostics")] + + /// + /// True when all players have submitted a Ready message + /// + [Tooltip("Diagnostic flag indicating all players are ready to play")] + [FormerlySerializedAs("allPlayersReady")] + [SerializeField] bool _allPlayersReady; + + /// + /// These slots track players that enter the room. + /// The slotId on players is global to the game - across all players. + /// + [Tooltip("List of Room Player objects")] + public List roomSlots = new List(); + + public bool allPlayersReady + { + get => _allPlayersReady; + set + { + bool wasReady = _allPlayersReady; + bool nowReady = value; + + if (wasReady != nowReady) + { + _allPlayersReady = value; + + if (nowReady) + { + OnRoomServerPlayersReady(); + } + else + { + OnRoomServerPlayersNotReady(); + } + } + } + } + + public override void OnValidate() + { + // always >= 0 + maxConnections = Mathf.Max(maxConnections, 0); + + // always <= maxConnections + minPlayers = Mathf.Min(minPlayers, maxConnections); + + // always >= 0 + minPlayers = Mathf.Max(minPlayers, 0); + + if (roomPlayerPrefab != null) + { + NetworkIdentity identity = roomPlayerPrefab.GetComponent(); + if (identity == null) + { + roomPlayerPrefab = null; + Debug.LogError("RoomPlayer prefab must have a NetworkIdentity component."); + } + } + + base.OnValidate(); + } + + public void ReadyStatusChanged() + { + int CurrentPlayers = 0; + int ReadyPlayers = 0; + + foreach (NetworkRoomPlayer item in roomSlots) + { + if (item != null) + { + CurrentPlayers++; + if (item.readyToBegin) + ReadyPlayers++; + } + } + + if (CurrentPlayers == ReadyPlayers) + CheckReadyToBegin(); + else + allPlayersReady = false; + } + + /// + /// Called on the server when a client is ready. + /// The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process. + /// + /// Connection from client. + public override void OnServerReady(NetworkConnection conn) + { + Debug.Log("NetworkRoomManager OnServerReady"); + base.OnServerReady(conn); + + if (conn != null && conn.identity != null) + { + GameObject roomPlayer = conn.identity.gameObject; + + // if null or not a room player, don't replace it + if (roomPlayer != null && roomPlayer.GetComponent() != null) + SceneLoadedForPlayer(conn, roomPlayer); + } + } + + void SceneLoadedForPlayer(NetworkConnection conn, GameObject roomPlayer) + { + // Debug.LogFormat(LogType.Log, "NetworkRoom SceneLoadedForPlayer scene: {0} {1}", SceneManager.GetActiveScene().path, conn); + + if (IsSceneActive(RoomScene)) + { + // cant be ready in room, add to ready list + PendingPlayer pending; + pending.conn = conn; + pending.roomPlayer = roomPlayer; + pendingPlayers.Add(pending); + return; + } + + GameObject gamePlayer = OnRoomServerCreateGamePlayer(conn, roomPlayer); + if (gamePlayer == null) + { + // get start position from base class + Transform startPos = GetStartPosition(); + gamePlayer = startPos != null + ? Instantiate(playerPrefab, startPos.position, startPos.rotation) + : Instantiate(playerPrefab, Vector3.zero, Quaternion.identity); + } + + if (!OnRoomServerSceneLoadedForPlayer(conn, roomPlayer, gamePlayer)) + return; + + // replace room player with game player + NetworkServer.ReplacePlayerForConnection(conn, gamePlayer, true); + } + + /// + /// CheckReadyToBegin checks all of the players in the room to see if their readyToBegin flag is set. + /// If all of the players are ready, then the server switches from the RoomScene to the PlayScene, essentially starting the game. This is called automatically in response to NetworkRoomPlayer.CmdChangeReadyState. + /// + public void CheckReadyToBegin() + { + if (!IsSceneActive(RoomScene)) + return; + + int numberOfReadyPlayers = NetworkServer.connections.Count(conn => conn.Value != null && conn.Value.identity.gameObject.GetComponent().readyToBegin); + bool enoughReadyPlayers = minPlayers <= 0 || numberOfReadyPlayers >= minPlayers; + if (enoughReadyPlayers) + { + pendingPlayers.Clear(); + allPlayersReady = true; + } + else + { + allPlayersReady = false; + } + } + + internal void CallOnClientEnterRoom() + { + OnRoomClientEnter(); + foreach (NetworkRoomPlayer player in roomSlots) + if (player != null) + { + player.OnClientEnterRoom(); + } + } + + internal void CallOnClientExitRoom() + { + OnRoomClientExit(); + foreach (NetworkRoomPlayer player in roomSlots) + if (player != null) + { + player.OnClientExitRoom(); + } + } + + #region server handlers + + /// + /// Called on the server when a new client connects. + /// Unity calls this on the Server when a Client connects to the Server. Use an override to tell the NetworkManager what to do when a client connects to the server. + /// + /// Connection from client. + public override void OnServerConnect(NetworkConnection conn) + { + if (numPlayers >= maxConnections) + { + conn.Disconnect(); + return; + } + + // cannot join game in progress + if (!IsSceneActive(RoomScene)) + { + conn.Disconnect(); + return; + } + + base.OnServerConnect(conn); + OnRoomServerConnect(conn); + } + + /// + /// Called on the server when a client disconnects. + /// This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected. + /// + /// Connection from client. + public override void OnServerDisconnect(NetworkConnection conn) + { + if (conn.identity != null) + { + NetworkRoomPlayer roomPlayer = conn.identity.GetComponent(); + + if (roomPlayer != null) + roomSlots.Remove(roomPlayer); + + foreach (NetworkIdentity clientOwnedObject in conn.clientOwnedObjects) + { + roomPlayer = clientOwnedObject.GetComponent(); + if (roomPlayer != null) + roomSlots.Remove(roomPlayer); + } + } + + allPlayersReady = false; + + foreach (NetworkRoomPlayer player in roomSlots) + { + if (player != null) + player.GetComponent().readyToBegin = false; + } + + if (IsSceneActive(RoomScene)) + RecalculateRoomPlayerIndices(); + + OnRoomServerDisconnect(conn); + base.OnServerDisconnect(conn); + +#if UNITY_SERVER + if (numPlayers < 1) + StopServer(); +#endif + } + + // Sequential index used in round-robin deployment of players into instances and score positioning + public int clientIndex; + + /// + /// Called on the server when a client adds a new player with NetworkClient.AddPlayer. + /// The default implementation for this function creates a new player object from the playerPrefab. + /// + /// Connection from client. + public override void OnServerAddPlayer(NetworkConnection conn) + { + // increment the index before adding the player, so first player starts at 1 + clientIndex++; + + if (IsSceneActive(RoomScene)) + { + if (roomSlots.Count == maxConnections) + return; + + allPlayersReady = false; + + // Debug.LogFormat(LogType.Log, "NetworkRoomManager.OnServerAddPlayer playerPrefab:{0}", roomPlayerPrefab.name); + + GameObject newRoomGameObject = OnRoomServerCreateRoomPlayer(conn); + if (newRoomGameObject == null) + newRoomGameObject = Instantiate(roomPlayerPrefab.gameObject, Vector3.zero, Quaternion.identity); + + NetworkServer.AddPlayerForConnection(conn, newRoomGameObject); + } + else + OnRoomServerAddPlayer(conn); + } + + [Server] + public void RecalculateRoomPlayerIndices() + { + if (roomSlots.Count > 0) + { + for (int i = 0; i < roomSlots.Count; i++) + { + roomSlots[i].index = i; + } + } + } + + /// + /// This causes the server to switch scenes and sets the networkSceneName. + /// Clients that connect to this server will automatically switch to this scene. This is called automatically if onlineScene or offlineScene are set, but it can be called from user code to switch scenes again while the game is in progress. This automatically sets clients to be not-ready. The clients must call NetworkClient.Ready() again to participate in the new scene. + /// + /// + public override void ServerChangeScene(string newSceneName) + { + if (newSceneName == RoomScene) + { + foreach (NetworkRoomPlayer roomPlayer in roomSlots) + { + if (roomPlayer == null) + continue; + + // find the game-player object for this connection, and destroy it + NetworkIdentity identity = roomPlayer.GetComponent(); + + if (NetworkServer.active) + { + // re-add the room object + roomPlayer.GetComponent().readyToBegin = false; + NetworkServer.ReplacePlayerForConnection(identity.connectionToClient, roomPlayer.gameObject); + } + } + + allPlayersReady = false; + } + + base.ServerChangeScene(newSceneName); + } + + /// + /// Called on the server when a scene is completed loaded, when the scene load was initiated by the server with ServerChangeScene(). + /// + /// The name of the new scene. + public override void OnServerSceneChanged(string sceneName) + { + if (sceneName != RoomScene) + { + // call SceneLoadedForPlayer on any players that become ready while we were loading the scene. + foreach (PendingPlayer pending in pendingPlayers) + SceneLoadedForPlayer(pending.conn, pending.roomPlayer); + + pendingPlayers.Clear(); + } + + OnRoomServerSceneChanged(sceneName); + } + + /// + /// This is invoked when a server is started - including when a host is started. + /// StartServer has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartServer() + { + if (string.IsNullOrEmpty(RoomScene)) + { + Debug.LogError("NetworkRoomManager RoomScene is empty. Set the RoomScene in the inspector for the NetworkRoomManager"); + return; + } + + if (string.IsNullOrEmpty(GameplayScene)) + { + Debug.LogError("NetworkRoomManager PlayScene is empty. Set the PlayScene in the inspector for the NetworkRoomManager"); + return; + } + + OnRoomStartServer(); + } + + /// + /// This is invoked when a host is started. + /// StartHost has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartHost() + { + OnRoomStartHost(); + } + + /// + /// This is called when a server is stopped - including when a host is stopped. + /// + public override void OnStopServer() + { + roomSlots.Clear(); + OnRoomStopServer(); + } + + /// + /// This is called when a host is stopped. + /// + public override void OnStopHost() + { + OnRoomStopHost(); + } + +#endregion + +#region client handlers + + /// + /// This is invoked when the client is started. + /// + public override void OnStartClient() + { + if (roomPlayerPrefab == null || roomPlayerPrefab.gameObject == null) + Debug.LogError("NetworkRoomManager no RoomPlayer prefab is registered. Please add a RoomPlayer prefab."); + else + NetworkClient.RegisterPrefab(roomPlayerPrefab.gameObject); + + if (playerPrefab == null) + Debug.LogError("NetworkRoomManager no GamePlayer prefab is registered. Please add a GamePlayer prefab."); + + OnRoomStartClient(); + } + + /// + /// Called on the client when connected to a server. + /// The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects. + /// + /// Connection to the server. + public override void OnClientConnect(NetworkConnection conn) + { + OnRoomClientConnect(conn); + base.OnClientConnect(conn); + } + + /// + /// Called on clients when disconnected from a server. + /// This is called on the client when it disconnects from the server. Override this function to decide what happens when the client disconnects. + /// + /// Connection to the server. + public override void OnClientDisconnect(NetworkConnection conn) + { + OnRoomClientDisconnect(conn); + base.OnClientDisconnect(conn); + } + + /// + /// This is called when a client is stopped. + /// + public override void OnStopClient() + { + OnRoomStopClient(); + CallOnClientExitRoom(); + roomSlots.Clear(); + } + + /// + /// Called on clients when a scene has completed loaded, when the scene load was initiated by the server. + /// Scene changes can cause player objects to be destroyed. The default implementation of OnClientSceneChanged in the NetworkManager is to add a player object for the connection if no player object exists. + /// + /// Connection of the client + public override void OnClientSceneChanged(NetworkConnection conn) + { + if (IsSceneActive(RoomScene)) + { + if (NetworkClient.isConnected) + CallOnClientEnterRoom(); + } + else + CallOnClientExitRoom(); + + base.OnClientSceneChanged(conn); + OnRoomClientSceneChanged(conn); + } + +#endregion + +#region room server virtuals + + /// + /// This is called on the host when a host is started. + /// + public virtual void OnRoomStartHost() {} + + /// + /// This is called on the host when the host is stopped. + /// + public virtual void OnRoomStopHost() {} + + /// + /// This is called on the server when the server is started - including when a host is started. + /// + public virtual void OnRoomStartServer() {} + + /// + /// This is called on the server when the server is started - including when a host is stopped. + /// + public virtual void OnRoomStopServer() {} + + /// + /// This is called on the server when a new client connects to the server. + /// + /// The new connection. + public virtual void OnRoomServerConnect(NetworkConnection conn) {} + + /// + /// This is called on the server when a client disconnects. + /// + /// The connection that disconnected. + public virtual void OnRoomServerDisconnect(NetworkConnection conn) {} + + /// + /// This is called on the server when a networked scene finishes loading. + /// + /// Name of the new scene. + public virtual void OnRoomServerSceneChanged(string sceneName) {} + + /// + /// This allows customization of the creation of the room-player object on the server. + /// By default the roomPlayerPrefab is used to create the room-player, but this function allows that behaviour to be customized. + /// + /// The connection the player object is for. + /// The new room-player object. + public virtual GameObject OnRoomServerCreateRoomPlayer(NetworkConnection conn) + { + return null; + } + + /// + /// This allows customization of the creation of the GamePlayer object on the server. + /// By default the gamePlayerPrefab is used to create the game-player, but this function allows that behaviour to be customized. The object returned from the function will be used to replace the room-player on the connection. + /// + /// The connection the player object is for. + /// The room player object for this connection. + /// A new GamePlayer object. + public virtual GameObject OnRoomServerCreateGamePlayer(NetworkConnection conn, GameObject roomPlayer) + { + return null; + } + + /// + /// This allows customization of the creation of the GamePlayer object on the server. + /// This is only called for subsequent GamePlay scenes after the first one. + /// See OnRoomServerCreateGamePlayer(NetworkConnection, GameObject) to customize the player object for the initial GamePlay scene. + /// + /// The connection the player object is for. + public virtual void OnRoomServerAddPlayer(NetworkConnection conn) + { + base.OnServerAddPlayer(conn); + } + + // for users to apply settings from their room player object to their in-game player object + /// + /// This is called on the server when it is told that a client has finished switching from the room scene to a game player scene. + /// When switching from the room, the room-player is replaced with a game-player object. This callback function gives an opportunity to apply state from the room-player to the game-player object. + /// + /// The connection of the player + /// The room player object. + /// The game player object. + /// False to not allow this player to replace the room player. + public virtual bool OnRoomServerSceneLoadedForPlayer(NetworkConnection conn, GameObject roomPlayer, GameObject gamePlayer) + { + return true; + } + + /// + /// This is called on the server when all the players in the room are ready. + /// The default implementation of this function uses ServerChangeScene() to switch to the game player scene. By implementing this callback you can customize what happens when all the players in the room are ready, such as adding a countdown or a confirmation for a group leader. + /// + public virtual void OnRoomServerPlayersReady() + { + // all players are readyToBegin, start the game + ServerChangeScene(GameplayScene); + } + + /// + /// This is called on the server when CheckReadyToBegin finds that players are not ready + /// May be called multiple times while not ready players are joining + /// + public virtual void OnRoomServerPlayersNotReady() {} + +#endregion + +#region room client virtuals + + /// + /// This is a hook to allow custom behaviour when the game client enters the room. + /// + public virtual void OnRoomClientEnter() {} + + /// + /// This is a hook to allow custom behaviour when the game client exits the room. + /// + public virtual void OnRoomClientExit() {} + + /// + /// This is called on the client when it connects to server. + /// + /// The connection that connected. + public virtual void OnRoomClientConnect(NetworkConnection conn) {} + + /// + /// This is called on the client when disconnected from a server. + /// + /// The connection that disconnected. + public virtual void OnRoomClientDisconnect(NetworkConnection conn) {} + + /// + /// This is called on the client when a client is started. + /// + /// The connection for the room. + public virtual void OnRoomStartClient() {} + + /// + /// This is called on the client when the client stops. + /// + public virtual void OnRoomStopClient() {} + + /// + /// This is called on the client when the client is finished loading a new networked scene. + /// + /// The connection that finished loading a new networked scene. + public virtual void OnRoomClientSceneChanged(NetworkConnection conn) {} + + /// + /// Called on the client when adding a player to the room fails. + /// This could be because the room is full, or the connection is not allowed to have more players. + /// + public virtual void OnRoomClientAddPlayerFailed() {} + +#endregion + +#region optional UI + + /// + /// virtual so inheriting classes can roll their own + /// + public virtual void OnGUI() + { + if (!showRoomGUI) + return; + + if (NetworkServer.active && IsSceneActive(GameplayScene)) + { + GUILayout.BeginArea(new Rect(Screen.width - 150f, 10f, 140f, 30f)); + if (GUILayout.Button("Return to Room")) + ServerChangeScene(RoomScene); + GUILayout.EndArea(); + } + + if (IsSceneActive(RoomScene)) + GUI.Box(new Rect(10f, 180f, 520f, 150f), "PLAYERS"); + } + +#endregion + } +} diff --git a/Assets/Mirror/Components/NetworkRoomManager.cs.meta b/Assets/Mirror/Components/NetworkRoomManager.cs.meta new file mode 100644 index 0000000..2c64616 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 615e6c6589cf9e54cad646b5a11e0529 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkRoomPlayer.cs b/Assets/Mirror/Components/NetworkRoomPlayer.cs new file mode 100644 index 0000000..90e6429 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomPlayer.cs @@ -0,0 +1,195 @@ +using UnityEngine; + +namespace Mirror +{ + /// + /// This component works in conjunction with the NetworkRoomManager to make up the multiplayer room system. + /// The RoomPrefab object of the NetworkRoomManager must have this component on it. This component holds basic room player data required for the room to function. Game specific data for room players can be put in other components on the RoomPrefab or in scripts derived from NetworkRoomPlayer. + /// + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkRoomPlayer")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-player")] + public class NetworkRoomPlayer : NetworkBehaviour + { + /// + /// This flag controls whether the default UI is shown for the room player. + /// As this UI is rendered using the old GUI system, it is only recommended for testing purposes. + /// + [Tooltip("This flag controls whether the default UI is shown for the room player")] + public bool showRoomGUI = true; + + [Header("Diagnostics")] + + /// + /// Diagnostic flag indicating whether this player is ready for the game to begin. + /// Invoke CmdChangeReadyState method on the client to set this flag. + /// When all players are ready to begin, the game will start. This should not be set directly, CmdChangeReadyState should be called on the client to set it on the server. + /// + [Tooltip("Diagnostic flag indicating whether this player is ready for the game to begin")] + [SyncVar(hook = nameof(ReadyStateChanged))] + public bool readyToBegin; + + /// + /// Diagnostic index of the player, e.g. Player1, Player2, etc. + /// + [Tooltip("Diagnostic index of the player, e.g. Player1, Player2, etc.")] + [SyncVar(hook = nameof(IndexChanged))] + public int index; + + #region Unity Callbacks + + /// + /// Do not use Start - Override OnStartHost / OnStartClient instead! + /// + public void Start() + { + if (NetworkManager.singleton is NetworkRoomManager room) + { + // NetworkRoomPlayer object must be set to DontDestroyOnLoad along with NetworkRoomManager + // in server and all clients, otherwise it will be respawned in the game scene which would + // have undesirable effects. + if (room.dontDestroyOnLoad) + DontDestroyOnLoad(gameObject); + + room.roomSlots.Add(this); + + if (NetworkServer.active) + room.RecalculateRoomPlayerIndices(); + + if (NetworkClient.active) + room.CallOnClientEnterRoom(); + } + else Debug.LogError("RoomPlayer could not find a NetworkRoomManager. The RoomPlayer requires a NetworkRoomManager object to function. Make sure that there is one in the scene."); + } + + public virtual void OnDisable() + { + if (NetworkClient.active && NetworkManager.singleton is NetworkRoomManager room) + { + // only need to call this on client as server removes it before object is destroyed + room.roomSlots.Remove(this); + + room.CallOnClientExitRoom(); + } + } + + #endregion + + #region Commands + + [Command] + public void CmdChangeReadyState(bool readyState) + { + readyToBegin = readyState; + NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager; + if (room != null) + { + room.ReadyStatusChanged(); + } + } + + #endregion + + #region SyncVar Hooks + + /// + /// This is a hook that is invoked on clients when the index changes. + /// + /// The old index value + /// The new index value + public virtual void IndexChanged(int oldIndex, int newIndex) {} + + /// + /// This is a hook that is invoked on clients when a RoomPlayer switches between ready or not ready. + /// This function is called when the a client player calls CmdChangeReadyState. + /// + /// New Ready State + public virtual void ReadyStateChanged(bool oldReadyState, bool newReadyState) {} + + #endregion + + #region Room Client Virtuals + + /// + /// This is a hook that is invoked on clients for all room player objects when entering the room. + /// Note: isLocalPlayer is not guaranteed to be set until OnStartLocalPlayer is called. + /// + public virtual void OnClientEnterRoom() {} + + /// + /// This is a hook that is invoked on clients for all room player objects when exiting the room. + /// + public virtual void OnClientExitRoom() {} + + #endregion + + #region Optional UI + + /// + /// Render a UI for the room. Override to provide your own UI + /// + public virtual void OnGUI() + { + if (!showRoomGUI) + return; + + NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager; + if (room) + { + if (!room.showRoomGUI) + return; + + if (!NetworkManager.IsSceneActive(room.RoomScene)) + return; + + DrawPlayerReadyState(); + DrawPlayerReadyButton(); + } + } + + void DrawPlayerReadyState() + { + GUILayout.BeginArea(new Rect(20f + (index * 100), 200f, 90f, 130f)); + + GUILayout.Label($"Player [{index + 1}]"); + + if (readyToBegin) + GUILayout.Label("Ready"); + else + GUILayout.Label("Not Ready"); + + if (((isServer && index > 0) || isServerOnly) && GUILayout.Button("REMOVE")) + { + // This button only shows on the Host for all players other than the Host + // Host and Players can't remove themselves (stop the client instead) + // Host can kick a Player this way. + GetComponent().connectionToClient.Disconnect(); + } + + GUILayout.EndArea(); + } + + void DrawPlayerReadyButton() + { + if (NetworkClient.active && isLocalPlayer) + { + GUILayout.BeginArea(new Rect(20f, 300f, 120f, 20f)); + + if (readyToBegin) + { + if (GUILayout.Button("Cancel")) + CmdChangeReadyState(false); + } + else + { + if (GUILayout.Button("Ready")) + CmdChangeReadyState(true); + } + + GUILayout.EndArea(); + } + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta b/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta new file mode 100644 index 0000000..d355d8d --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79874ac94d5b1314788ecf0e86bd23fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkSceneChecker.cs b/Assets/Mirror/Components/NetworkSceneChecker.cs new file mode 100644 index 0000000..343e46a --- /dev/null +++ b/Assets/Mirror/Components/NetworkSceneChecker.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror +{ + /// + /// Component that controls visibility of networked objects between scenes. + /// Any object with this component on it will only be visible to other objects in the same scene + /// This would be used when the server has multiple additive subscenes loaded to isolate players to their respective subscenes + /// + // Deprecated 2021-02-17 + [Obsolete(NetworkVisibilityObsoleteMessage.Message)] + [DisallowMultipleComponent] + [AddComponentMenu("Network/NetworkSceneChecker")] + [RequireComponent(typeof(NetworkIdentity))] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-scene-checker")] + public class NetworkSceneChecker : NetworkVisibility + { + /// + /// Flag to force this object to be hidden from all observers. + /// If this object is a player object, it will not be hidden for that client. + /// + [Tooltip("Enable to force this object to be hidden from all observers.")] + public bool forceHidden; + + // Use Scene instead of string scene.name because when additively loading multiples of a subscene the name won't be unique + static readonly Dictionary> sceneCheckerObjects = new Dictionary>(); + + Scene currentScene; + + [ServerCallback] + void Awake() + { + currentScene = gameObject.scene; + // Debug.Log($"NetworkSceneChecker.Awake currentScene: {currentScene}"); + } + + public override void OnStartServer() + { + if (!sceneCheckerObjects.ContainsKey(currentScene)) + sceneCheckerObjects.Add(currentScene, new HashSet()); + + sceneCheckerObjects[currentScene].Add(netIdentity); + } + + public override void OnStopServer() + { + if (sceneCheckerObjects.ContainsKey(currentScene) && sceneCheckerObjects[currentScene].Remove(netIdentity)) + RebuildSceneObservers(); + } + + [ServerCallback] + void Update() + { + if (currentScene == gameObject.scene) + return; + + // This object is in a new scene so observers in the prior scene + // and the new scene need to rebuild their respective observers lists. + + // Remove this object from the hashset of the scene it just left + sceneCheckerObjects[currentScene].Remove(netIdentity); + + // RebuildObservers of all NetworkIdentity's in the scene this object just left + RebuildSceneObservers(); + + // Set this to the new scene this object just entered + currentScene = gameObject.scene; + + // Make sure this new scene is in the dictionary + if (!sceneCheckerObjects.ContainsKey(currentScene)) + sceneCheckerObjects.Add(currentScene, new HashSet()); + + // Add this object to the hashset of the new scene + sceneCheckerObjects[currentScene].Add(netIdentity); + + // RebuildObservers of all NetworkIdentity's in the scene this object just entered + RebuildSceneObservers(); + } + + void RebuildSceneObservers() + { + foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene]) + if (networkIdentity != null) + networkIdentity.RebuildObservers(false); + } + + /// + /// Callback used by the visibility system to determine if an observer (player) can see this object. + /// If this function returns true, the network connection will be added as an observer. + /// + /// Network connection of a player. + /// True if the player can see this object. + public override bool OnCheckObserver(NetworkConnection conn) + { + if (forceHidden) + return false; + + return conn.identity.gameObject.scene == gameObject.scene; + } + + /// + /// Callback used by the visibility system to (re)construct the set of observers that can see this object. + /// Implementations of this callback should add network connections of players that can see this object to the observers set. + /// + /// The new set of observers for this object. + /// True if the set of observers is being built for the first time. + public override void OnRebuildObservers(HashSet observers, bool initialize) + { + // If forceHidden then return without adding any observers. + if (forceHidden) + return; + + // Add everything in the hashset for this object's current scene + foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene]) + if (networkIdentity != null && networkIdentity.connectionToClient != null) + observers.Add(networkIdentity.connectionToClient); + } + } +} diff --git a/Assets/Mirror/Components/NetworkSceneChecker.cs.meta b/Assets/Mirror/Components/NetworkSceneChecker.cs.meta new file mode 100644 index 0000000..f81ad4f --- /dev/null +++ b/Assets/Mirror/Components/NetworkSceneChecker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7fdb599e1359924bad6255660370252 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkTransform2k.meta b/Assets/Mirror/Components/NetworkTransform2k.meta new file mode 100644 index 0000000..ea3ea29 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 44e823b93c7d2477c8796766dc364c59 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransform.cs b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransform.cs new file mode 100644 index 0000000..037e34a --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransform.cs @@ -0,0 +1,16 @@ +// ʻOumuamua's light curve, assuming little systematic error, presents its +// motion as tumbling, rather than smoothly rotating, and moving sufficiently +// fast relative to the Sun. +// +// A small number of astronomers suggested that ʻOumuamua could be a product of +// alien technology, but evidence in support of this hypothesis is weak. +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + public class NetworkTransform : NetworkTransformBase + { + protected override Transform targetComponent => transform; + } +} diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransform.cs.meta b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransform.cs.meta new file mode 100644 index 0000000..4ad6860 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f74aedd71d9a4f55b3ce499326d45fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformBase.cs b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformBase.cs new file mode 100644 index 0000000..d77ecda --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformBase.cs @@ -0,0 +1,566 @@ +// NetworkTransform V2 aka project Oumuamua by vis2k (2021-07) +// Snapshot Interpolation: https://gafferongames.com/post/snapshot_interpolation/ +// +// Base class for NetworkTransform and NetworkTransformChild. +// => simple unreliable sync without any interpolation for now. +// => which means we don't need teleport detection either +// +// NOTE: several functions are virtual in case someone needs to modify a part. +// +// Channel: uses UNRELIABLE at all times. +// -> out of order packets are dropped automatically +// -> it's better than RELIABLE for several reasons: +// * head of line blocking would add delay +// * resending is mostly pointless +// * bigger data race: +// -> if we use a Cmd() at position X over reliable +// -> client gets Cmd() and X at the same time, but buffers X for bufferTime +// -> for unreliable, it would get X before the reliable Cmd(), still +// buffer for bufferTime but end up closer to the original time +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public abstract class NetworkTransformBase : NetworkBehaviour + { + // TODO SyncDirection { CLIENT_TO_SERVER, SERVER_TO_CLIENT } is easier? + [Header("Authority")] + [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] + public bool clientAuthority; + + // Is this a client with authority over this transform? + // This component could be on the player object or any object that has been assigned authority to this client. + bool IsClientWithAuthority => hasAuthority && clientAuthority; + + // target transform to sync. can be on a child. + protected abstract Transform targetComponent { get; } + + [Header("Synchronization")] + [Range(0, 1)] public float sendInterval = 0.050f; + public bool syncPosition = true; + public bool syncRotation = true; + // scale sync is rare. off by default. + public bool syncScale = false; + + double lastClientSendTime; + double lastServerSendTime; + + // not all games need to interpolate. a board game might jump to the + // final position immediately. + [Header("Interpolation")] + public bool interpolatePosition = true; + public bool interpolateRotation = true; + public bool interpolateScale = true; + + // "Experimentally I’ve found that the amount of delay that works best + // at 2-5% packet loss is 3X the packet send rate" + // NOTE: we do NOT use a dyanmically changing buffer size. + // it would come with a lot of complications, e.g. buffer time + // advantages/disadvantages for different connections. + // Glenn Fiedler's recommendation seems solid, and should cover + // the vast majority of connections. + // (a player with 2000ms latency will have issues no matter what) + [Header("Buffering")] + [Tooltip("Snapshots are buffered for sendInterval * multiplier seconds. At 2-5% packet loss, 3x supposedly works best.")] + public int bufferTimeMultiplier = 3; + public float bufferTime => sendInterval * bufferTimeMultiplier; + [Tooltip("Buffer size limit to avoid ever growing list memory consumption attacks.")] + public int bufferSizeLimit = 64; + + [Tooltip("Start to accelerate interpolation if buffer size is >= threshold. Needs to be larger than bufferTimeMultiplier.")] + public int catchupThreshold = 6; + + [Tooltip("Once buffer is larger catchupThreshold, accelerate by multiplier % per excess entry.")] + [Range(0, 1)] public float catchupMultiplier = 0.10f; + + // snapshots sorted by timestamp + // in the original article, glenn fiedler drops any snapshots older than + // the last received snapshot. + // -> instead, we insert into a sorted buffer + // -> the higher the buffer information density, the better + // -> we still drop anything older than the first element in the buffer + // => internal for testing + // + // IMPORTANT: of explicit 'NTSnapshot' type instead of 'Snapshot' + // interface because List allocates through boxing + internal SortedList serverBuffer = new SortedList(); + internal SortedList clientBuffer = new SortedList(); + + // absolute interpolation time, moved along with deltaTime + // (roughly between [0, delta] where delta is snapshot B - A timestamp) + // (can be bigger than delta when overshooting) + double serverInterpolationTime; + double clientInterpolationTime; + + // only convert the static Interpolation function to Func once to + // avoid allocations + Func Interpolate = NTSnapshot.Interpolate; + + [Header("Debug")] + public bool showGizmos; + public bool showOverlay; + public Color overlayColor = new Color(0, 0, 0, 0.5f); + + // snapshot functions ////////////////////////////////////////////////// + // construct a snapshot of the current state + // => internal for testing + protected virtual NTSnapshot ConstructSnapshot() + { + // NetworkTime.localTime for double precision until Unity has it too + return new NTSnapshot( + // our local time is what the other end uses as remote time + NetworkTime.localTime, + // the other end fills out local time itself + 0, + targetComponent.localPosition, + targetComponent.localRotation, + targetComponent.localScale + ); + } + + // apply a snapshot to the Transform. + // -> start, end, interpolated are all passed in caes they are needed + // -> a regular game would apply the 'interpolated' snapshot + // -> a board game might want to jump to 'goal' directly + // (it's easier to always interpolate and then apply selectively, + // instead of manually interpolating x, y, z, ... depending on flags) + // => internal for testing + // + // NOTE: stuck detection is unnecessary here. + // we always set transform.position anyway, we can't get stuck. + protected virtual void ApplySnapshot(NTSnapshot start, NTSnapshot goal, NTSnapshot interpolated) + { + // local position/rotation for VR support + // + // if syncPosition/Rotation/Scale is disabled then we received nulls + // -> current position/rotation/scale would've been added as snapshot + // -> we still interpolated + // -> but simply don't apply it. if the user doesn't want to sync + // scale, then we should not touch scale etc. + if (syncPosition) + targetComponent.localPosition = interpolatePosition ? interpolated.position : goal.position; + + if (syncRotation) + targetComponent.localRotation = interpolateRotation ? interpolated.rotation : goal.rotation; + + if (syncScale) + targetComponent.localScale = interpolateScale ? interpolated.scale : goal.scale; + } + + // cmd ///////////////////////////////////////////////////////////////// + // only unreliable. see comment above of this file. + [Command(channel = Channels.Unreliable)] + void CmdClientToServerSync(Vector3? position, Quaternion? rotation, Vector3? scale) + { + OnClientToServerSync(position, rotation, scale); + //For client authority, immediately pass on the client snapshot to all other + //clients instead of waiting for server to send its snapshots. + if (clientAuthority) + { + RpcServerToClientSync(position, rotation, scale); + } + } + + // local authority client sends sync message to server for broadcasting + protected virtual void OnClientToServerSync(Vector3? position, Quaternion? rotation, Vector3? scale) + { + // only apply if in client authority mode + if (!clientAuthority) return; + + // protect against ever growing buffer size attacks + if (serverBuffer.Count >= bufferSizeLimit) return; + + // only player owned objects (with a connection) can send to + // server. we can get the timestamp from the connection. + double timestamp = connectionToClient.remoteTimeStamp; + + // position, rotation, scale can have no value if same as last time. + // saves bandwidth. + // but we still need to feed it to snapshot interpolation. we can't + // just have gaps in there if nothing has changed. for example, if + // client sends snapshot at t=0 + // client sends nothing for 10s because not moved + // client sends snapshot at t=10 + // then the server would assume that it's one super slow move and + // replay it for 10 seconds. + if (!position.HasValue) position = targetComponent.localPosition; + if (!rotation.HasValue) rotation = targetComponent.localRotation; + if (!scale.HasValue) scale = targetComponent.localScale; + + // construct snapshot with batch timestamp to save bandwidth + NTSnapshot snapshot = new NTSnapshot( + timestamp, + NetworkTime.localTime, + position.Value, rotation.Value, scale.Value + ); + + // add to buffer (or drop if older than first element) + SnapshotInterpolation.InsertIfNewEnough(snapshot, serverBuffer); + } + + // rpc ///////////////////////////////////////////////////////////////// + // only unreliable. see comment above of this file. + [ClientRpc(channel = Channels.Unreliable)] + void RpcServerToClientSync(Vector3? position, Quaternion? rotation, Vector3? scale) => + OnServerToClientSync(position, rotation, scale); + + // server broadcasts sync message to all clients + protected virtual void OnServerToClientSync(Vector3? position, Quaternion? rotation, Vector3? scale) + { + // in host mode, the server sends rpcs to all clients. + // the host client itself will receive them too. + // -> host server is always the source of truth + // -> we can ignore any rpc on the host client + // => otherwise host objects would have ever growing clientBuffers + // (rpc goes to clients. if isServer is true too then we are host) + if (isServer) return; + + // don't apply for local player with authority + if (IsClientWithAuthority) return; + + // protect against ever growing buffer size attacks + if (clientBuffer.Count >= bufferSizeLimit) return; + + // on the client, we receive rpcs for all entities. + // not all of them have a connectionToServer. + // but all of them go through NetworkClient.connection. + // we can get the timestamp from there. + double timestamp = NetworkClient.connection.remoteTimeStamp; + + // position, rotation, scale can have no value if same as last time. + // saves bandwidth. + // but we still need to feed it to snapshot interpolation. we can't + // just have gaps in there if nothing has changed. for example, if + // client sends snapshot at t=0 + // client sends nothing for 10s because not moved + // client sends snapshot at t=10 + // then the server would assume that it's one super slow move and + // replay it for 10 seconds. + if (!position.HasValue) position = targetComponent.localPosition; + if (!rotation.HasValue) rotation = targetComponent.localRotation; + if (!scale.HasValue) scale = targetComponent.localScale; + + // construct snapshot with batch timestamp to save bandwidth + NTSnapshot snapshot = new NTSnapshot( + timestamp, + NetworkTime.localTime, + position.Value, rotation.Value, scale.Value + ); + + // add to buffer (or drop if older than first element) + SnapshotInterpolation.InsertIfNewEnough(snapshot, clientBuffer); + } + + // update ////////////////////////////////////////////////////////////// + void UpdateServer() + { + // broadcast to all clients each 'sendInterval' + // (client with authority will drop the rpc) + // NetworkTime.localTime for double precision until Unity has it too + // + // IMPORTANT: + // snapshot interpolation requires constant sending. + // DO NOT only send if position changed. for example: + // --- + // * client sends first position at t=0 + // * ... 10s later ... + // * client moves again, sends second position at t=10 + // --- + // * server gets first position at t=0 + // * server gets second position at t=10 + // * server moves from first to second within a time of 10s + // => would be a super slow move, instead of a wait & move. + // + // IMPORTANT: + // DO NOT send nulls if not changed 'since last send' either. we + // send unreliable and don't know which 'last send' the other end + // received successfully. + // + // Checks to ensure server only sends snapshots if object is + // on server authority(!clientAuthority) mode because on client + // authority mode snapshots are broadcasted right after the authoritative + // client updates server in the command function(see above), OR, + // since host does not send anything to update the server, any client + // authoritative movement done by the host will have to be broadcasted + // here by checking IsClientWithAuthority. + if (NetworkTime.localTime >= lastServerSendTime + sendInterval && + (!clientAuthority || IsClientWithAuthority)) + { + // send snapshot without timestamp. + // receiver gets it from batch timestamp to save bandwidth. + NTSnapshot snapshot = ConstructSnapshot(); + RpcServerToClientSync( + // only sync what the user wants to sync + syncPosition ? snapshot.position : new Vector3?(), + syncRotation? snapshot.rotation : new Quaternion?(), + syncScale ? snapshot.scale : new Vector3?() + ); + + lastServerSendTime = NetworkTime.localTime; + } + + // apply buffered snapshots IF client authority + // -> in server authority, server moves the object + // so no need to apply any snapshots there. + // -> don't apply for host mode player objects either, even if in + // client authority mode. if it doesn't go over the network, + // then we don't need to do anything. + if (clientAuthority && !hasAuthority) + { + // compute snapshot interpolation & apply if any was spit out + // TODO we don't have Time.deltaTime double yet. float is fine. + if (SnapshotInterpolation.Compute( + NetworkTime.localTime, Time.deltaTime, + ref serverInterpolationTime, + bufferTime, serverBuffer, + catchupThreshold, catchupMultiplier, + Interpolate, + out NTSnapshot computed)) + { + NTSnapshot start = serverBuffer.Values[0]; + NTSnapshot goal = serverBuffer.Values[1]; + ApplySnapshot(start, goal, computed); + } + } + } + + void UpdateClient() + { + // client authority, and local player (= allowed to move myself)? + if (IsClientWithAuthority) + { + // send to server each 'sendInterval' + // NetworkTime.localTime for double precision until Unity has it too + // + // IMPORTANT: + // snapshot interpolation requires constant sending. + // DO NOT only send if position changed. for example: + // --- + // * client sends first position at t=0 + // * ... 10s later ... + // * client moves again, sends second position at t=10 + // --- + // * server gets first position at t=0 + // * server gets second position at t=10 + // * server moves from first to second within a time of 10s + // => would be a super slow move, instead of a wait & move. + // + // IMPORTANT: + // DO NOT send nulls if not changed 'since last send' either. we + // send unreliable and don't know which 'last send' the other end + // received successfully. + if (NetworkTime.localTime >= lastClientSendTime + sendInterval) + { + // send snapshot without timestamp. + // receiver gets it from batch timestamp to save bandwidth. + NTSnapshot snapshot = ConstructSnapshot(); + CmdClientToServerSync( + // only sync what the user wants to sync + syncPosition ? snapshot.position : new Vector3?(), + syncRotation? snapshot.rotation : new Quaternion?(), + syncScale ? snapshot.scale : new Vector3?() + ); + + lastClientSendTime = NetworkTime.localTime; + } + } + // for all other clients (and for local player if !authority), + // we need to apply snapshots from the buffer + else + { + // compute snapshot interpolation & apply if any was spit out + // TODO we don't have Time.deltaTime double yet. float is fine. + if (SnapshotInterpolation.Compute( + NetworkTime.localTime, Time.deltaTime, + ref clientInterpolationTime, + bufferTime, clientBuffer, + catchupThreshold, catchupMultiplier, + Interpolate, + out NTSnapshot computed)) + { + NTSnapshot start = clientBuffer.Values[0]; + NTSnapshot goal = clientBuffer.Values[1]; + ApplySnapshot(start, goal, computed); + } + } + } + + void Update() + { + // if server then always sync to others. + if (isServer) UpdateServer(); + // 'else if' because host mode shouldn't send anything to server. + // it is the server. don't overwrite anything there. + else if (isClient) UpdateClient(); + } + + // common Teleport code for client->server and server->client + protected virtual void OnTeleport(Vector3 destination) + { + // reset any in-progress interpolation & buffers + Reset(); + + // set the new position. + // interpolation will automatically continue. + targetComponent.position = destination; + + // TODO + // what if we still receive a snapshot from before the interpolation? + // it could easily happen over unreliable. + // -> maybe add destionation as first entry? + } + + // server->client teleport to force position without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [ClientRpc] + public void RpcTeleport(Vector3 destination) + { + // NOTE: even in client authority mode, the server is always allowed + // to teleport the player. for example: + // * CmdEnterPortal() might teleport the player + // * Some people use client authority with server sided checks + // so the server should be able to reset position if needed. + + // TODO what about host mode? + OnTeleport(destination); + } + + // client->server teleport to force position without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [Command] + public void CmdTeleport(Vector3 destination) + { + // client can only teleport objects that it has authority over. + if (!clientAuthority) return; + + // TODO what about host mode? + OnTeleport(destination); + + // if a client teleports, we need to broadcast to everyone else too + // TODO the teleported client should ignore the rpc though. + // otherwise if it already moved again after teleporting, + // the rpc would come a little bit later and reset it once. + // TODO or not? if client ONLY calls Teleport(pos), the position + // would only be set after the rpc. unless the client calls + // BOTH Teleport(pos) and targetComponent.position=pos + RpcTeleport(destination); + } + + protected virtual void Reset() + { + // disabled objects aren't updated anymore. + // so let's clear the buffers. + serverBuffer.Clear(); + clientBuffer.Clear(); + + // reset interpolation time too so we start at t=0 next time + serverInterpolationTime = 0; + clientInterpolationTime = 0; + } + + protected virtual void OnDisable() => Reset(); + protected virtual void OnEnable() => Reset(); + + protected virtual void OnValidate() + { + // make sure that catchup threshold is > buffer multiplier. + // for a buffer multiplier of '3', we usually have at _least_ 3 + // buffered snapshots. often 4-5 even. + // + // catchUpThreshold should be a minimum of bufferTimeMultiplier + 3, + // to prevent clashes with SnapshotInterpolation looking for at least + // 3 old enough buffers, else catch up will be implemented while there + // is not enough old buffers, and will result in jitter. + // (validated with several real world tests by ninja & imer) + catchupThreshold = Mathf.Max(bufferTimeMultiplier + 3, catchupThreshold); + + // buffer limit should be at least multiplier to have enough in there + bufferSizeLimit = Mathf.Max(bufferTimeMultiplier, bufferSizeLimit); + } + +// OnGUI allocates even if it does nothing. avoid in release. +#if UNITY_EDITOR || DEVELOPMENT_BUILD + // debug /////////////////////////////////////////////////////////////// + protected virtual void OnGUI() + { + if (!showOverlay) return; + + // show data next to player for easier debugging. this is very useful! + // IMPORTANT: this is basically an ESP hack for shooter games. + // DO NOT make this available with a hotkey in release builds + if (!Debug.isDebugBuild) return; + + // project position to screen + Vector3 point = Camera.main.WorldToScreenPoint(targetComponent.position); + + // enough alpha, in front of camera and in screen? + if (point.z >= 0 && Utils.IsPointInScreen(point)) + { + // catchup is useful to show too + int serverBufferExcess = Mathf.Max(serverBuffer.Count - catchupThreshold, 0); + int clientBufferExcess = Mathf.Max(clientBuffer.Count - catchupThreshold, 0); + float serverCatchup = serverBufferExcess * catchupMultiplier; + float clientCatchup = clientBufferExcess * catchupMultiplier; + + GUI.color = overlayColor; + GUILayout.BeginArea(new Rect(point.x, Screen.height - point.y, 200, 100)); + + // always show both client & server buffers so it's super + // obvious if we accidentally populate both. + GUILayout.Label($"Server Buffer:{serverBuffer.Count}"); + if (serverCatchup > 0) + GUILayout.Label($"Server Catchup:{serverCatchup*100:F2}%"); + + GUILayout.Label($"Client Buffer:{clientBuffer.Count}"); + if (clientCatchup > 0) + GUILayout.Label($"Client Catchup:{clientCatchup*100:F2}%"); + + GUILayout.EndArea(); + GUI.color = Color.white; + } + } + + protected virtual void DrawGizmos(SortedList buffer) + { + // only draw if we have at least two entries + if (buffer.Count < 2) return; + + // calcluate threshold for 'old enough' snapshots + double threshold = NetworkTime.localTime - bufferTime; + Color oldEnoughColor = new Color(0, 1, 0, 0.5f); + Color notOldEnoughColor = new Color(0.5f, 0.5f, 0.5f, 0.3f); + + // draw the whole buffer for easier debugging. + // it's worth seeing how much we have buffered ahead already + for (int i = 0; i < buffer.Count; ++i) + { + // color depends on if old enough or not + NTSnapshot entry = buffer.Values[i]; + bool oldEnough = entry.localTimestamp <= threshold; + Gizmos.color = oldEnough ? oldEnoughColor : notOldEnoughColor; + Gizmos.DrawCube(entry.position, Vector3.one); + } + + // extra: lines between start<->position<->goal + Gizmos.color = Color.green; + Gizmos.DrawLine(buffer.Values[0].position, targetComponent.position); + Gizmos.color = Color.white; + Gizmos.DrawLine(targetComponent.position, buffer.Values[1].position); + } + + protected virtual void OnDrawGizmos() + { + // This fires in edit mode but that spams NRE's so check isPlaying + if (!Application.isPlaying) return; + if (!showGizmos) return; + + if (isServer) DrawGizmos(serverBuffer); + if (isClient) DrawGizmos(clientBuffer); + } +#endif + } +} diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformBase.cs.meta b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformBase.cs.meta new file mode 100644 index 0000000..3ce0661 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e77294d8ccbc4e7cb8ca2bd0d3e99ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformChild.cs b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformChild.cs new file mode 100644 index 0000000..6e6cf06 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformChild.cs @@ -0,0 +1,13 @@ +// A component to synchronize the position of child transforms of networked objects. +// There must be a NetworkTransform on the root object of the hierarchy. There can be multiple NetworkTransformChild components on an object. This does not use physics for synchronization, it simply synchronizes the localPosition and localRotation of the child transform and lerps towards the recieved values. +using UnityEngine; + +namespace Mirror +{ + public class NetworkTransformChild : NetworkTransformBase + { + [Header("Target")] + public Transform target; + protected override Transform targetComponent => target; + } +} diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformChild.cs.meta b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformChild.cs.meta new file mode 100644 index 0000000..4fce429 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformChild.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 734b48bea0b204338958ee3d885e11f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformSnapshot.cs b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformSnapshot.cs new file mode 100644 index 0000000..510665a --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformSnapshot.cs @@ -0,0 +1,62 @@ +// snapshot for snapshot interpolation +// https://gafferongames.com/post/snapshot_interpolation/ +// position, rotation, scale for compatibility for now. +using UnityEngine; + +namespace Mirror +{ + // NetworkTransform Snapshot + public struct NTSnapshot : Snapshot + { + // time or sequence are needed to throw away older snapshots. + // + // glenn fiedler starts with a 16 bit sequence number. + // supposedly this is meant as a simplified example. + // in the end we need the remote timestamp for accurate interpolation + // and buffering over time. + // + // note: in theory, IF server sends exactly(!) at the same interval then + // the 16 bit ushort timestamp would be enough to calculate the + // remote time (sequence * sendInterval). but Unity's update is + // not guaranteed to run on the exact intervals / do catchup. + // => remote timestamp is better for now + // + // [REMOTE TIME, NOT LOCAL TIME] + // => DOUBLE for long term accuracy & batching gives us double anyway + public double remoteTimestamp { get; set; } + public double localTimestamp { get; set; } + + public Vector3 position; + public Quaternion rotation; + public Vector3 scale; + + public NTSnapshot(double remoteTimestamp, double localTimestamp, Vector3 position, Quaternion rotation, Vector3 scale) + { + this.remoteTimestamp = remoteTimestamp; + this.localTimestamp = localTimestamp; + this.position = position; + this.rotation = rotation; + this.scale = scale; + } + + public static NTSnapshot Interpolate(NTSnapshot from, NTSnapshot to, double t) + { + // NOTE: + // Vector3 & Quaternion components are float anyway, so we can + // keep using the functions with 't' as float instead of double. + return new NTSnapshot( + // interpolated snapshot is applied directly. don't need timestamps. + 0, 0, + // lerp position/rotation/scale unclamped in case we ever need + // to extrapolate. atm SnapshotInterpolation never does. + Vector3.LerpUnclamped(from.position, to.position, (float)t), + // IMPORTANT: LerpUnclamped(0, 60, 1.5) extrapolates to ~86. + // SlerpUnclamped(0, 60, 1.5) extrapolates to 90! + // (0, 90, 1.5) is even worse. for Lerp. + // => Slerp works way better for our euler angles. + Quaternion.SlerpUnclamped(from.rotation, to.rotation, (float)t), + Vector3.LerpUnclamped(from.scale, to.scale, (float)t) + ); + } + } +} diff --git a/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformSnapshot.cs.meta b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformSnapshot.cs.meta new file mode 100644 index 0000000..ea0c9dc --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform2k/NetworkTransformSnapshot.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3dae77b43dc4e1dbb2012924b2da79c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor.meta b/Assets/Mirror/Editor.meta new file mode 100644 index 0000000..0c23e8c --- /dev/null +++ b/Assets/Mirror/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2539267b6934a4026a505690a1e1eda2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/EditorHelper.cs b/Assets/Mirror/Editor/EditorHelper.cs new file mode 100644 index 0000000..7870d62 --- /dev/null +++ b/Assets/Mirror/Editor/EditorHelper.cs @@ -0,0 +1,31 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + public static class EditorHelper + { + public static string FindPath() + { + string typeName = typeof(T).Name; + + string[] guidsFound = AssetDatabase.FindAssets($"t:Script " + typeName); + if (guidsFound.Length >= 1 && !string.IsNullOrEmpty(guidsFound[0])) + { + if (guidsFound.Length > 1) + { + Debug.LogWarning($"Found more than one{typeName}"); + } + + string path = AssetDatabase.GUIDToAssetPath(guidsFound[0]); + return Path.GetDirectoryName(path); + } + else + { + Debug.LogError($"Could not find path of {typeName}"); + return string.Empty; + } + } + } +} diff --git a/Assets/Mirror/Editor/EditorHelper.cs.meta b/Assets/Mirror/Editor/EditorHelper.cs.meta new file mode 100644 index 0000000..02aec40 --- /dev/null +++ b/Assets/Mirror/Editor/EditorHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dba787f167ff29c4288532af1ec3584c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty.meta b/Assets/Mirror/Editor/Empty.meta new file mode 100644 index 0000000..2c2233e --- /dev/null +++ b/Assets/Mirror/Editor/Empty.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 62c8dc5bb12bbc6428bb66ccbac57000 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty/LogLevelWindow.cs b/Assets/Mirror/Editor/Empty/LogLevelWindow.cs new file mode 100644 index 0000000..82e5275 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/LogLevelWindow.cs @@ -0,0 +1 @@ +// File moved to Mirror/Editor/Logging/LogLevelWindow.cs \ No newline at end of file diff --git a/Assets/Mirror/Editor/Empty/LogLevelWindow.cs.meta b/Assets/Mirror/Editor/Empty/LogLevelWindow.cs.meta new file mode 100644 index 0000000..a068358 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/LogLevelWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f28def2148ed5194abe70af012a4e3e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty/Logging.meta b/Assets/Mirror/Editor/Empty/Logging.meta new file mode 100644 index 0000000..0919d1e --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d97731cd74ac8b4b8aad808548ef9cd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs b/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs new file mode 100644 index 0000000..39b95f7 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs @@ -0,0 +1 @@ +// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs.meta b/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs.meta new file mode 100644 index 0000000..aff9fad --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3dbf48190d77d243b87962a82c3b164 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs b/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs new file mode 100644 index 0000000..39b95f7 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs @@ -0,0 +1 @@ +// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs.meta b/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs.meta new file mode 100644 index 0000000..bc9e68c --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d6ce9d62a2d2ec4d8cef8a0d22b8dd2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs b/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs new file mode 100644 index 0000000..39b95f7 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs @@ -0,0 +1 @@ +// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs.meta b/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs.meta new file mode 100644 index 0000000..1a456c5 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f4ecb3d81ce9ff44b91f311ee46d4ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs b/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs new file mode 100644 index 0000000..39b95f7 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs @@ -0,0 +1 @@ +// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs.meta b/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs.meta new file mode 100644 index 0000000..21d0db6 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37fb96d5bbf965d47acfc5c8589a1b71 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs b/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs new file mode 100644 index 0000000..39b95f7 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs @@ -0,0 +1 @@ +// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs.meta b/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs.meta new file mode 100644 index 0000000..c1cfe35 --- /dev/null +++ b/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4d54a29ddd5b52b4eaa07ed39c0e3e83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs b/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs new file mode 100644 index 0000000..4c4d339 --- /dev/null +++ b/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs @@ -0,0 +1,52 @@ +// Unity 2019.3 has an experimental 'disable domain reload on play' +// feature. keeping any global state between sessions will break +// Mirror and most of our user's projects. don't allow it for now. +// https://blogs.unity3d.com/2019/11/05/enter-play-mode-faster-in-unity-2019-3/ +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + public class EnterPlayModeSettingsCheck : MonoBehaviour + { + [InitializeOnLoadMethod] + static void OnInitializeOnLoad() + { +#if UNITY_2019_3_OR_NEWER + // We can't support experimental "Enter Play Mode Options" mode + // Check immediately on load, and before entering play mode, and warn the user + CheckPlayModeOptions(); +#endif + + // Hook this event to see if we have a good weave every time + // user attempts to enter play mode or tries to do a build + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + } + + static void OnPlayModeStateChanged(PlayModeStateChange state) + { + // Per Unity docs, this fires "when exiting edit mode before the Editor is in play mode". + // This doesn't fire when closing the editor. + if (state == PlayModeStateChange.ExitingEditMode) + { +#if UNITY_2019_3_OR_NEWER + // We can't support experimental "Enter Play Mode Options" mode + // Check and prevent entering play mode if enabled + CheckPlayModeOptions(); +#endif + } + } + +#if UNITY_2019_3_OR_NEWER + static void CheckPlayModeOptions() + { + // enabling the checkbox is enough. it controls all the other settings. + if (EditorSettings.enterPlayModeOptionsEnabled) + { + Debug.LogError("Enter Play Mode Options are not supported by Mirror. Please disable 'ProjectSettings -> Editor -> Enter Play Mode Settings (Experimental)'."); + EditorApplication.isPlaying = false; + } + } +#endif + } +} diff --git a/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs.meta b/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs.meta new file mode 100644 index 0000000..49a4298 --- /dev/null +++ b/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b15a0d2ca0909400eb53dd6fe894cddd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/InspectorHelper.cs b/Assets/Mirror/Editor/InspectorHelper.cs new file mode 100644 index 0000000..40d2f1e --- /dev/null +++ b/Assets/Mirror/Editor/InspectorHelper.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; + +namespace Mirror +{ + public static class InspectorHelper + { + /// + /// Gets all public and private fields for a type + /// + /// + /// Stops at this base type (exclusive) + /// + public static IEnumerable GetAllFields(Type type, Type deepestBaseType) + { + const BindingFlags publicFields = BindingFlags.Public | BindingFlags.Instance; + const BindingFlags privateFields = BindingFlags.NonPublic | BindingFlags.Instance; + + // get public fields (includes fields from base type) + FieldInfo[] allPublicFields = type.GetFields(publicFields); + foreach (FieldInfo field in allPublicFields) + { + yield return field; + } + + // get private fields in current type, then move to base type + while (type != null) + { + FieldInfo[] allPrivateFields = type.GetFields(privateFields); + foreach (FieldInfo field in allPrivateFields) + { + yield return field; + } + + type = type.BaseType; + + // stop early + if (type == deepestBaseType) + { + break; + } + } + } + + public static bool IsSyncVar(this FieldInfo field) + { + object[] fieldMarkers = field.GetCustomAttributes(typeof(SyncVarAttribute), true); + return fieldMarkers.Length > 0; + } + public static bool IsSerializeField(this FieldInfo field) + { + object[] fieldMarkers = field.GetCustomAttributes(typeof(SerializeField), true); + return fieldMarkers.Length > 0; + } + public static bool IsVisibleField(this FieldInfo field) + { + return field.IsPublic || IsSerializeField(field); + } + + public static bool IsSyncObject(this FieldInfo field) + { + return typeof(SyncObject).IsAssignableFrom(field.FieldType); + } + public static bool HasShowInInspector(this FieldInfo field) + { + object[] fieldMarkers = field.GetCustomAttributes(typeof(ShowInInspectorAttribute), true); + return fieldMarkers.Length > 0; + } + public static bool IsVisibleSyncObject(this FieldInfo field) + { + return field.IsPublic || HasShowInInspector(field); + } + } +} diff --git a/Assets/Mirror/Editor/InspectorHelper.cs.meta b/Assets/Mirror/Editor/InspectorHelper.cs.meta new file mode 100644 index 0000000..bb6cb6c --- /dev/null +++ b/Assets/Mirror/Editor/InspectorHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 047c894c2a5ccc1438b7e59302f62744 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Mirror.Editor.asmdef b/Assets/Mirror/Editor/Mirror.Editor.asmdef new file mode 100644 index 0000000..0d59f9f --- /dev/null +++ b/Assets/Mirror/Editor/Mirror.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "Mirror.Editor", + "rootNamespace": "", + "references": [ + "Mirror", + "Unity.Mirror.CodeGen" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta b/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta new file mode 100644 index 0000000..ba2d88c --- /dev/null +++ b/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1c7c33eb5480dd24c9e29a8250c1a775 +AssemblyDefinitionImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs new file mode 100644 index 0000000..cc56210 --- /dev/null +++ b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomEditor(typeof(NetworkBehaviour), true)] + [CanEditMultipleObjects] + public class NetworkBehaviourInspector : Editor + { + /// + /// List of all visible syncVars in target class + /// + protected List syncVarNames = new List(); + bool syncsAnything; + SyncListDrawer syncListDrawer; + + // does this type sync anything? otherwise we don't need to show syncInterval + bool SyncsAnything(Type scriptClass) + { + // check for all SyncVar fields, they don't have to be visible + foreach (FieldInfo field in InspectorHelper.GetAllFields(scriptClass, typeof(NetworkBehaviour))) + { + if (field.IsSyncVar()) + { + return true; + } + } + + // has OnSerialize that is not in NetworkBehaviour? + // then it either has a syncvar or custom OnSerialize. either way + // this means we have something to sync. + MethodInfo method = scriptClass.GetMethod("OnSerialize"); + if (method != null && method.DeclaringType != typeof(NetworkBehaviour)) + { + return true; + } + + // SyncObjects are serialized in NetworkBehaviour.OnSerialize, which + // is always there even if we don't use SyncObjects. so we need to + // search for SyncObjects manually. + // Any SyncObject should be added to syncObjects when unity creates an + // object so we can check length of list so see if sync objects exists + FieldInfo syncObjectsField = scriptClass.GetField("syncObjects", BindingFlags.NonPublic | BindingFlags.Instance); + List syncObjects = (List)syncObjectsField.GetValue(serializedObject.targetObject); + + return syncObjects.Count > 0; + } + + void OnEnable() + { + if (target == null) { Debug.LogWarning("NetworkBehaviourInspector had no target object"); return; } + + // If target's base class is changed from NetworkBehaviour to MonoBehaviour + // then Unity temporarily keep using this Inspector causing things to break + if (!(target is NetworkBehaviour)) { return; } + + Type scriptClass = target.GetType(); + + syncVarNames = new List(); + foreach (FieldInfo field in InspectorHelper.GetAllFields(scriptClass, typeof(NetworkBehaviour))) + { + if (field.IsSyncVar() && field.IsVisibleField()) + { + syncVarNames.Add(field.Name); + } + } + + syncListDrawer = new SyncListDrawer(serializedObject.targetObject); + + syncsAnything = SyncsAnything(scriptClass); + } + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + DrawDefaultSyncLists(); + DrawDefaultSyncSettings(); + } + + /// + /// Draws Sync Objects that are IEnumerable + /// + protected void DrawDefaultSyncLists() + { + // Need this check in case OnEnable returns early + if (syncListDrawer == null) { return; } + + syncListDrawer.Draw(); + } + + /// + /// Draws SyncSettings if the NetworkBehaviour has anything to sync + /// + protected void DrawDefaultSyncSettings() + { + // does it sync anything? then show extra properties + // (no need to show it if the class only has Cmds/Rpcs and no sync) + if (!syncsAnything) + { + return; + } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Sync Settings", EditorStyles.boldLabel); + + EditorGUILayout.PropertyField(serializedObject.FindProperty("syncMode")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("syncInterval")); + + // apply + serializedObject.ApplyModifiedProperties(); + } + } + public class SyncListDrawer + { + readonly UnityEngine.Object targetObject; + readonly List syncListFields; + + public SyncListDrawer(UnityEngine.Object targetObject) + { + this.targetObject = targetObject; + syncListFields = new List(); + foreach (FieldInfo field in InspectorHelper.GetAllFields(targetObject.GetType(), typeof(NetworkBehaviour))) + { + if (field.IsSyncObject() && field.IsVisibleSyncObject()) + { + syncListFields.Add(new SyncListField(field)); + } + } + } + + public void Draw() + { + if (syncListFields.Count == 0) { return; } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Sync Lists", EditorStyles.boldLabel); + + for (int i = 0; i < syncListFields.Count; i++) + { + DrawSyncList(syncListFields[i]); + } + } + + void DrawSyncList(SyncListField syncListField) + { + syncListField.visible = EditorGUILayout.Foldout(syncListField.visible, syncListField.label); + if (syncListField.visible) + { + using (new EditorGUI.IndentLevelScope()) + { + object fieldValue = syncListField.field.GetValue(targetObject); + if (fieldValue is IEnumerable synclist) + { + int index = 0; + foreach (object item in synclist) + { + string itemValue = item != null ? item.ToString() : "NULL"; + string itemLabel = "Element " + index; + EditorGUILayout.LabelField(itemLabel, itemValue); + + index++; + } + } + } + } + } + + class SyncListField + { + public bool visible; + public readonly FieldInfo field; + public readonly string label; + + public SyncListField(FieldInfo field) + { + this.field = field; + visible = false; + label = field.Name + " [" + field.FieldType.Name + "]"; + } + } + } +} diff --git a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta new file mode 100644 index 0000000..2a4a45a --- /dev/null +++ b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f02853db46b6346e4866594a96c3b0e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/NetworkInformationPreview.cs b/Assets/Mirror/Editor/NetworkInformationPreview.cs new file mode 100644 index 0000000..0c30298 --- /dev/null +++ b/Assets/Mirror/Editor/NetworkInformationPreview.cs @@ -0,0 +1,305 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomPreview(typeof(GameObject))] + class NetworkInformationPreview : ObjectPreview + { + struct NetworkIdentityInfo + { + public GUIContent name; + public GUIContent value; + } + + struct NetworkBehaviourInfo + { + // This is here just so we can check if it's enabled/disabled + public NetworkBehaviour behaviour; + public GUIContent name; + } + + class Styles + { + public GUIStyle labelStyle = new GUIStyle(EditorStyles.label); + public GUIStyle componentName = new GUIStyle(EditorStyles.boldLabel); + public GUIStyle disabledName = new GUIStyle(EditorStyles.miniLabel); + + public Styles() + { + Color fontColor = new Color(0.7f, 0.7f, 0.7f); + labelStyle.padding.right += 20; + labelStyle.normal.textColor = fontColor; + labelStyle.active.textColor = fontColor; + labelStyle.focused.textColor = fontColor; + labelStyle.hover.textColor = fontColor; + labelStyle.onNormal.textColor = fontColor; + labelStyle.onActive.textColor = fontColor; + labelStyle.onFocused.textColor = fontColor; + labelStyle.onHover.textColor = fontColor; + + componentName.normal.textColor = fontColor; + componentName.active.textColor = fontColor; + componentName.focused.textColor = fontColor; + componentName.hover.textColor = fontColor; + componentName.onNormal.textColor = fontColor; + componentName.onActive.textColor = fontColor; + componentName.onFocused.textColor = fontColor; + componentName.onHover.textColor = fontColor; + + disabledName.normal.textColor = fontColor; + disabledName.active.textColor = fontColor; + disabledName.focused.textColor = fontColor; + disabledName.hover.textColor = fontColor; + disabledName.onNormal.textColor = fontColor; + disabledName.onActive.textColor = fontColor; + disabledName.onFocused.textColor = fontColor; + disabledName.onHover.textColor = fontColor; + } + } + + GUIContent title; + Styles styles = new Styles(); + + public override GUIContent GetPreviewTitle() + { + if (title == null) + { + title = new GUIContent("Network Information"); + } + return title; + } + + public override bool HasPreviewGUI() + { + // need to check if target is null to stop MissingReferenceException + return target != null && target is GameObject gameObject && gameObject.GetComponent() != null; + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + if (Event.current.type != EventType.Repaint) + return; + + if (target == null) + return; + + GameObject targetGameObject = target as GameObject; + + if (targetGameObject == null) + return; + + NetworkIdentity identity = targetGameObject.GetComponent(); + + if (identity == null) + return; + + if (styles == null) + styles = new Styles(); + + + // padding + RectOffset previewPadding = new RectOffset(-5, -5, -5, -5); + Rect paddedr = previewPadding.Add(r); + + //Centering + float initialX = paddedr.x + 10; + float Y = paddedr.y + 10; + + Y = DrawNetworkIdentityInfo(identity, initialX, Y); + + Y = DrawNetworkBehaviors(identity, initialX, Y); + + Y = DrawObservers(identity, initialX, Y); + + _ = DrawOwner(identity, initialX, Y); + + } + + float DrawNetworkIdentityInfo(NetworkIdentity identity, float initialX, float Y) + { + IEnumerable infos = GetNetworkIdentityInfo(identity); + // Get required label size for the names of the information values we're going to show + // There are two columns, one with label for the name of the info and the next for the value + Vector2 maxNameLabelSize = new Vector2(140, 16); + Vector2 maxValueLabelSize = GetMaxNameLabelSize(infos); + + Rect labelRect = new Rect(initialX, Y, maxNameLabelSize.x, maxNameLabelSize.y); + Rect idLabelRect = new Rect(maxNameLabelSize.x, Y, maxValueLabelSize.x, maxValueLabelSize.y); + + foreach (NetworkIdentityInfo info in infos) + { + GUI.Label(labelRect, info.name, styles.labelStyle); + GUI.Label(idLabelRect, info.value, styles.componentName); + labelRect.y += labelRect.height; + labelRect.x = initialX; + idLabelRect.y += idLabelRect.height; + } + + return labelRect.y; + } + + float DrawNetworkBehaviors(NetworkIdentity identity, float initialX, float Y) + { + IEnumerable behavioursInfo = GetNetworkBehaviorInfo(identity); + + // Show behaviours list in a different way than the name/value pairs above + Vector2 maxBehaviourLabelSize = GetMaxBehaviourLabelSize(behavioursInfo); + Rect behaviourRect = new Rect(initialX, Y + 10, maxBehaviourLabelSize.x, maxBehaviourLabelSize.y); + + GUI.Label(behaviourRect, new GUIContent("Network Behaviours"), styles.labelStyle); + // indent names + behaviourRect.x += 20; + behaviourRect.y += behaviourRect.height; + + foreach (NetworkBehaviourInfo info in behavioursInfo) + { + if (info.behaviour == null) + { + // could be the case in the editor after existing play mode. + continue; + } + + GUI.Label(behaviourRect, info.name, info.behaviour.enabled ? styles.componentName : styles.disabledName); + behaviourRect.y += behaviourRect.height; + Y = behaviourRect.y; + } + + return Y; + } + + float DrawObservers(NetworkIdentity identity, float initialX, float Y) + { + if (identity.observers != null && identity.observers.Count > 0) + { + Rect observerRect = new Rect(initialX, Y + 10, 200, 20); + + GUI.Label(observerRect, new GUIContent("Network observers"), styles.labelStyle); + // indent names + observerRect.x += 20; + observerRect.y += observerRect.height; + + foreach (KeyValuePair kvp in identity.observers) + { + GUI.Label(observerRect, kvp.Value.address + ":" + kvp.Value, styles.componentName); + observerRect.y += observerRect.height; + Y = observerRect.y; + } + } + + return Y; + } + + float DrawOwner(NetworkIdentity identity, float initialX, float Y) + { + if (identity.connectionToClient != null) + { + Rect ownerRect = new Rect(initialX, Y + 10, 400, 20); + GUI.Label(ownerRect, new GUIContent("Client Authority: " + identity.connectionToClient), styles.labelStyle); + Y += ownerRect.height; + } + return Y; + } + + // Get the maximum size used by the value of information items + Vector2 GetMaxNameLabelSize(IEnumerable infos) + { + Vector2 maxLabelSize = Vector2.zero; + foreach (NetworkIdentityInfo info in infos) + { + Vector2 labelSize = styles.labelStyle.CalcSize(info.value); + if (maxLabelSize.x < labelSize.x) + { + maxLabelSize.x = labelSize.x; + } + if (maxLabelSize.y < labelSize.y) + { + maxLabelSize.y = labelSize.y; + } + } + return maxLabelSize; + } + + Vector2 GetMaxBehaviourLabelSize(IEnumerable behavioursInfo) + { + Vector2 maxLabelSize = Vector2.zero; + foreach (NetworkBehaviourInfo behaviour in behavioursInfo) + { + Vector2 labelSize = styles.labelStyle.CalcSize(behaviour.name); + if (maxLabelSize.x < labelSize.x) + { + maxLabelSize.x = labelSize.x; + } + if (maxLabelSize.y < labelSize.y) + { + maxLabelSize.y = labelSize.y; + } + } + return maxLabelSize; + } + + IEnumerable GetNetworkIdentityInfo(NetworkIdentity identity) + { + List infos = new List + { + GetAssetId(identity), + GetString("Scene ID", identity.sceneId.ToString("X")) + }; + + if (Application.isPlaying) + { + infos.Add(GetString("Network ID", identity.netId.ToString())); + infos.Add(GetBoolean("Is Client", identity.isClient)); + infos.Add(GetBoolean("Is Server", identity.isServer)); + infos.Add(GetBoolean("Has Authority", identity.hasAuthority)); + infos.Add(GetBoolean("Is Local Player", identity.isLocalPlayer)); + } + return infos; + } + + IEnumerable GetNetworkBehaviorInfo(NetworkIdentity identity) + { + List behaviourInfos = new List(); + + NetworkBehaviour[] behaviours = identity.GetComponents(); + foreach (NetworkBehaviour behaviour in behaviours) + { + behaviourInfos.Add(new NetworkBehaviourInfo + { + name = new GUIContent(behaviour.GetType().FullName), + behaviour = behaviour + }); + } + return behaviourInfos; + } + + NetworkIdentityInfo GetAssetId(NetworkIdentity identity) + { + string assetId = identity.assetId.ToString(); + if (string.IsNullOrEmpty(assetId)) + { + assetId = ""; + } + return GetString("Asset ID", assetId); + } + + static NetworkIdentityInfo GetString(string name, string value) + { + return new NetworkIdentityInfo + { + name = new GUIContent(name), + value = new GUIContent(value) + }; + } + + static NetworkIdentityInfo GetBoolean(string name, bool value) + { + return new NetworkIdentityInfo + { + name = new GUIContent(name), + value = new GUIContent((value ? "Yes" : "No")) + }; + } + } +} diff --git a/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta b/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta new file mode 100644 index 0000000..c93e6c0 --- /dev/null +++ b/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51a99294efe134232932c34606737356 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/NetworkManagerEditor.cs b/Assets/Mirror/Editor/NetworkManagerEditor.cs new file mode 100644 index 0000000..4f80de1 --- /dev/null +++ b/Assets/Mirror/Editor/NetworkManagerEditor.cs @@ -0,0 +1,108 @@ +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace Mirror +{ + [CustomEditor(typeof(NetworkManager), true)] + [CanEditMultipleObjects] + public class NetworkManagerEditor : Editor + { + SerializedProperty spawnListProperty; + ReorderableList spawnList; + protected NetworkManager networkManager; + + protected void Init() + { + if (spawnList == null) + { + networkManager = target as NetworkManager; + spawnListProperty = serializedObject.FindProperty("spawnPrefabs"); + spawnList = new ReorderableList(serializedObject, spawnListProperty) + { + drawHeaderCallback = DrawHeader, + drawElementCallback = DrawChild, + onReorderCallback = Changed, + onRemoveCallback = RemoveButton, + onChangedCallback = Changed, + onAddCallback = AddButton, + // this uses a 16x16 icon. other sizes make it stretch. + elementHeight = 16 + }; + } + } + + public override void OnInspectorGUI() + { + Init(); + DrawDefaultInspector(); + EditorGUI.BeginChangeCheck(); + spawnList.DoLayoutList(); + if (EditorGUI.EndChangeCheck()) + { + serializedObject.ApplyModifiedProperties(); + } + } + + static void DrawHeader(Rect headerRect) + { + GUI.Label(headerRect, "Registered Spawnable Prefabs:"); + } + + internal void DrawChild(Rect r, int index, bool isActive, bool isFocused) + { + SerializedProperty prefab = spawnListProperty.GetArrayElementAtIndex(index); + GameObject go = (GameObject)prefab.objectReferenceValue; + + GUIContent label; + if (go == null) + { + label = new GUIContent("Empty", "Drag a prefab with a NetworkIdentity here"); + } + else + { + NetworkIdentity identity = go.GetComponent(); + label = new GUIContent(go.name, identity != null ? "AssetId: [" + identity.assetId + "]" : "No Network Identity"); + } + + GameObject newGameObject = (GameObject)EditorGUI.ObjectField(r, label, go, typeof(GameObject), false); + + if (newGameObject != go) + { + if (newGameObject != null && !newGameObject.GetComponent()) + { + Debug.LogError("Prefab " + newGameObject + " cannot be added as spawnable as it doesn't have a NetworkIdentity."); + return; + } + prefab.objectReferenceValue = newGameObject; + } + } + + internal void Changed(ReorderableList list) + { + EditorUtility.SetDirty(target); + } + + internal void AddButton(ReorderableList list) + { + spawnListProperty.arraySize += 1; + list.index = spawnListProperty.arraySize - 1; + + SerializedProperty obj = spawnListProperty.GetArrayElementAtIndex(spawnListProperty.arraySize - 1); + obj.objectReferenceValue = null; + + spawnList.index = spawnList.count - 1; + + Changed(list); + } + + internal void RemoveButton(ReorderableList list) + { + spawnListProperty.DeleteArrayElementAtIndex(spawnList.index); + if (list.index >= spawnListProperty.arraySize) + { + list.index = spawnListProperty.arraySize - 1; + } + } + } +} diff --git a/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta b/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta new file mode 100644 index 0000000..6fb657e --- /dev/null +++ b/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 519712eb07f7a44039df57664811c2c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/NetworkScenePostProcess.cs b/Assets/Mirror/Editor/NetworkScenePostProcess.cs new file mode 100644 index 0000000..c60493d --- /dev/null +++ b/Assets/Mirror/Editor/NetworkScenePostProcess.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEngine; + +namespace Mirror +{ + public class NetworkScenePostProcess : MonoBehaviour + { + [PostProcessScene] + public static void OnPostProcessScene() + { + // find all NetworkIdentities in all scenes + // => can't limit it to GetActiveScene() because that wouldn't work + // for additive scene loads (the additively loaded scene is never + // the active scene) + // => ignore DontDestroyOnLoad scene! this avoids weird situations + // like in NetworkZones when we destroy the local player and + // load another scene afterwards, yet the local player is still + // in the FindObjectsOfType result with scene=DontDestroyOnLoad + // for some reason + // => OfTypeAll so disabled objects are included too + // => Unity 2019 returns prefabs here too, so filter them out. + IEnumerable identities = Resources.FindObjectsOfTypeAll() + .Where(identity => identity.gameObject.hideFlags != HideFlags.NotEditable && + identity.gameObject.hideFlags != HideFlags.HideAndDontSave && + identity.gameObject.scene.name != "DontDestroyOnLoad" && + !Utils.IsPrefab(identity.gameObject)); + + foreach (NetworkIdentity identity in identities) + { + // if we had a [ConflictComponent] attribute that would be better than this check. + // also there is no context about which scene this is in. + if (identity.GetComponent() != null) + { + Debug.LogError("NetworkManager has a NetworkIdentity component. This will cause the NetworkManager object to be disabled, so it is not recommended."); + } + + // not spawned before? + // OnPostProcessScene is called after additive scene loads too, + // and we don't want to set main scene's objects inactive again + if (!identity.isClient && !identity.isServer) + { + // valid scene object? + // otherwise it might be an unopened scene that still has null + // sceneIds. builds are interrupted if they contain 0 sceneIds, + // but it's still possible that we call LoadScene in Editor + // for a previously unopened scene. + // (and only do SetActive if this was actually a scene object) + if (identity.sceneId != 0) + { + PrepareSceneObject(identity); + } + // throwing an exception would only show it for one object + // because this function would return afterwards. + else + { + // there are two cases where sceneId == 0: + // * if we have a prefab open in the prefab scene + // * if an unopened scene needs resaving + // show a proper error message in both cases so the user + // knows what to do. + string path = identity.gameObject.scene.path; + if (string.IsNullOrWhiteSpace(path)) + Debug.LogError($"{identity.name} is currently open in Prefab Edit Mode. Please open the actual scene before launching Mirror."); + else + Debug.LogError($"Scene {path} needs to be opened and resaved, because the scene object {identity.name} has no valid sceneId yet."); + + // either way we shouldn't continue. nothing good will + // happen when trying to launch with invalid sceneIds. + EditorApplication.isPlaying = false; + } + } + } + } + + static void PrepareSceneObject(NetworkIdentity identity) + { + // set scene hash + identity.SetSceneIdSceneHashPartInternal(); + + // disable it + // note: NetworkIdentity.OnDisable adds itself to the + // spawnableObjects dictionary (only if sceneId != 0) + identity.gameObject.SetActive(false); + + // safety check for prefabs with more than one NetworkIdentity +#if UNITY_2018_2_OR_NEWER + GameObject prefabGO = PrefabUtility.GetCorrespondingObjectFromSource(identity.gameObject); +#else + GameObject prefabGO = PrefabUtility.GetPrefabParent(identity.gameObject); +#endif + if (prefabGO) + { +#if UNITY_2018_3_OR_NEWER + GameObject prefabRootGO = prefabGO.transform.root.gameObject; +#else + GameObject prefabRootGO = PrefabUtility.FindPrefabRoot(prefabGO); +#endif + if (prefabRootGO != null && prefabRootGO.GetComponentsInChildren().Length > 1) + { + Debug.LogWarning($"Prefab {prefabRootGO.name} has several NetworkIdentity components attached to itself or its children, this is not supported."); + } + } + } + } +} diff --git a/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta b/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta new file mode 100644 index 0000000..53b148f --- /dev/null +++ b/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3ec1c414d821444a9e77f18a2c130ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/SceneDrawer.cs b/Assets/Mirror/Editor/SceneDrawer.cs new file mode 100644 index 0000000..cb3b731 --- /dev/null +++ b/Assets/Mirror/Editor/SceneDrawer.cs @@ -0,0 +1,47 @@ +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomPropertyDrawer(typeof(SceneAttribute))] + public class SceneDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (property.propertyType == SerializedPropertyType.String) + { + SceneAsset sceneObject = AssetDatabase.LoadAssetAtPath(property.stringValue); + + if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue)) + { + // try to load it from the build settings for legacy compatibility + sceneObject = GetBuildSettingsSceneObject(property.stringValue); + } + if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue)) + { + Debug.LogError($"Could not find scene {property.stringValue} in {property.propertyPath}, assign the proper scenes in your NetworkManager"); + } + SceneAsset scene = (SceneAsset)EditorGUI.ObjectField(position, label, sceneObject, typeof(SceneAsset), true); + + property.stringValue = AssetDatabase.GetAssetPath(scene); + } + else + { + EditorGUI.LabelField(position, label.text, "Use [Scene] with strings."); + } + } + + protected SceneAsset GetBuildSettingsSceneObject(string sceneName) + { + foreach (EditorBuildSettingsScene buildScene in EditorBuildSettings.scenes) + { + SceneAsset sceneAsset = AssetDatabase.LoadAssetAtPath(buildScene.path); + if (sceneAsset!= null && sceneAsset.name == sceneName) + { + return sceneAsset; + } + } + return null; + } + } +} diff --git a/Assets/Mirror/Editor/SceneDrawer.cs.meta b/Assets/Mirror/Editor/SceneDrawer.cs.meta new file mode 100644 index 0000000..e37ff9c --- /dev/null +++ b/Assets/Mirror/Editor/SceneDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b24704a46211b4ea294aba8f58715cea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs new file mode 100644 index 0000000..2356a5e --- /dev/null +++ b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs @@ -0,0 +1,28 @@ +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomPropertyDrawer(typeof(SyncVarAttribute))] + public class SyncVarAttributeDrawer : PropertyDrawer + { + static readonly GUIContent syncVarIndicatorContent = new GUIContent("SyncVar", "This variable has been marked with the [SyncVar] attribute."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Vector2 syncVarIndicatorRect = EditorStyles.miniLabel.CalcSize(syncVarIndicatorContent); + float valueWidth = position.width - syncVarIndicatorRect.x; + + Rect valueRect = new Rect(position.x, position.y, valueWidth, position.height); + Rect labelRect = new Rect(position.x + valueWidth, position.y, syncVarIndicatorRect.x, position.height); + + EditorGUI.PropertyField(valueRect, property, label, true); + GUI.Label(labelRect, syncVarIndicatorContent, EditorStyles.miniLabel); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUI.GetPropertyHeight(property); + } + } +} diff --git a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta new file mode 100644 index 0000000..1cb1250 --- /dev/null +++ b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27821afc81c4d064d8348fbeb00c0ce8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver.meta b/Assets/Mirror/Editor/Weaver.meta new file mode 100644 index 0000000..ed8a67a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9f8e6274119b4ce29e498cfb8aca8a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs new file mode 100644 index 0000000..08b43f5 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Mirror.Tests")] diff --git a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta new file mode 100644 index 0000000..f31bae2 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 929924d95663264478d4238d4910d22e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Empty.meta b/Assets/Mirror/Editor/Weaver/Empty.meta new file mode 100644 index 0000000..71a3491 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 30fc290f2ff9c29498f54f63de12ca6f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs b/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs new file mode 100644 index 0000000..a88144a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs @@ -0,0 +1 @@ +// Removed Oct 1 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs.meta new file mode 100644 index 0000000..3fcfa0c --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd67b3f7c2d66074a9bc7a23787e2ffb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs b/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs new file mode 100644 index 0000000..b38f171 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs @@ -0,0 +1 @@ +// removed Oct 5 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs.meta new file mode 100644 index 0000000..d7b6208 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e25c00c88fc134f6ea7ab00ae4db8083 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Empty/Program.cs b/Assets/Mirror/Editor/Weaver/Empty/Program.cs new file mode 100644 index 0000000..a214b81 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/Program.cs @@ -0,0 +1 @@ +// Removed 05/09/20 diff --git a/Assets/Mirror/Editor/Weaver/Empty/Program.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/Program.cs.meta new file mode 100644 index 0000000..bde63d2 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/Program.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0152994c9591626408fcfec96fcc7933 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs b/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs new file mode 100644 index 0000000..a88144a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs @@ -0,0 +1 @@ +// Removed Oct 1 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs.meta new file mode 100644 index 0000000..8ca8566 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29e4a45f69822462ab0b15adda962a29 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs b/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs new file mode 100644 index 0000000..2fdbc52 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs @@ -0,0 +1 @@ +// removed 2020-09 diff --git a/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs.meta new file mode 100644 index 0000000..2a2b518 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5d8b25543a624384944b599e5a832a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs b/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs new file mode 100644 index 0000000..a88144a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs @@ -0,0 +1 @@ +// Removed Oct 1 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs.meta new file mode 100644 index 0000000..16b8097 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f3445268e45d437fac325837aff3246 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint.meta b/Assets/Mirror/Editor/Weaver/EntryPoint.meta new file mode 100644 index 0000000..54b718a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 251338e67afb4cefa38da924f8c50a6e +timeCreated: 1628851818 diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs new file mode 100644 index 0000000..01ffff0 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs @@ -0,0 +1,189 @@ +// for Unity 2020+ we use ILPostProcessor. +// only automatically invoke it for older versions. +#if !UNITY_2020_1_OR_NEWER +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Mono.CecilX; +using UnityEditor; +using UnityEditor.Compilation; +using UnityEngine; +using UnityAssembly = UnityEditor.Compilation.Assembly; + +namespace Mirror.Weaver +{ + public static class CompilationFinishedHook + { + // needs to be the same as Weaver.MirrorAssemblyName! + const string MirrorRuntimeAssemblyName = "Mirror"; + const string MirrorWeaverAssemblyName = "Mirror.Weaver"; + + // global weaver define so that tests can use it + internal static Weaver weaver; + + // delegate for subscription to Weaver warning messages + public static Action OnWeaverWarning; + // delete for subscription to Weaver error messages + public static Action OnWeaverError; + + // controls weather Weaver errors are reported direct to the Unity console (tests enable this) + public static bool UnityLogEnabled = true; + + [InitializeOnLoadMethod] + public static void OnInitializeOnLoad() + { + CompilationPipeline.assemblyCompilationFinished += OnCompilationFinished; + + // We only need to run this once per session + // after that, all assemblies will be weaved by the event + if (!SessionState.GetBool("MIRROR_WEAVED", false)) + { + // reset session flag + SessionState.SetBool("MIRROR_WEAVED", true); + SessionState.SetBool("MIRROR_WEAVE_SUCCESS", true); + + WeaveExistingAssemblies(); + } + } + + public static void WeaveExistingAssemblies() + { + foreach (UnityAssembly assembly in CompilationPipeline.GetAssemblies()) + { + if (File.Exists(assembly.outputPath)) + { + OnCompilationFinished(assembly.outputPath, new CompilerMessage[0]); + } + } + +#if UNITY_2019_3_OR_NEWER + EditorUtility.RequestScriptReload(); +#else + UnityEditorInternal.InternalEditorUtility.RequestScriptReload(); +#endif + } + + static Assembly FindCompilationPipelineAssembly(string assemblyName) => + CompilationPipeline.GetAssemblies().First(assembly => assembly.name == assemblyName); + + static bool CompilerMessagesContainError(CompilerMessage[] messages) => + messages.Any(msg => msg.type == CompilerMessageType.Error); + + public static void OnCompilationFinished(string assemblyPath, CompilerMessage[] messages) + { + // Do nothing if there were compile errors on the target + if (CompilerMessagesContainError(messages)) + { + Debug.Log("Weaver: stop because compile errors on target"); + return; + } + + // Should not run on the editor only assemblies + if (assemblyPath.Contains("-Editor") || assemblyPath.Contains(".Editor")) + { + return; + } + + // don't weave mirror files + string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); + if (assemblyName == MirrorRuntimeAssemblyName || assemblyName == MirrorWeaverAssemblyName) + { + return; + } + + // find Mirror.dll + Assembly mirrorAssembly = FindCompilationPipelineAssembly(MirrorRuntimeAssemblyName); + if (mirrorAssembly == null) + { + Debug.LogError("Failed to find Mirror runtime assembly"); + return; + } + + string mirrorRuntimeDll = mirrorAssembly.outputPath; + if (!File.Exists(mirrorRuntimeDll)) + { + // this is normal, it happens with any assembly that is built before mirror + // such as unity packages or your own assemblies + // those don't need to be weaved + // if any assembly depends on mirror, then it will be built after + return; + } + + // find UnityEngine.CoreModule.dll + string unityEngineCoreModuleDLL = UnityEditorInternal.InternalEditorUtility.GetEngineCoreModuleAssemblyPath(); + if (string.IsNullOrEmpty(unityEngineCoreModuleDLL)) + { + Debug.LogError("Failed to find UnityEngine assembly"); + return; + } + + HashSet dependencyPaths = GetDependencyPaths(assemblyPath); + dependencyPaths.Add(Path.GetDirectoryName(mirrorRuntimeDll)); + dependencyPaths.Add(Path.GetDirectoryName(unityEngineCoreModuleDLL)); + + if (!WeaveFromFile(assemblyPath, dependencyPaths.ToArray())) + { + // Set false...will be checked in \Editor\EnterPlayModeSettingsCheck.CheckSuccessfulWeave() + SessionState.SetBool("MIRROR_WEAVE_SUCCESS", false); + if (UnityLogEnabled) Debug.LogError("Weaving failed for: " + assemblyPath); + } + } + + static HashSet GetDependencyPaths(string assemblyPath) + { + // build directory list for later asm/symbol resolving using CompilationPipeline refs + HashSet dependencyPaths = new HashSet + { + Path.GetDirectoryName(assemblyPath) + }; + foreach (Assembly assembly in CompilationPipeline.GetAssemblies()) + { + if (assembly.outputPath == assemblyPath) + { + foreach (string reference in assembly.compiledAssemblyReferences) + { + dependencyPaths.Add(Path.GetDirectoryName(reference)); + } + } + } + + return dependencyPaths; + } + // helper function to invoke Weaver with an AssemblyDefinition from a + // file path, with dependencies added. + static bool WeaveFromFile(string assemblyPath, string[] dependencies) + { + // resolve assembly from stream + using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver()) + using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters{ ReadWrite = true, ReadSymbols = true, AssemblyResolver = asmResolver })) + { + // add this assembly's path and unity's assembly path + asmResolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath)); + asmResolver.AddSearchDirectory(Helpers.UnityEngineDllDirectoryName()); + + // add dependencies + if (dependencies != null) + { + foreach (string path in dependencies) + { + asmResolver.AddSearchDirectory(path); + } + } + + // create weaver with logger + weaver = new Weaver(new CompilationFinishedLogger()); + if (weaver.Weave(assembly, asmResolver, out bool modified)) + { + // write changes to file if modified + if (modified) + assembly.Write(new WriterParameters{WriteSymbols = true}); + + return true; + } + return false; + } + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs.meta new file mode 100644 index 0000000..004ab69 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de2aeb2e8068f421a9a1febe408f7051 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs new file mode 100644 index 0000000..7f782ee --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs @@ -0,0 +1,31 @@ +// logger for compilation finished hook. +// where we need a callback and Debug.Log. +// for Unity 2020+ we use ILPostProcessor. +#if !UNITY_2020_1_OR_NEWER +using Mono.CecilX; +using UnityEngine; + +namespace Mirror.Weaver +{ + public class CompilationFinishedLogger : Logger + { + public void Warning(string message) => Warning(message, null); + public void Warning(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + + if (CompilationFinishedHook.UnityLogEnabled) Debug.LogWarning(message); + CompilationFinishedHook.OnWeaverWarning?.Invoke(message); + } + + public void Error(string message) => Error(message, null); + public void Error(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + + if (CompilationFinishedHook.UnityLogEnabled) Debug.LogError(message); + CompilationFinishedHook.OnWeaverError?.Invoke(message); + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs.meta new file mode 100644 index 0000000..cb37fcb --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 47026732f0fa475c94bd1dd41f1de559 +timeCreated: 1629379868 diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs new file mode 100644 index 0000000..48b6d6b --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs @@ -0,0 +1,44 @@ +#if !UNITY_2020_1_OR_NEWER +// make sure we weaved successfully when entering play mode. +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + public class EnterPlayModeSettingsCheck : MonoBehaviour + { + [InitializeOnLoadMethod] + static void OnInitializeOnLoad() + { + // Hook this event to see if we have a good weave every time + // user attempts to enter play mode or tries to do a build + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + } + + static void OnPlayModeStateChanged(PlayModeStateChange state) + { + // Per Unity docs, this fires "when exiting edit mode before the Editor is in play mode". + // This doesn't fire when closing the editor. + if (state == PlayModeStateChange.ExitingEditMode) + { + // Check if last weave result was successful + if (!SessionState.GetBool("MIRROR_WEAVE_SUCCESS", false)) + { + // Last weave result was a failure...try to weave again + // Faults will show in the console that may have been cleared by "Clear on Play" + SessionState.SetBool("MIRROR_WEAVE_SUCCESS", true); + Weaver.CompilationFinishedHook.WeaveExistingAssemblies(); + + // Did that clear things up for us? + if (!SessionState.GetBool("MIRROR_WEAVE_SUCCESS", false)) + { + // Nope, still failed, and console has the issues logged + Debug.LogError("Can't enter play mode until weaver issues are resolved."); + EditorApplication.isPlaying = false; + } + } + } + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs.meta new file mode 100644 index 0000000..7c86b2e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b73d0f106ba84aa983baa5142b08a0a9 +timeCreated: 1628851346 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor.meta new file mode 100644 index 0000000..d1fa101 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 09082db63d1d48d9ab91320165c1b684 +timeCreated: 1628859005 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs new file mode 100644 index 0000000..e4d9de2 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs @@ -0,0 +1,31 @@ +// tests use WeaveAssembler, which uses AssemblyBuilder to Build(). +// afterwards ILPostProcessor weaves the build. +// this works on windows, but build() does not run ILPP on mac atm. +// we need to manually invoke ILPP with an assembly from file. +// +// this is in Weaver folder becuase CompilationPipeline can only be accessed +// from assemblies with the name "Unity.*.CodeGen" +using System.IO; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace Mirror.Weaver +{ + public class CompiledAssemblyFromFile : ICompiledAssembly + { + readonly string assemblyPath; + + public string Name => Path.GetFileNameWithoutExtension(assemblyPath); + public string[] References { get; set; } + public string[] Defines { get; set; } + public InMemoryAssembly InMemoryAssembly { get; } + + public CompiledAssemblyFromFile(string assemblyPath) + { + this.assemblyPath = assemblyPath; + byte[] peData = File.ReadAllBytes(assemblyPath); + string pdbFileName = Path.GetFileNameWithoutExtension(assemblyPath) + ".pdb"; + byte[] pdbData = File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(assemblyPath), pdbFileName)); + InMemoryAssembly = new InMemoryAssembly(peData, pdbData); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs.meta new file mode 100644 index 0000000..08a71c0 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9009d1db4ed44f6694a92bf8ad7738e9 +timeCreated: 1630129423 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs new file mode 100644 index 0000000..aeb2265 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs @@ -0,0 +1,167 @@ +// based on paul's resolver from +// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split +// +// an assembly resolver's job is to open an assembly in case we want to resolve +// a type from it. +// +// for example, while weaving MyGame.dll: if we want to resolve ArraySegment, +// then we need to open and resolve from another assembly (CoreLib). +// +// using DefaultAssemblyResolver with ILPostProcessor throws Exceptions in +// WeaverTypes.cs when resolving anything, for example: +// ArraySegment in Mirror.Tests.Dll. +// +// we need a custom resolver for ILPostProcessor. +#if UNITY_2020_1_OR_NEWER +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using Mono.CecilX; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace Mirror.Weaver +{ + class ILPostProcessorAssemblyResolver : IAssemblyResolver + { + readonly string[] assemblyReferences; + readonly Dictionary assemblyCache = + new Dictionary(); + readonly ICompiledAssembly compiledAssembly; + AssemblyDefinition selfAssembly; + + Logger Log; + + public ILPostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly, Logger Log) + { + this.compiledAssembly = compiledAssembly; + assemblyReferences = compiledAssembly.References; + this.Log = Log; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + // Cleanup + } + + public AssemblyDefinition Resolve(AssemblyNameReference name) => + Resolve(name, new ReaderParameters(ReadingMode.Deferred)); + + public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) + { + lock (assemblyCache) + { + if (name.Name == compiledAssembly.Name) + return selfAssembly; + + string fileName = FindFile(name); + if (fileName == null) + { + // returning null will throw exceptions in our weaver where. + // let's make it obvious why we returned null for easier debugging. + // NOTE: if this fails for "System.Private.CoreLib": + // ILPostProcessorReflectionImporter fixes it! + Log.Warning($"ILPostProcessorAssemblyResolver.Resolve: Failed to find file for {name}"); + return null; + } + + DateTime lastWriteTime = File.GetLastWriteTime(fileName); + + string cacheKey = fileName + lastWriteTime; + + if (assemblyCache.TryGetValue(cacheKey, out AssemblyDefinition result)) + return result; + + parameters.AssemblyResolver = this; + + MemoryStream ms = MemoryStreamFor(fileName); + + string pdb = fileName + ".pdb"; + if (File.Exists(pdb)) + parameters.SymbolStream = MemoryStreamFor(pdb); + + AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters); + assemblyCache.Add(cacheKey, assemblyDefinition); + return assemblyDefinition; + } + } + + // find assemblyname in assembly's references + string FindFile(AssemblyNameReference name) + { + string fileName = assemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == name.Name + ".dll"); + if (fileName != null) + return fileName; + + // perhaps the type comes from an exe instead + fileName = assemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == name.Name + ".exe"); + if (fileName != null) + return fileName; + + // Unfortunately the current ICompiledAssembly API only provides direct references. + // It is very much possible that a postprocessor ends up investigating a type in a directly + // referenced assembly, that contains a field that is not in a directly referenced assembly. + // if we don't do anything special for that situation, it will fail to resolve. We should fix this + // in the ILPostProcessing API. As a workaround, we rely on the fact here that the indirect references + // are always located next to direct references, so we search in all directories of direct references we + // got passed, and if we find the file in there, we resolve to it. + foreach (string parentDir in assemblyReferences.Select(Path.GetDirectoryName).Distinct()) + { + string candidate = Path.Combine(parentDir, name.Name + ".dll"); + if (File.Exists(candidate)) + return candidate; + } + + return null; + } + + // open file as MemoryStream + // attempts multiple times, not sure why.. + static MemoryStream MemoryStreamFor(string fileName) + { + return Retry(10, TimeSpan.FromSeconds(1), () => + { + byte[] byteArray; + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + byteArray = new byte[fs.Length]; + int readLength = fs.Read(byteArray, 0, (int)fs.Length); + if (readLength != fs.Length) + throw new InvalidOperationException("File read length is not full length of file."); + } + + return new MemoryStream(byteArray); + }); + } + + static MemoryStream Retry(int retryCount, TimeSpan waitTime, Func func) + { + try + { + return func(); + } + catch (IOException) + { + if (retryCount == 0) + throw; + Console.WriteLine($"Caught IO Exception, trying {retryCount} more times"); + Thread.Sleep(waitTime); + return Retry(retryCount - 1, waitTime, func); + } + } + + // if the CompiledAssembly's AssemblyDefinition is known, we can add it + public void SetAssemblyDefinitionForCompiledAssembly(AssemblyDefinition assemblyDefinition) + { + selfAssembly = assemblyDefinition; + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs.meta new file mode 100644 index 0000000..2c6e77e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0b3e94696e22440ead0b3a42411bbe14 +timeCreated: 1629693784 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs new file mode 100644 index 0000000..31d270d --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs @@ -0,0 +1,53 @@ +// helper function to use ILPostProcessor for an assembly from file. +// we keep this in Weaver folder because we can access CompilationPipleine here. +// in tests folder we can't, unless we rename to "Unity.*.CodeGen", +// but then tests wouldn't be weaved anymore. +#if UNITY_2020_1_OR_NEWER +using System; +using System.IO; +using Unity.CompilationPipeline.Common.Diagnostics; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace Mirror.Weaver +{ + public static class ILPostProcessorFromFile + { + // read, weave, write file via ILPostProcessor + public static void ILPostProcessFile(string assemblyPath, string[] references, Action OnWarning, Action OnError) + { + // we COULD Weave() with a test logger manually. + // but for test result consistency on all platforms, + // let's invoke the ILPostProcessor here too. + CompiledAssemblyFromFile assembly = new CompiledAssemblyFromFile(assemblyPath); + assembly.References = references; + + // create ILPP and check WillProcess like Unity would. + ILPostProcessorHook ilpp = new ILPostProcessorHook(); + if (ilpp.WillProcess(assembly)) + { + //Debug.Log("Will Process: " + assembly.Name); + + // process it like Unity would + ILPostProcessResult result = ilpp.Process(assembly); + + // handle the error messages like Unity would + foreach (DiagnosticMessage message in result.Diagnostics) + { + if (message.DiagnosticType == DiagnosticType.Warning) + { + OnWarning(message.MessageData); + } + else if (message.DiagnosticType == DiagnosticType.Error) + { + OnError(message.MessageData); + } + } + + // save the weaved assembly to file. + // some tests open it and check for certain IL code. + File.WriteAllBytes(assemblyPath, result.InMemoryAssembly.PeData); + } + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs.meta new file mode 100644 index 0000000..0fced88 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2a4b115486b74d27a9540f3c39ae2d46 +timeCreated: 1630152191 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs new file mode 100644 index 0000000..25ba6c0 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs @@ -0,0 +1,142 @@ +// hook via ILPostProcessor from Unity 2020+ +#if UNITY_2020_1_OR_NEWER +// Unity.CompilationPipeline reference is only resolved if assembly name is +// Unity.*.CodeGen: +// https://forum.unity.com/threads/how-does-unity-do-codegen-and-why-cant-i-do-it-myself.853867/#post-5646937 +using System.IO; +using System.Linq; +// to use Mono.CecilX here, we need to 'override references' in the +// Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX. +// otherwise we get a reflection exception with 'file not found: CecilX'. +using Mono.CecilX; +using Mono.CecilX.Cil; +using Unity.CompilationPipeline.Common.ILPostProcessing; +// IMPORTANT: 'using UnityEngine' does not work in here. +// Unity gives "(0,0): error System.Security.SecurityException: ECall methods must be packaged into a system module." +//using UnityEngine; + +namespace Mirror.Weaver +{ + public class ILPostProcessorHook : ILPostProcessor + { + // from CompilationFinishedHook + const string MirrorRuntimeAssemblyName = "Mirror"; + + // ILPostProcessor is invoked by Unity. + // we can not tell it to ignore certain assemblies before processing. + // add a 'ignore' define for convenience. + // => WeaverTests/WeaverAssembler need it to avoid Unity running it + public const string IgnoreDefine = "ILPP_IGNORE"; + + // we can't use Debug.Log in ILPP, so we need a custom logger + ILPostProcessorLogger Log = new ILPostProcessorLogger(); + + // ??? + public override ILPostProcessor GetInstance() => this; + + // check if assembly has the 'ignore' define + static bool HasDefine(ICompiledAssembly assembly, string define) => + assembly.Defines != null && + assembly.Defines.Contains(define); + + // process Mirror, or anything that references Mirror + public override bool WillProcess(ICompiledAssembly compiledAssembly) + { + // compiledAssembly.References are file paths: + // Library/Bee/artifacts/200b0aE.dag/Mirror.CompilerSymbols.dll + // Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll + // /Applications/Unity/Hub/Editor/2021.2.0b6_apple_silicon/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll + // + // log them to see: + // foreach (string reference in compiledAssembly.References) + // LogDiagnostics($"{compiledAssembly.Name} references {reference}"); + bool relevant = compiledAssembly.Name == MirrorRuntimeAssemblyName || + compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == MirrorRuntimeAssemblyName); + bool ignore = HasDefine(compiledAssembly, IgnoreDefine); + return relevant && !ignore; + } + + public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) + { + //Log.Warning($"Processing {compiledAssembly.Name}"); + + // load the InMemoryAssembly peData into a MemoryStream + byte[] peData = compiledAssembly.InMemoryAssembly.PeData; + //LogDiagnostics($" peData.Length={peData.Length} bytes"); + using (MemoryStream stream = new MemoryStream(peData)) + using (ILPostProcessorAssemblyResolver asmResolver = new ILPostProcessorAssemblyResolver(compiledAssembly, Log)) + { + // we need to load symbols. otherwise we get: + // "(0,0): error Mono.CecilX.Cil.SymbolsNotFoundException: No symbol found for file: " + using (MemoryStream symbols = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData)) + { + ReaderParameters readerParameters = new ReaderParameters{ + SymbolStream = symbols, + ReadWrite = true, + ReadSymbols = true, + AssemblyResolver = asmResolver, + // custom reflection importer to fix System.Private.CoreLib + // not being found in custom assembly resolver above. + ReflectionImporterProvider = new ILPostProcessorReflectionImporterProvider() + }; + using (AssemblyDefinition asmDef = AssemblyDefinition.ReadAssembly(stream, readerParameters)) + { + // resolving a Mirror.dll type like NetworkServer while + // weaving Mirror.dll does not work. it throws a + // NullReferenceException in WeaverTypes.ctor + // when Resolve() is called on the first Mirror type. + // need to add the AssemblyDefinition itself to use. + asmResolver.SetAssemblyDefinitionForCompiledAssembly(asmDef); + + // weave this assembly. + Weaver weaver = new Weaver(Log); + if (weaver.Weave(asmDef, asmResolver, out bool modified)) + { + //Log.Warning($"Weaving succeeded for: {compiledAssembly.Name}"); + + // write if modified + if (modified) + { + // when weaving Mirror.dll with ILPostProcessor, + // Weave() -> WeaverTypes -> resolving the first + // type in Mirror.dll adds a reference to + // Mirror.dll even though we are in Mirror.dll. + // -> this would throw an exception: + // "Mirror references itself" and not compile + // -> need to detect and fix manually here + if (asmDef.MainModule.AssemblyReferences.Any(r => r.Name == asmDef.Name.Name)) + { + asmDef.MainModule.AssemblyReferences.Remove(asmDef.MainModule.AssemblyReferences.First(r => r.Name == asmDef.Name.Name)); + //Log.Warning($"fixed self referencing Assembly: {asmDef.Name.Name}"); + } + + MemoryStream peOut = new MemoryStream(); + MemoryStream pdbOut = new MemoryStream(); + WriterParameters writerParameters = new WriterParameters + { + SymbolWriterProvider = new PortablePdbWriterProvider(), + SymbolStream = pdbOut, + WriteSymbols = true + }; + + asmDef.Write(peOut, writerParameters); + + InMemoryAssembly inMemory = new InMemoryAssembly(peOut.ToArray(), pdbOut.ToArray()); + return new ILPostProcessResult(inMemory, Log.Logs); + } + } + // if anything during Weave() fails, we log an error. + // don't need to indicate 'weaving failed' again. + // in fact, this would break tests only expecting certain errors. + //else Log.Error($"Weaving failed for: {compiledAssembly.Name}"); + } + } + } + + // always return an ILPostProcessResult with Logs. + // otherwise we won't see Logs if weaving failed. + return new ILPostProcessResult(compiledAssembly.InMemoryAssembly, Log.Logs); + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs.meta new file mode 100644 index 0000000..1930bd1 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5f113eb695b348b5b28cd85358c8959a +timeCreated: 1628859074 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs new file mode 100644 index 0000000..2c070cc --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using Mono.CecilX; +using Unity.CompilationPipeline.Common.Diagnostics; + +namespace Mirror.Weaver +{ + public class ILPostProcessorLogger : Logger + { + // can't Debug.Log in ILPostProcessor. need to add to this list. + internal List Logs = new List(); + + void Add(string message, DiagnosticType logType) + { + Logs.Add(new DiagnosticMessage + { + // TODO add file etc. for double click opening later? + DiagnosticType = logType, // doesn't have .Log + File = null, + Line = 0, + Column = 0, + MessageData = message + }); + } + + public void LogDiagnostics(string message, DiagnosticType logType = DiagnosticType.Warning) + { + // DiagnosticMessage can't display \n for some reason. + // it just cuts it off and we don't see any stack trace. + // so let's replace all line breaks so we get the stack trace. + // (Unity 2021.2.0b6 apple silicon) + //message = message.Replace("\n", "/"); + + // lets break it into several messages instead so it's easier readable + string[] lines = message.Split('\n'); + + // if it's just one line, simply log it + if (lines.Length == 1) + { + // tests assume exact message log. + // don't include 'Weaver: ...' or similar. + Add($"{message}", logType); + } + // for multiple lines, log each line separately with start/end indicators + else + { + // first line with Weaver: ... first + Add("----------------------------------------------", logType); + foreach (string line in lines) Add(line, logType); + Add("----------------------------------------------", logType); + } + } + + public void Warning(string message) => Warning(message, null); + public void Warning(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + LogDiagnostics(message, DiagnosticType.Warning); + } + + public void Error(string message) => Error(message, null); + public void Error(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + LogDiagnostics(message, DiagnosticType.Error); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs.meta new file mode 100644 index 0000000..b943801 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7b56e7826664e34a415e4b70d958f2a +timeCreated: 1629533154 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs new file mode 100644 index 0000000..e15c103 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs @@ -0,0 +1,36 @@ +// based on paul's resolver from +// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split +// +// ILPostProcessorAssemblyRESOLVER does not find the .dll file for: +// "System.Private.CoreLib" +// we need this custom reflection importer to fix that. +using System.Linq; +using System.Reflection; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + internal class ILPostProcessorReflectionImporter : DefaultReflectionImporter + { + const string SystemPrivateCoreLib = "System.Private.CoreLib"; + readonly AssemblyNameReference fixedCoreLib; + + public ILPostProcessorReflectionImporter(ModuleDefinition module) : base(module) + { + // find the correct library for "System.Private.CoreLib". + // either mscorlib or netstandard. + // defaults to System.Private.CoreLib if not found. + fixedCoreLib = module.AssemblyReferences.FirstOrDefault(a => a.Name == "mscorlib" || a.Name == "netstandard" || a.Name == SystemPrivateCoreLib); + } + + public override AssemblyNameReference ImportReference(AssemblyName name) + { + // System.Private.CoreLib? + if (name.Name == SystemPrivateCoreLib && fixedCoreLib != null) + return fixedCoreLib; + + // otherwise import as usual + return base.ImportReference(name); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs.meta new file mode 100644 index 0000000..ebeb48e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6403a7e3b3ae4e009ae282f111d266e0 +timeCreated: 1629709256 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs new file mode 100644 index 0000000..7358e1b --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs @@ -0,0 +1,16 @@ +// based on paul's resolver from +// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split +// +// ILPostProcessorAssemblyRESOLVER does not find the .dll file for: +// "System.Private.CoreLib" +// we need this custom reflection importer to fix that. +using Mono.CecilX; + +namespace Mirror.Weaver +{ + internal class ILPostProcessorReflectionImporterProvider : IReflectionImporterProvider + { + public IReflectionImporter GetReflectionImporter(ModuleDefinition module) => + new ILPostProcessorReflectionImporter(module); + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs.meta new file mode 100644 index 0000000..0ce258f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a1003b568bad4e69b961c4c81d5afd96 +timeCreated: 1629709223 diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs b/Assets/Mirror/Editor/Weaver/Extensions.cs new file mode 100644 index 0000000..f04048e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Extensions.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + public static class Extensions + { + public static bool Is(this TypeReference td, Type t) + { + if (t.IsGenericType) + { + return td.GetElementType().FullName == t.FullName; + } + return td.FullName == t.FullName; + } + + public static bool Is(this TypeReference td) => Is(td, typeof(T)); + + public static bool IsDerivedFrom(this TypeReference tr) => IsDerivedFrom(tr, typeof(T)); + + public static bool IsDerivedFrom(this TypeReference tr, Type baseClass) + { + TypeDefinition td = tr.Resolve(); + if (!td.IsClass) + return false; + + // are ANY parent classes of baseClass? + TypeReference parent = td.BaseType; + + if (parent == null) + return false; + + if (parent.Is(baseClass)) + return true; + + if (parent.CanBeResolved()) + return IsDerivedFrom(parent.Resolve(), baseClass); + + return false; + } + + public static TypeReference GetEnumUnderlyingType(this TypeDefinition td) + { + foreach (FieldDefinition field in td.Fields) + { + if (!field.IsStatic) + return field.FieldType; + } + throw new ArgumentException($"Invalid enum {td.FullName}"); + } + + public static bool ImplementsInterface(this TypeDefinition td) + { + TypeDefinition typedef = td; + + while (typedef != null) + { + if (typedef.Interfaces.Any(iface => iface.InterfaceType.Is())) + return true; + + try + { + TypeReference parent = typedef.BaseType; + typedef = parent?.Resolve(); + } + catch (AssemblyResolutionException) + { + // this can happen for plugins. + //Console.WriteLine("AssemblyResolutionException: "+ ex.ToString()); + break; + } + } + + return false; + } + + public static bool IsMultidimensionalArray(this TypeReference tr) => + tr is ArrayType arrayType && arrayType.Rank > 1; + + // Does type use netId as backing field + public static bool IsNetworkIdentityField(this TypeReference tr) => + tr.Is() || + tr.Is() || + tr.IsDerivedFrom(); + + public static bool CanBeResolved(this TypeReference parent) + { + while (parent != null) + { + if (parent.Scope.Name == "Windows") + { + return false; + } + + if (parent.Scope.Name == "mscorlib") + { + TypeDefinition resolved = parent.Resolve(); + return resolved != null; + } + + try + { + parent = parent.Resolve().BaseType; + } + catch + { + return false; + } + } + return true; + } + + // Makes T => Variable and imports function + public static MethodReference MakeGeneric(this MethodReference generic, ModuleDefinition module, TypeReference variableReference) + { + GenericInstanceMethod instance = new GenericInstanceMethod(generic); + instance.GenericArguments.Add(variableReference); + + MethodReference readFunc = module.ImportReference(instance); + return readFunc; + } + + // Given a method of a generic class such as ArraySegment`T.get_Count, + // and a generic instance such as ArraySegment`int + // Creates a reference to the specialized method ArraySegment`int`.get_Count + // Note that calling ArraySegment`T.get_Count directly gives an invalid IL error + public static MethodReference MakeHostInstanceGeneric(this MethodReference self, ModuleDefinition module, GenericInstanceType instanceType) + { + MethodReference reference = new MethodReference(self.Name, self.ReturnType, instanceType) + { + CallingConvention = self.CallingConvention, + HasThis = self.HasThis, + ExplicitThis = self.ExplicitThis + }; + + foreach (ParameterDefinition parameter in self.Parameters) + reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); + + foreach (GenericParameter generic_parameter in self.GenericParameters) + reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference)); + + return module.ImportReference(reference); + } + + // Given a field of a generic class such as Writer.write, + // and a generic instance such as ArraySegment`int + // Creates a reference to the specialized method ArraySegment`int`.get_Count + // Note that calling ArraySegment`T.get_Count directly gives an invalid IL error + public static FieldReference SpecializeField(this FieldReference self, ModuleDefinition module, GenericInstanceType instanceType) + { + FieldReference reference = new FieldReference(self.Name, self.FieldType, instanceType); + return module.ImportReference(reference); + } + + public static CustomAttribute GetCustomAttribute(this ICustomAttributeProvider method) + { + return method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Is()); + } + + public static bool HasCustomAttribute(this ICustomAttributeProvider attributeProvider) + { + return attributeProvider.CustomAttributes.Any(attr => attr.AttributeType.Is()); + } + + public static T GetField(this CustomAttribute ca, string field, T defaultValue) + { + foreach (CustomAttributeNamedArgument customField in ca.Fields) + if (customField.Name == field) + return (T)customField.Argument.Value; + return defaultValue; + } + + public static MethodDefinition GetMethod(this TypeDefinition td, string methodName) + { + return td.Methods.FirstOrDefault(method => method.Name == methodName); + } + + public static List GetMethods(this TypeDefinition td, string methodName) + { + return td.Methods.Where(method => method.Name == methodName).ToList(); + } + + public static MethodDefinition GetMethodInBaseType(this TypeDefinition td, string methodName) + { + TypeDefinition typedef = td; + while (typedef != null) + { + foreach (MethodDefinition md in typedef.Methods) + { + if (md.Name == methodName) + return md; + } + + try + { + TypeReference parent = typedef.BaseType; + typedef = parent?.Resolve(); + } + catch (AssemblyResolutionException) + { + // this can happen for plugins. + break; + } + } + + return null; + } + + // Finds public fields in type and base type + public static IEnumerable FindAllPublicFields(this TypeReference variable) + { + return FindAllPublicFields(variable.Resolve()); + } + + // Finds public fields in type and base type + public static IEnumerable FindAllPublicFields(this TypeDefinition typeDefinition) + { + while (typeDefinition != null) + { + foreach (FieldDefinition field in typeDefinition.Fields) + { + if (field.IsStatic || field.IsPrivate) + continue; + + if (field.IsNotSerialized) + continue; + + yield return field; + } + + try + { + typeDefinition = typeDefinition.BaseType?.Resolve(); + } + catch (AssemblyResolutionException) + { + break; + } + } + } + + public static bool ContainsClass(this ModuleDefinition module, string nameSpace, string className) => + module.GetTypes().Any(td => td.Namespace == nameSpace && + td.Name == className); + + + public static AssemblyNameReference FindReference(this ModuleDefinition module, string referenceName) + { + foreach (AssemblyNameReference reference in module.AssemblyReferences) + { + if (reference.Name == referenceName) + return reference; + } + return null; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs.meta b/Assets/Mirror/Editor/Weaver/Extensions.cs.meta new file mode 100644 index 0000000..a5b8aa4 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Extensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 562a5cf0254cc45738e9aa549a7100b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Helpers.cs b/Assets/Mirror/Editor/Weaver/Helpers.cs new file mode 100644 index 0000000..56b7385 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Helpers.cs @@ -0,0 +1,26 @@ +using System.IO; +using System.Linq; +using System.Reflection; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + static class Helpers + { + // This code is taken from SerializationWeaver + public static string UnityEngineDllDirectoryName() + { + string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); + return directoryName?.Replace(@"file:\", ""); + } + + public static bool IsEditorAssembly(AssemblyDefinition currentAssembly) + { + // we want to add the [InitializeOnLoad] attribute if it's available + // -> usually either 'UnityEditor' or 'UnityEditor.CoreModule' + return currentAssembly.MainModule.AssemblyReferences.Any(assemblyReference => + assemblyReference.Name.StartsWith(nameof(UnityEditor)) + ); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Helpers.cs.meta b/Assets/Mirror/Editor/Weaver/Helpers.cs.meta new file mode 100644 index 0000000..f49ae98 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Helpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c4ed76daf48547c5abb7c58f8d20886 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Logger.cs b/Assets/Mirror/Editor/Weaver/Logger.cs new file mode 100644 index 0000000..8be978f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Logger.cs @@ -0,0 +1,13 @@ +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public interface Logger + { + void Warning(string message); + void Warning(string message, MemberReference mr); + void Error(string message); + void Error(string message, MemberReference mr); + } +} diff --git a/Assets/Mirror/Editor/Weaver/Logger.cs.meta b/Assets/Mirror/Editor/Weaver/Logger.cs.meta new file mode 100644 index 0000000..ed584d5 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Logger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a21c60c40a4c4d679c2b71a7c40882e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors.meta b/Assets/Mirror/Editor/Weaver/Processors.meta new file mode 100644 index 0000000..f3a01c1 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e538d627280d2471b8c72fdea822ca49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs new file mode 100644 index 0000000..75ed3b6 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs @@ -0,0 +1,125 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + // Processes [Command] methods in NetworkBehaviour + public static class CommandProcessor + { + /* + // generates code like: + public void CmdThrust(float thrusting, int spin) + { + NetworkWriter networkWriter = new NetworkWriter(); + networkWriter.Write(thrusting); + networkWriter.WritePackedUInt32((uint)spin); + base.SendCommandInternal(cmdName, networkWriter, cmdName); + } + + public void CallCmdThrust(float thrusting, int spin) + { + // whatever the user was doing before + } + + Originally HLAPI put the send message code inside the Call function + and then proceeded to replace every call to CmdTrust with CallCmdTrust + + This method moves all the user's code into the "CallCmd" method + and replaces the body of the original method with the send message code. + This way we do not need to modify the code anywhere else, and this works + correctly in dependent assemblies + */ + public static MethodDefinition ProcessCommandCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute commandAttr, ref bool WeavingFailed) + { + MethodDefinition cmd = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed); + + ILProcessor worker = md.Body.GetILProcessor(); + + NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes); + + // NetworkWriter writer = new NetworkWriter(); + NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes); + + // write all the arguments that the user passed to the Cmd call + if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.Command, ref WeavingFailed)) + return null; + + string cmdName = md.Name; + int channel = commandAttr.GetField("channel", 0); + bool requiresAuthority = commandAttr.GetField("requiresAuthority", true); + + // invoke internal send and return + // load 'base.' to call the SendCommand function with + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldtoken, td); + // invokerClass + worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference); + worker.Emit(OpCodes.Ldstr, cmdName); + // writer + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ldc_I4, channel); + // requiresAuthority ? 1 : 0 + worker.Emit(requiresAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + worker.Emit(OpCodes.Call, weaverTypes.sendCommandInternal); + + NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes); + + worker.Emit(OpCodes.Ret); + return cmd; + } + + /* + // generates code like: + protected static void InvokeCmdCmdThrust(NetworkBehaviour obj, NetworkReader reader, NetworkConnection senderConnection) + { + if (!NetworkServer.active) + { + return; + } + ((ShipControl)obj).CmdThrust(reader.ReadSingle(), (int)reader.ReadPackedUInt32()); + } + */ + public static MethodDefinition ProcessCommandInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition method, MethodDefinition cmdCallFunc, ref bool WeavingFailed) + { + MethodDefinition cmd = new MethodDefinition(Weaver.InvokeRpcPrefix + method.Name, + MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = cmd.Body.GetILProcessor(); + Instruction label = worker.Create(OpCodes.Nop); + + NetworkBehaviourProcessor.WriteServerActiveCheck(worker, weaverTypes, method.Name, label, "Command"); + + // setup for reader + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Castclass, td); + + if (!NetworkBehaviourProcessor.ReadArguments(method, readers, Log, worker, RemoteCallType.Command, ref WeavingFailed)) + return null; + + AddSenderConnection(method, worker); + + // invoke actual command function + worker.Emit(OpCodes.Callvirt, cmdCallFunc); + worker.Emit(OpCodes.Ret); + + NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, cmd.Parameters); + + td.Methods.Add(cmd); + return cmd; + } + + static void AddSenderConnection(MethodDefinition method, ILProcessor worker) + { + foreach (ParameterDefinition param in method.Parameters) + { + if (NetworkBehaviourProcessor.IsSenderConnection(param, RemoteCallType.Command)) + { + // NetworkConnection is 3nd arg (arg0 is "obj" not "this" because method is static) + // example: static void InvokeCmdCmdSendCommand(NetworkBehaviour obj, NetworkReader reader, NetworkConnection connection) + worker.Emit(OpCodes.Ldarg_2); + } + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta new file mode 100644 index 0000000..4596f69 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73f6c9cdbb9e54f65b3a0a35cc8e55c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs new file mode 100644 index 0000000..00aa68d --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs @@ -0,0 +1,130 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public static class MethodProcessor + { + const string RpcPrefix = "UserCode_"; + + // creates a method substitute + // For example, if we have this: + // public void CmdThrust(float thrusting, int spin) + // { + // xxxxx + // } + // + // it will substitute the method and move the code to a new method with a provided name + // for example: + // + // public void CmdTrust(float thrusting, int spin) + // { + // } + // + // public void (float thrusting, int spin) + // { + // xxxxx + // } + // + // Note that all the calls to the method remain untouched + // + // the original method definition loses all code + // this returns the newly created method with all the user provided code + public static MethodDefinition SubstituteMethod(Logger Log, TypeDefinition td, MethodDefinition md, ref bool WeavingFailed) + { + string newName = RpcPrefix + md.Name; + MethodDefinition cmd = new MethodDefinition(newName, md.Attributes, md.ReturnType); + + // force the substitute method to be protected. + // -> public would show in the Inspector for UnityEvents as + // User_CmdUsePotion() etc. but the user shouldn't use those. + // -> private would not allow inheriting classes to call it, see + // OverrideVirtualWithBaseCallsBothVirtualAndBase test. + // -> IL has no concept of 'protected', it's called IsFamily there. + cmd.IsPublic = false; + cmd.IsFamily = true; + + // add parameters + foreach (ParameterDefinition pd in md.Parameters) + { + cmd.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType)); + } + + // swap bodies + (cmd.Body, md.Body) = (md.Body, cmd.Body); + + // Move over all the debugging information + foreach (SequencePoint sequencePoint in md.DebugInformation.SequencePoints) + cmd.DebugInformation.SequencePoints.Add(sequencePoint); + md.DebugInformation.SequencePoints.Clear(); + + foreach (CustomDebugInformation customInfo in md.CustomDebugInformations) + cmd.CustomDebugInformations.Add(customInfo); + md.CustomDebugInformations.Clear(); + + (md.DebugInformation.Scope, cmd.DebugInformation.Scope) = (cmd.DebugInformation.Scope, md.DebugInformation.Scope); + + td.Methods.Add(cmd); + + FixRemoteCallToBaseMethod(Log, td, cmd, ref WeavingFailed); + return cmd; + } + + // Finds and fixes call to base methods within remote calls + //For example, changes `base.CmdDoSomething` to `base.CallCmdDoSomething` within `this.CallCmdDoSomething` + public static void FixRemoteCallToBaseMethod(Logger Log, TypeDefinition type, MethodDefinition method, ref bool WeavingFailed) + { + string callName = method.Name; + + // Cmd/rpc start with Weaver.RpcPrefix + // e.g. CallCmdDoSomething + if (!callName.StartsWith(RpcPrefix)) + return; + + // e.g. CmdDoSomething + string baseRemoteCallName = method.Name.Substring(RpcPrefix.Length); + + foreach (Instruction instruction in method.Body.Instructions) + { + // if call to base.CmdDoSomething within this.CallCmdDoSomething + if (IsCallToMethod(instruction, out MethodDefinition calledMethod) && + calledMethod.Name == baseRemoteCallName) + { + TypeDefinition baseType = type.BaseType.Resolve(); + MethodDefinition baseMethod = baseType.GetMethodInBaseType(callName); + + if (baseMethod == null) + { + Log.Error($"Could not find base method for {callName}", method); + WeavingFailed = true; + return; + } + + if (!baseMethod.IsVirtual) + { + Log.Error($"Could not find base method that was virtual {callName}", method); + WeavingFailed = true; + return; + } + + instruction.Operand = baseMethod; + } + } + } + + static bool IsCallToMethod(Instruction instruction, out MethodDefinition calledMethod) + { + if (instruction.OpCode == OpCodes.Call && + instruction.Operand is MethodDefinition method) + { + calledMethod = method; + return true; + } + else + { + calledMethod = null; + return false; + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta new file mode 100644 index 0000000..b40023d --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 661e1af528e3441f79e1552fb5ec4e0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs new file mode 100644 index 0000000..e88c5d6 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs @@ -0,0 +1,56 @@ +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // only shows warnings in case we use SyncVars etc. for MonoBehaviour. + static class MonoBehaviourProcessor + { + public static void Process(Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + ProcessSyncVars(Log, td, ref WeavingFailed); + ProcessMethods(Log, td, ref WeavingFailed); + } + + static void ProcessSyncVars(Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + // find syncvars + foreach (FieldDefinition fd in td.Fields) + { + if (fd.HasCustomAttribute()) + { + Log.Error($"SyncVar {fd.Name} must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); + WeavingFailed = true; + } + + if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType)) + { + Log.Error($"{fd.Name} is a SyncObject and must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); + WeavingFailed = true; + } + } + } + + static void ProcessMethods(Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + // find command and RPC functions + foreach (MethodDefinition md in td.Methods) + { + if (md.HasCustomAttribute()) + { + Log.Error($"Command {md.Name} must be declared inside a NetworkBehaviour", md); + WeavingFailed = true; + } + if (md.HasCustomAttribute()) + { + Log.Error($"ClientRpc {md.Name} must be declared inside a NetworkBehaviour", md); + WeavingFailed = true; + } + if (md.HasCustomAttribute()) + { + Log.Error($"TargetRpc {md.Name} must be declared inside a NetworkBehaviour", md); + WeavingFailed = true; + } + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta new file mode 100644 index 0000000..4eb8840 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35c16722912b64af894e4f6668f2e54c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs new file mode 100644 index 0000000..ac2ad61 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs @@ -0,0 +1,1201 @@ +using System.Collections.Generic; +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public enum RemoteCallType + { + Command, + ClientRpc, + TargetRpc + } + + // processes SyncVars, Cmds, Rpcs, etc. of NetworkBehaviours + class NetworkBehaviourProcessor + { + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + WeaverLists weaverLists; + SyncVarProcessor syncVarProcessor; + Writers writers; + Readers readers; + Logger Log; + + List syncVars = new List(); + List syncObjects = new List(); + // + Dictionary syncVarNetIds = new Dictionary(); + readonly List commands = new List(); + readonly List clientRpcs = new List(); + readonly List targetRpcs = new List(); + readonly List commandInvocationFuncs = new List(); + readonly List clientRpcInvocationFuncs = new List(); + readonly List targetRpcInvocationFuncs = new List(); + + readonly TypeDefinition netBehaviourSubclass; + + public struct CmdResult + { + public MethodDefinition method; + public bool requiresAuthority; + } + + public struct ClientRpcResult + { + public MethodDefinition method; + public bool includeOwner; + } + + public NetworkBehaviourProcessor(AssemblyDefinition assembly, WeaverTypes weaverTypes, WeaverLists weaverLists, Writers writers, Readers readers, Logger Log, TypeDefinition td) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.weaverLists = weaverLists; + this.writers = writers; + this.readers = readers; + this.Log = Log; + syncVarProcessor = new SyncVarProcessor(assembly, weaverTypes, weaverLists, Log); + netBehaviourSubclass = td; + } + + // return true if modified + public bool Process(ref bool WeavingFailed) + { + // only process once + if (WasProcessed(netBehaviourSubclass)) + { + return false; + } + + if (netBehaviourSubclass.HasGenericParameters) + { + Log.Error($"{netBehaviourSubclass.Name} cannot have generic parameters", netBehaviourSubclass); + WeavingFailed = true; + // originally Process returned true in every case, except if already processed. + // maybe return false here in the future. + return true; + } + MarkAsProcessed(netBehaviourSubclass); + + // deconstruct tuple and set fields + (syncVars, syncVarNetIds) = syncVarProcessor.ProcessSyncVars(netBehaviourSubclass, ref WeavingFailed); + + syncObjects = SyncObjectProcessor.FindSyncObjectsFields(writers, readers, Log, netBehaviourSubclass, ref WeavingFailed); + + ProcessMethods(ref WeavingFailed); + if (WeavingFailed) + { + // originally Process returned true in every case, except if already processed. + // maybe return false here in the future. + return true; + } + GenerateConstants(ref WeavingFailed); + + GenerateSerialization(ref WeavingFailed); + if (WeavingFailed) + { + // originally Process returned true in every case, except if already processed. + // maybe return false here in the future. + return true; + } + + GenerateDeSerialization(ref WeavingFailed); + return true; + } + + /* + generates code like: + if (!NetworkClient.active) + Debug.LogError((object) "Command function CmdRespawn called on server."); + + which is used in InvokeCmd, InvokeRpc, etc. + */ + public static void WriteClientActiveCheck(ILProcessor worker, WeaverTypes weaverTypes, string mdName, Instruction label, string errString) + { + // client active check + worker.Emit(OpCodes.Call, weaverTypes.NetworkClientGetActive); + worker.Emit(OpCodes.Brtrue, label); + + worker.Emit(OpCodes.Ldstr, errString + " " + mdName + " called on server."); + worker.Emit(OpCodes.Call, weaverTypes.logErrorReference); + worker.Emit(OpCodes.Ret); + worker.Append(label); + } + /* + generates code like: + if (!NetworkServer.active) + Debug.LogError((object) "Command CmdMsgWhisper called on client."); + */ + public static void WriteServerActiveCheck(ILProcessor worker, WeaverTypes weaverTypes, string mdName, Instruction label, string errString) + { + // server active check + worker.Emit(OpCodes.Call, weaverTypes.NetworkServerGetActive); + worker.Emit(OpCodes.Brtrue, label); + + worker.Emit(OpCodes.Ldstr, errString + " " + mdName + " called on client."); + worker.Emit(OpCodes.Call, weaverTypes.logErrorReference); + worker.Emit(OpCodes.Ret); + worker.Append(label); + } + + public static void WriteSetupLocals(ILProcessor worker, WeaverTypes weaverTypes) + { + worker.Body.InitLocals = true; + worker.Body.Variables.Add(new VariableDefinition(weaverTypes.Import())); + } + + public static void WriteCreateWriter(ILProcessor worker, WeaverTypes weaverTypes) + { + // create writer + worker.Emit(OpCodes.Call, weaverTypes.GetPooledWriterReference); + worker.Emit(OpCodes.Stloc_0); + } + + public static void WriteRecycleWriter(ILProcessor worker, WeaverTypes weaverTypes) + { + // NetworkWriterPool.Recycle(writer); + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Call, weaverTypes.RecycleWriterReference); + } + + public static bool WriteArguments(ILProcessor worker, Writers writers, Logger Log, MethodDefinition method, RemoteCallType callType, ref bool WeavingFailed) + { + // write each argument + // example result + /* + writer.WritePackedInt32(someNumber); + writer.WriteNetworkIdentity(someTarget); + */ + + bool skipFirst = callType == RemoteCallType.TargetRpc + && TargetRpcProcessor.HasNetworkConnectionParameter(method); + + // arg of calling function, arg 0 is "this" so start counting at 1 + int argNum = 1; + foreach (ParameterDefinition param in method.Parameters) + { + // NetworkConnection is not sent via the NetworkWriter so skip it here + // skip first for NetworkConnection in TargetRpc + if (argNum == 1 && skipFirst) + { + argNum += 1; + continue; + } + // skip SenderConnection in Command + if (IsSenderConnection(param, callType)) + { + argNum += 1; + continue; + } + + MethodReference writeFunc = writers.GetWriteFunc(param.ParameterType, ref WeavingFailed); + if (writeFunc == null) + { + Log.Error($"{method.Name} has invalid parameter {param}", method); + WeavingFailed = true; + return false; + } + + // use built-in writer func on writer object + // NetworkWriter object + worker.Emit(OpCodes.Ldloc_0); + // add argument to call + worker.Emit(OpCodes.Ldarg, argNum); + // call writer extension method + worker.Emit(OpCodes.Call, writeFunc); + argNum += 1; + } + return true; + } + + #region mark / check type as processed + public const string ProcessedFunctionName = "MirrorProcessed"; + + // by adding an empty MirrorProcessed() function + public static bool WasProcessed(TypeDefinition td) + { + return td.GetMethod(ProcessedFunctionName) != null; + } + + public void MarkAsProcessed(TypeDefinition td) + { + if (!WasProcessed(td)) + { + MethodDefinition versionMethod = new MethodDefinition(ProcessedFunctionName, MethodAttributes.Private, weaverTypes.Import(typeof(void))); + ILProcessor worker = versionMethod.Body.GetILProcessor(); + worker.Emit(OpCodes.Ret); + td.Methods.Add(versionMethod); + } + } + #endregion + + void GenerateConstants(ref bool WeavingFailed) + { + if (commands.Count == 0 && clientRpcs.Count == 0 && targetRpcs.Count == 0 && syncObjects.Count == 0) + return; + + // find static constructor + MethodDefinition cctor = netBehaviourSubclass.GetMethod(".cctor"); + bool cctorFound = cctor != null; + if (cctor != null) + { + // remove the return opcode from end of function. will add our own later. + if (cctor.Body.Instructions.Count != 0) + { + Instruction retInstr = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1]; + if (retInstr.OpCode == OpCodes.Ret) + { + cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1); + } + else + { + Log.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor); + WeavingFailed = true; + return; + } + } + } + else + { + // make one! + cctor = new MethodDefinition(".cctor", MethodAttributes.Private | + MethodAttributes.HideBySig | + MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName | + MethodAttributes.Static, + weaverTypes.Import(typeof(void))); + } + + // find instance constructor + MethodDefinition ctor = netBehaviourSubclass.GetMethod(".ctor"); + + if (ctor == null) + { + Log.Error($"{netBehaviourSubclass.Name} has invalid constructor", netBehaviourSubclass); + WeavingFailed = true; + return; + } + + Instruction ret = ctor.Body.Instructions[ctor.Body.Instructions.Count - 1]; + if (ret.OpCode == OpCodes.Ret) + { + ctor.Body.Instructions.RemoveAt(ctor.Body.Instructions.Count - 1); + } + else + { + Log.Error($"{netBehaviourSubclass.Name} has invalid constructor", ctor); + WeavingFailed = true; + return; + } + + // TODO: find out if the order below matters. If it doesn't split code below into 2 functions + ILProcessor ctorWorker = ctor.Body.GetILProcessor(); + ILProcessor cctorWorker = cctor.Body.GetILProcessor(); + + for (int i = 0; i < commands.Count; ++i) + { + CmdResult cmdResult = commands[i]; + GenerateRegisterCommandDelegate(cctorWorker, weaverTypes, weaverTypes.registerCommandDelegateReference, commandInvocationFuncs[i], cmdResult); + } + + for (int i = 0; i < clientRpcs.Count; ++i) + { + ClientRpcResult clientRpcResult = clientRpcs[i]; + GenerateRegisterRemoteDelegate(cctorWorker, weaverTypes, weaverTypes.registerRpcDelegateReference, clientRpcInvocationFuncs[i], clientRpcResult.method.Name); + } + + for (int i = 0; i < targetRpcs.Count; ++i) + { + GenerateRegisterRemoteDelegate(cctorWorker, weaverTypes, weaverTypes.registerRpcDelegateReference, targetRpcInvocationFuncs[i], targetRpcs[i].Name); + } + + foreach (FieldDefinition fd in syncObjects) + { + SyncObjectInitializer.GenerateSyncObjectInitializer(ctorWorker, weaverTypes, fd); + } + + cctorWorker.Append(cctorWorker.Create(OpCodes.Ret)); + if (!cctorFound) + { + netBehaviourSubclass.Methods.Add(cctor); + } + + // finish ctor + ctorWorker.Append(ctorWorker.Create(OpCodes.Ret)); + + // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late + netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit; + } + + /* + // This generates code like: + NetworkBehaviour.RegisterCommandDelegate(base.GetType(), "CmdThrust", new NetworkBehaviour.CmdDelegate(ShipControl.InvokeCmdCmdThrust)); + */ + void GenerateRegisterRemoteDelegate(ILProcessor worker, WeaverTypes weaverTypes, MethodReference registerMethod, MethodDefinition func, string cmdName) + { + worker.Emit(OpCodes.Ldtoken, netBehaviourSubclass); + worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference); + worker.Emit(OpCodes.Ldstr, cmdName); + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, func); + + worker.Emit(OpCodes.Newobj, weaverTypes.CmdDelegateConstructor); + // + worker.Emit(OpCodes.Call, registerMethod); + } + + void GenerateRegisterCommandDelegate(ILProcessor worker, WeaverTypes weaverTypes, MethodReference registerMethod, MethodDefinition func, CmdResult cmdResult) + { + string cmdName = cmdResult.method.Name; + bool requiresAuthority = cmdResult.requiresAuthority; + + worker.Emit(OpCodes.Ldtoken, netBehaviourSubclass); + worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference); + worker.Emit(OpCodes.Ldstr, cmdName); + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, func); + + worker.Emit(OpCodes.Newobj, weaverTypes.CmdDelegateConstructor); + + // requiresAuthority ? 1 : 0 + worker.Emit(requiresAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + + worker.Emit(OpCodes.Call, registerMethod); + } + + void GenerateSerialization(ref bool WeavingFailed) + { + const string SerializeMethodName = "SerializeSyncVars"; + if (netBehaviourSubclass.GetMethod(SerializeMethodName) != null) + return; + + if (syncVars.Count == 0) + { + // no synvars, no need for custom OnSerialize + return; + } + + MethodDefinition serialize = new MethodDefinition(SerializeMethodName, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, + weaverTypes.Import()); + + serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, weaverTypes.Import())); + serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, weaverTypes.Import())); + ILProcessor worker = serialize.Body.GetILProcessor(); + + serialize.Body.InitLocals = true; + + // loc_0, this local variable is to determine if any variable was dirty + VariableDefinition dirtyLocal = new VariableDefinition(weaverTypes.Import()); + serialize.Body.Variables.Add(dirtyLocal); + + MethodReference baseSerialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, SerializeMethodName); + if (baseSerialize != null) + { + // base + worker.Emit(OpCodes.Ldarg_0); + // writer + worker.Emit(OpCodes.Ldarg_1); + // forceAll + worker.Emit(OpCodes.Ldarg_2); + worker.Emit(OpCodes.Call, baseSerialize); + // set dirtyLocal to result of base.OnSerialize() + worker.Emit(OpCodes.Stloc_0); + } + + // Generates: if (forceAll); + Instruction initialStateLabel = worker.Create(OpCodes.Nop); + // forceAll + worker.Emit(OpCodes.Ldarg_2); + worker.Emit(OpCodes.Brfalse, initialStateLabel); + + foreach (FieldDefinition syncVar in syncVars) + { + // Generates a writer call for each sync variable + // writer + worker.Emit(OpCodes.Ldarg_1); + // this + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, syncVar); + MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + if (writeFunc != null) + { + worker.Emit(OpCodes.Call, writeFunc); + } + else + { + Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); + WeavingFailed = true; + return; + } + } + + // always return true if forceAll + + // Generates: return true + worker.Emit(OpCodes.Ldc_I4_1); + worker.Emit(OpCodes.Ret); + + // Generates: end if (forceAll); + worker.Append(initialStateLabel); + + // write dirty bits before the data fields + // Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ()); + // writer + worker.Emit(OpCodes.Ldarg_1); + // base + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, weaverTypes.NetworkBehaviourDirtyBitsReference); + MethodReference writeUint64Func = writers.GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + worker.Emit(OpCodes.Call, writeUint64Func); + + // generate a writer call for any dirty variable in this class + + // start at number of syncvars in parent + int dirtyBit = weaverLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); + foreach (FieldDefinition syncVar in syncVars) + { + Instruction varLabel = worker.Create(OpCodes.Nop); + + // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL) + // base + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, weaverTypes.NetworkBehaviourDirtyBitsReference); + // 8 bytes = long + worker.Emit(OpCodes.Ldc_I8, 1L << dirtyBit); + worker.Emit(OpCodes.And); + worker.Emit(OpCodes.Brfalse, varLabel); + + // Generates a call to the writer for that field + // writer + worker.Emit(OpCodes.Ldarg_1); + // base + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, syncVar); + + MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + if (writeFunc != null) + { + worker.Emit(OpCodes.Call, writeFunc); + } + else + { + Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); + WeavingFailed = true; + return; + } + + // something was dirty + worker.Emit(OpCodes.Ldc_I4_1); + // set dirtyLocal to true + worker.Emit(OpCodes.Stloc_0); + + worker.Append(varLabel); + dirtyBit += 1; + } + + // add a log message if needed for debugging + //worker.Emit(OpCodes.Ldstr, "Injected Serialize " + netBehaviourSubclass.Name); + //worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference); + + // generate: return dirtyLocal + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ret); + netBehaviourSubclass.Methods.Add(serialize); + } + + void DeserializeField(WeaverTypes weaverTypes, FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize, ref bool WeavingFailed) + { + // check for Hook function + MethodDefinition hookMethod = syncVarProcessor.GetHookMethod(netBehaviourSubclass, syncVar, ref WeavingFailed); + + if (syncVar.FieldType.IsDerivedFrom()) + { + DeserializeNetworkBehaviourField(weaverTypes, syncVar, worker, deserialize, hookMethod, ref WeavingFailed); + } + else if (syncVar.FieldType.IsNetworkIdentityField()) + { + DeserializeNetworkIdentityField(weaverTypes, syncVar, worker, deserialize, hookMethod, ref WeavingFailed); + } + else + { + DeserializeNormalField(weaverTypes, syncVar, worker, deserialize, hookMethod, ref WeavingFailed); + } + } + + /// [SyncVar] GameObject/NetworkIdentity? + void DeserializeNetworkIdentityField(WeaverTypes weaverTypes, FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize, MethodDefinition hookMethod, ref bool WeavingFailed) + { + /* + Generates code like: + uint oldNetId = ___qNetId; + // returns GetSyncVarGameObject(___qNetId) + GameObject oldSyncVar = syncvar.getter; + ___qNetId = reader.ReadPackedUInt32(); + if (!SyncVarEqual(oldNetId, ref ___goNetId)) + { + // getter returns GetSyncVarGameObject(___qNetId) + OnSetQ(oldSyncVar, syncvar.getter); + } + */ + + // GameObject/NetworkIdentity SyncVar: + // OnSerialize sends writer.Write(go); + // OnDeserialize reads to __netId manually so we can use + // lookups in the getter (so it still works if objects + // move in and out of range repeatedly) + FieldDefinition netIdField = syncVarNetIds[syncVar]; + + // uint oldNetId = ___qNetId; + VariableDefinition oldNetId = new VariableDefinition(weaverTypes.Import()); + deserialize.Body.Variables.Add(oldNetId); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netIdField); + worker.Emit(OpCodes.Stloc, oldNetId); + + // GameObject/NetworkIdentity oldSyncVar = syncvar.getter; + VariableDefinition oldSyncVar = new VariableDefinition(syncVar.FieldType); + deserialize.Body.Variables.Add(oldSyncVar); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, syncVar); + worker.Emit(OpCodes.Stloc, oldSyncVar); + + // read id and store in netId field BEFORE calling the hook + // -> this makes way more sense. by definition, the hook is + // supposed to be called after it was changed. not before. + // -> setting it BEFORE calling the hook fixes the following bug: + // https://github.com/vis2k/Mirror/issues/1151 in host mode + // where the value during the Hook call would call Cmds on + // the host server, and they would all happen and compare + // values BEFORE the hook even returned and hence BEFORE the + // actual value was even set. + // put 'this.' onto stack for 'this.netId' below + worker.Emit(OpCodes.Ldarg_0); + // reader. for 'reader.Read()' below + worker.Emit(OpCodes.Ldarg_1); + // Read() + worker.Emit(OpCodes.Call, readers.GetReadFunc(weaverTypes.Import(), ref WeavingFailed)); + // netId + worker.Emit(OpCodes.Stfld, netIdField); + + if (hookMethod != null) + { + // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32())) + // because we send/receive the netID, not the GameObject/NetworkIdentity + // but only if SyncVar changed. otherwise a client would + // get hook calls for all initial values, even if they + // didn't change from the default values on the client. + // see also: https://github.com/vis2k/Mirror/issues/1278 + + // IMPORTANT: for GameObjects/NetworkIdentities we usually + // use SyncVarGameObjectEqual to compare equality. + // in this case however, we can just use + // SyncVarEqual with the two uint netIds. + // => this is easier weaver code because we don't + // have to get the GameObject/NetworkIdentity + // from the uint netId + // => this is faster because we void one + // GetComponent call for GameObjects to get + // their NetworkIdentity when comparing. + + // Generates: if (!SyncVarEqual); + Instruction syncVarEqualLabel = worker.Create(OpCodes.Nop); + + // 'this.' for 'this.SyncVarEqual' + worker.Emit(OpCodes.Ldarg_0); + // 'oldNetId' + worker.Emit(OpCodes.Ldloc, oldNetId); + // 'ref this.__netId' + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdField); + // call the function + GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(weaverTypes.syncVarEqualReference); + syncVarEqualGm.GenericArguments.Add(netIdField.FieldType); + worker.Emit(OpCodes.Call, syncVarEqualGm); + worker.Emit(OpCodes.Brtrue, syncVarEqualLabel); + + // call the hook + // Generates: OnValueChanged(oldValue, this.syncVar); + syncVarProcessor.WriteCallHookMethodUsingField(worker, hookMethod, oldSyncVar, syncVar, ref WeavingFailed); + + // Generates: end if (!SyncVarEqual); + worker.Append(syncVarEqualLabel); + } + } + + // [SyncVar] NetworkBehaviour + void DeserializeNetworkBehaviourField(WeaverTypes weaverTypes, FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize, MethodDefinition hookMethod, ref bool WeavingFailed) + { + /* + Generates code like: + uint oldNetId = ___qNetId.netId; + byte oldCompIndex = ___qNetId.componentIndex; + T oldSyncVar = syncvar.getter; + ___qNetId.netId = reader.ReadPackedUInt32(); + ___qNetId.componentIndex = reader.ReadByte(); + if (!SyncVarEqual(oldNetId, ref ___goNetId)) + { + // getter returns GetSyncVarGameObject(___qNetId) + OnSetQ(oldSyncVar, syncvar.getter); + } + */ + + // GameObject/NetworkIdentity SyncVar: + // OnSerialize sends writer.Write(go); + // OnDeserialize reads to __netId manually so we can use + // lookups in the getter (so it still works if objects + // move in and out of range repeatedly) + FieldDefinition netIdField = syncVarNetIds[syncVar]; + + // uint oldNetId = ___qNetId; + VariableDefinition oldNetId = new VariableDefinition(weaverTypes.Import()); + deserialize.Body.Variables.Add(oldNetId); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netIdField); + worker.Emit(OpCodes.Stloc, oldNetId); + + // GameObject/NetworkIdentity oldSyncVar = syncvar.getter; + VariableDefinition oldSyncVar = new VariableDefinition(syncVar.FieldType); + deserialize.Body.Variables.Add(oldSyncVar); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, syncVar); + worker.Emit(OpCodes.Stloc, oldSyncVar); + + // read id and store in netId field BEFORE calling the hook + // -> this makes way more sense. by definition, the hook is + // supposed to be called after it was changed. not before. + // -> setting it BEFORE calling the hook fixes the following bug: + // https://github.com/vis2k/Mirror/issues/1151 in host mode + // where the value during the Hook call would call Cmds on + // the host server, and they would all happen and compare + // values BEFORE the hook even returned and hence BEFORE the + // actual value was even set. + // put 'this.' onto stack for 'this.netId' below + worker.Emit(OpCodes.Ldarg_0); + // reader. for 'reader.Read()' below + worker.Emit(OpCodes.Ldarg_1); + // Read() + worker.Emit(OpCodes.Call, readers.GetReadFunc(weaverTypes.Import(), ref WeavingFailed)); + // netId + worker.Emit(OpCodes.Stfld, netIdField); + + if (hookMethod != null) + { + // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32())) + // because we send/receive the netID, not the GameObject/NetworkIdentity + // but only if SyncVar changed. otherwise a client would + // get hook calls for all initial values, even if they + // didn't change from the default values on the client. + // see also: https://github.com/vis2k/Mirror/issues/1278 + + // IMPORTANT: for GameObjects/NetworkIdentities we usually + // use SyncVarGameObjectEqual to compare equality. + // in this case however, we can just use + // SyncVarEqual with the two uint netIds. + // => this is easier weaver code because we don't + // have to get the GameObject/NetworkIdentity + // from the uint netId + // => this is faster because we void one + // GetComponent call for GameObjects to get + // their NetworkIdentity when comparing. + + // Generates: if (!SyncVarEqual); + Instruction syncVarEqualLabel = worker.Create(OpCodes.Nop); + + // 'this.' for 'this.SyncVarEqual' + worker.Emit(OpCodes.Ldarg_0); + // 'oldNetId' + worker.Emit(OpCodes.Ldloc, oldNetId); + // 'ref this.__netId' + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdField); + // call the function + GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(weaverTypes.syncVarEqualReference); + syncVarEqualGm.GenericArguments.Add(netIdField.FieldType); + worker.Emit(OpCodes.Call, syncVarEqualGm); + worker.Emit(OpCodes.Brtrue, syncVarEqualLabel); + + // call the hook + // Generates: OnValueChanged(oldValue, this.syncVar); + syncVarProcessor.WriteCallHookMethodUsingField(worker, hookMethod, oldSyncVar, syncVar, ref WeavingFailed); + + // Generates: end if (!SyncVarEqual); + worker.Append(syncVarEqualLabel); + } + } + + + // [SyncVar] int/float/struct/etc.? + void DeserializeNormalField(WeaverTypes weaverTypes, FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize, MethodDefinition hookMethod, ref bool WeavingFailed) + { + /* + Generates code like: + // for hook + int oldValue = a; + Networka = reader.ReadPackedInt32(); + if (!SyncVarEqual(oldValue, ref a)) + { + OnSetA(oldValue, Networka); + } + */ + + MethodReference readFunc = readers.GetReadFunc(syncVar.FieldType, ref WeavingFailed); + if (readFunc == null) + { + Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); + WeavingFailed = true; + return; + } + + // T oldValue = value; + VariableDefinition oldValue = new VariableDefinition(syncVar.FieldType); + deserialize.Body.Variables.Add(oldValue); + serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); + serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar)); + serWorker.Append(serWorker.Create(OpCodes.Stloc, oldValue)); + + // read value and store in syncvar BEFORE calling the hook + // -> this makes way more sense. by definition, the hook is + // supposed to be called after it was changed. not before. + // -> setting it BEFORE calling the hook fixes the following bug: + // https://github.com/vis2k/Mirror/issues/1151 in host mode + // where the value during the Hook call would call Cmds on + // the host server, and they would all happen and compare + // values BEFORE the hook even returned and hence BEFORE the + // actual value was even set. + // put 'this.' onto stack for 'this.syncvar' below + serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); + // reader. for 'reader.Read()' below + serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); + // reader.Read() + serWorker.Append(serWorker.Create(OpCodes.Call, readFunc)); + // syncvar + serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar)); + + if (hookMethod != null) + { + // call hook + // but only if SyncVar changed. otherwise a client would + // get hook calls for all initial values, even if they + // didn't change from the default values on the client. + // see also: https://github.com/vis2k/Mirror/issues/1278 + + // Generates: if (!SyncVarEqual); + Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop); + + // 'this.' for 'this.SyncVarEqual' + serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); + // 'oldValue' + serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue)); + // 'ref this.syncVar' + serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); + serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar)); + // call the function + GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(weaverTypes.syncVarEqualReference); + syncVarEqualGm.GenericArguments.Add(syncVar.FieldType); + serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm)); + serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel)); + + // call the hook + // Generates: OnValueChanged(oldValue, this.syncVar); + syncVarProcessor.WriteCallHookMethodUsingField(serWorker, hookMethod, oldValue, syncVar, ref WeavingFailed); + + // Generates: end if (!SyncVarEqual); + serWorker.Append(syncVarEqualLabel); + } + } + + void GenerateDeSerialization(ref bool WeavingFailed) + { + const string DeserializeMethodName = "DeserializeSyncVars"; + if (netBehaviourSubclass.GetMethod(DeserializeMethodName) != null) + return; + + if (syncVars.Count == 0) + { + // no synvars, no need for custom OnDeserialize + return; + } + + MethodDefinition serialize = new MethodDefinition(DeserializeMethodName, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + serialize.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, weaverTypes.Import())); + serialize.Parameters.Add(new ParameterDefinition("initialState", ParameterAttributes.None, weaverTypes.Import())); + ILProcessor serWorker = serialize.Body.GetILProcessor(); + // setup local for dirty bits + serialize.Body.InitLocals = true; + VariableDefinition dirtyBitsLocal = new VariableDefinition(weaverTypes.Import()); + serialize.Body.Variables.Add(dirtyBitsLocal); + + MethodReference baseDeserialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, DeserializeMethodName); + if (baseDeserialize != null) + { + // base + serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); + // reader + serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); + // initialState + serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); + serWorker.Append(serWorker.Create(OpCodes.Call, baseDeserialize)); + } + + // Generates: if (initialState); + Instruction initialStateLabel = serWorker.Create(OpCodes.Nop); + + serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); + serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel)); + + foreach (FieldDefinition syncVar in syncVars) + { + DeserializeField(weaverTypes, syncVar, serWorker, serialize, ref WeavingFailed); + } + + serWorker.Append(serWorker.Create(OpCodes.Ret)); + + // Generates: end if (initialState); + serWorker.Append(initialStateLabel); + + // get dirty bits + serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); + serWorker.Append(serWorker.Create(OpCodes.Call, readers.GetReadFunc(weaverTypes.Import(), ref WeavingFailed))); + serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); + + // conditionally read each syncvar + // start at number of syncvars in parent + int dirtyBit = weaverLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); + foreach (FieldDefinition syncVar in syncVars) + { + Instruction varLabel = serWorker.Create(OpCodes.Nop); + + // check if dirty bit is set + serWorker.Append(serWorker.Create(OpCodes.Ldloc_0)); + serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); + serWorker.Append(serWorker.Create(OpCodes.And)); + serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel)); + + DeserializeField(weaverTypes, syncVar, serWorker, serialize, ref WeavingFailed); + + serWorker.Append(varLabel); + dirtyBit += 1; + } + + // add a log message if needed for debugging + //serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Deserialize " + netBehaviourSubclass.Name)); + //serWorker.Append(serWorker.Create(OpCodes.Call, WeaverTypes.logErrorReference)); + + serWorker.Append(serWorker.Create(OpCodes.Ret)); + netBehaviourSubclass.Methods.Add(serialize); + } + + public static bool ReadArguments(MethodDefinition method, Readers readers, Logger Log, ILProcessor worker, RemoteCallType callType, ref bool WeavingFailed) + { + // read each argument + // example result + /* + CallCmdDoSomething(reader.ReadPackedInt32(), reader.ReadNetworkIdentity()); + */ + + bool skipFirst = callType == RemoteCallType.TargetRpc + && TargetRpcProcessor.HasNetworkConnectionParameter(method); + + // arg of calling function, arg 0 is "this" so start counting at 1 + int argNum = 1; + foreach (ParameterDefinition param in method.Parameters) + { + // NetworkConnection is not sent via the NetworkWriter so skip it here + // skip first for NetworkConnection in TargetRpc + if (argNum == 1 && skipFirst) + { + argNum += 1; + continue; + } + // skip SenderConnection in Command + if (IsSenderConnection(param, callType)) + { + argNum += 1; + continue; + } + + + MethodReference readFunc = readers.GetReadFunc(param.ParameterType, ref WeavingFailed); + + if (readFunc == null) + { + Log.Error($"{method.Name} has invalid parameter {param}. Unsupported type {param.ParameterType}, use a supported Mirror type instead", method); + WeavingFailed = true; + return false; + } + + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Call, readFunc); + + // conversion.. is this needed? + if (param.ParameterType.Is()) + { + worker.Emit(OpCodes.Conv_R4); + } + else if (param.ParameterType.Is()) + { + worker.Emit(OpCodes.Conv_R8); + } + } + return true; + } + + public static void AddInvokeParameters(WeaverTypes weaverTypes, ICollection collection) + { + collection.Add(new ParameterDefinition("obj", ParameterAttributes.None, weaverTypes.Import())); + collection.Add(new ParameterDefinition("reader", ParameterAttributes.None, weaverTypes.Import())); + // senderConnection is only used for commands but NetworkBehaviour.CmdDelegate is used for all remote calls + collection.Add(new ParameterDefinition("senderConnection", ParameterAttributes.None, weaverTypes.Import())); + } + + // check if a Command/TargetRpc/Rpc function & parameters are valid for weaving + public bool ValidateRemoteCallAndParameters(MethodDefinition method, RemoteCallType callType, ref bool WeavingFailed) + { + if (method.IsStatic) + { + Log.Error($"{method.Name} must not be static", method); + WeavingFailed = true; + return false; + } + + return ValidateFunction(method, ref WeavingFailed) && + ValidateParameters(method, callType, ref WeavingFailed); + } + + // check if a Command/TargetRpc/Rpc function is valid for weaving + bool ValidateFunction(MethodReference md, ref bool WeavingFailed) + { + if (md.ReturnType.Is()) + { + Log.Error($"{md.Name} cannot be a coroutine", md); + WeavingFailed = true; + return false; + } + if (!md.ReturnType.Is(typeof(void))) + { + Log.Error($"{md.Name} cannot return a value. Make it void instead", md); + WeavingFailed = true; + return false; + } + if (md.HasGenericParameters) + { + Log.Error($"{md.Name} cannot have generic parameters", md); + WeavingFailed = true; + return false; + } + return true; + } + + // check if all Command/TargetRpc/Rpc function's parameters are valid for weaving + bool ValidateParameters(MethodReference method, RemoteCallType callType, ref bool WeavingFailed) + { + for (int i = 0; i < method.Parameters.Count; ++i) + { + ParameterDefinition param = method.Parameters[i]; + if (!ValidateParameter(method, param, callType, i == 0, ref WeavingFailed)) + { + return false; + } + } + return true; + } + + // validate parameters for a remote function call like Rpc/Cmd + bool ValidateParameter(MethodReference method, ParameterDefinition param, RemoteCallType callType, bool firstParam, ref bool WeavingFailed) + { + bool isNetworkConnection = param.ParameterType.Is(); + bool isSenderConnection = IsSenderConnection(param, callType); + + if (param.IsOut) + { + Log.Error($"{method.Name} cannot have out parameters", method); + WeavingFailed = true; + return false; + } + + + // if not SenderConnection And not TargetRpc NetworkConnection first param + if (!isSenderConnection && isNetworkConnection && !(callType == RemoteCallType.TargetRpc && firstParam)) + { + if (callType == RemoteCallType.Command) + { + Log.Error($"{method.Name} has invalid parameter {param}, Cannot pass NetworkConnections. Instead use 'NetworkConnectionToClient conn = null' to get the sender's connection on the server", method); + } + else + { + Log.Error($"{method.Name} has invalid parameter {param}. Cannot pass NetworkConnections", method); + } + WeavingFailed = true; + return false; + } + + // sender connection can be optional + if (param.IsOptional && !isSenderConnection) + { + Log.Error($"{method.Name} cannot have optional parameters", method); + WeavingFailed = true; + return false; + } + + return true; + } + + public static bool IsSenderConnection(ParameterDefinition param, RemoteCallType callType) + { + if (callType != RemoteCallType.Command) + { + return false; + } + + TypeReference type = param.ParameterType; + + return type.Is() + || type.Resolve().IsDerivedFrom(); + } + + void ProcessMethods(ref bool WeavingFailed) + { + HashSet names = new HashSet(); + + // copy the list of methods because we will be adding methods in the loop + List methods = new List(netBehaviourSubclass.Methods); + // find command and RPC functions + foreach (MethodDefinition md in methods) + { + foreach (CustomAttribute ca in md.CustomAttributes) + { + if (ca.AttributeType.Is()) + { + ProcessCommand(names, md, ca, ref WeavingFailed); + break; + } + + if (ca.AttributeType.Is()) + { + ProcessTargetRpc(names, md, ca, ref WeavingFailed); + break; + } + + if (ca.AttributeType.Is()) + { + ProcessClientRpc(names, md, ca, ref WeavingFailed); + break; + } + } + } + } + + void ProcessClientRpc(HashSet names, MethodDefinition md, CustomAttribute clientRpcAttr, ref bool WeavingFailed) + { + if (md.IsAbstract) + { + Log.Error("Abstract ClientRpc are currently not supported, use virtual method instead", md); + WeavingFailed = true; + return; + } + + if (!ValidateRemoteCallAndParameters(md, RemoteCallType.ClientRpc, ref WeavingFailed)) + { + return; + } + + if (names.Contains(md.Name)) + { + Log.Error($"Duplicate ClientRpc name {md.Name}", md); + WeavingFailed = true; + return; + } + + bool includeOwner = clientRpcAttr.GetField("includeOwner", true); + + names.Add(md.Name); + clientRpcs.Add(new ClientRpcResult + { + method = md, + includeOwner = includeOwner + }); + + MethodDefinition rpcCallFunc = RpcProcessor.ProcessRpcCall(weaverTypes, writers, Log, netBehaviourSubclass, md, clientRpcAttr, ref WeavingFailed); + // need null check here because ProcessRpcCall returns null if it can't write all the args + if (rpcCallFunc == null) { return; } + + MethodDefinition rpcFunc = RpcProcessor.ProcessRpcInvoke(weaverTypes, writers, readers, Log, netBehaviourSubclass, md, rpcCallFunc, ref WeavingFailed); + if (rpcFunc != null) + { + clientRpcInvocationFuncs.Add(rpcFunc); + } + } + + void ProcessTargetRpc(HashSet names, MethodDefinition md, CustomAttribute targetRpcAttr, ref bool WeavingFailed) + { + if (md.IsAbstract) + { + Log.Error("Abstract TargetRpc are currently not supported, use virtual method instead", md); + WeavingFailed = true; + return; + } + + if (!ValidateRemoteCallAndParameters(md, RemoteCallType.TargetRpc, ref WeavingFailed)) + return; + + if (names.Contains(md.Name)) + { + Log.Error($"Duplicate Target Rpc name {md.Name}", md); + WeavingFailed = true; + return; + } + names.Add(md.Name); + targetRpcs.Add(md); + + MethodDefinition rpcCallFunc = TargetRpcProcessor.ProcessTargetRpcCall(weaverTypes, writers, Log, netBehaviourSubclass, md, targetRpcAttr, ref WeavingFailed); + + MethodDefinition rpcFunc = TargetRpcProcessor.ProcessTargetRpcInvoke(weaverTypes, readers, Log, netBehaviourSubclass, md, rpcCallFunc, ref WeavingFailed); + if (rpcFunc != null) + { + targetRpcInvocationFuncs.Add(rpcFunc); + } + } + + void ProcessCommand(HashSet names, MethodDefinition md, CustomAttribute commandAttr, ref bool WeavingFailed) + { + if (md.IsAbstract) + { + Log.Error("Abstract Commands are currently not supported, use virtual method instead", md); + WeavingFailed = true; + return; + } + + if (!ValidateRemoteCallAndParameters(md, RemoteCallType.Command, ref WeavingFailed)) + return; + + if (names.Contains(md.Name)) + { + Log.Error($"Duplicate Command name {md.Name}", md); + WeavingFailed = true; + return; + } + + bool requiresAuthority = commandAttr.GetField("requiresAuthority", true); + + names.Add(md.Name); + commands.Add(new CmdResult + { + method = md, + requiresAuthority = requiresAuthority + }); + + MethodDefinition cmdCallFunc = CommandProcessor.ProcessCommandCall(weaverTypes, writers, Log, netBehaviourSubclass, md, commandAttr, ref WeavingFailed); + + MethodDefinition cmdFunc = CommandProcessor.ProcessCommandInvoke(weaverTypes, readers, Log, netBehaviourSubclass, md, cmdCallFunc, ref WeavingFailed); + if (cmdFunc != null) + { + commandInvocationFuncs.Add(cmdFunc); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta new file mode 100644 index 0000000..78a67bf --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8118d606be3214e5d99943ec39530dd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs new file mode 100644 index 0000000..e2ff19f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs @@ -0,0 +1,160 @@ +using System; +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public static class PropertySiteProcessor + { + public static void Process(ModuleDefinition moduleDef, WeaverLists weaverLists) + { + DateTime startTime = DateTime.Now; + + //Search through the types + foreach (TypeDefinition td in moduleDef.Types) + { + if (td.IsClass) + { + ProcessSiteClass(weaverLists, td); + } + } + + Console.WriteLine(" ProcessSitesModule " + moduleDef.Name + " elapsed time:" + (DateTime.Now - startTime)); + } + + static void ProcessSiteClass(WeaverLists weaverLists, TypeDefinition td) + { + //Console.WriteLine(" ProcessSiteClass " + td); + foreach (MethodDefinition md in td.Methods) + { + ProcessSiteMethod(weaverLists, md); + } + + foreach (TypeDefinition nested in td.NestedTypes) + { + ProcessSiteClass(weaverLists, nested); + } + } + + static void ProcessSiteMethod(WeaverLists weaverLists, MethodDefinition md) + { + // process all references to replaced members with properties + //Weaver.DLog(td, " ProcessSiteMethod " + md); + + if (md.Name == ".cctor" || + md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || + md.Name.StartsWith(Weaver.InvokeRpcPrefix)) + return; + + if (md.IsAbstract) + { + return; + } + + if (md.Body != null && md.Body.Instructions != null) + { + for (int iCount = 0; iCount < md.Body.Instructions.Count;) + { + Instruction instr = md.Body.Instructions[iCount]; + iCount += ProcessInstruction(weaverLists, md, instr, iCount); + } + } + } + + // replaces syncvar write access with the NetworkXYZ.get property calls + static void ProcessInstructionSetterField(WeaverLists weaverLists, MethodDefinition md, Instruction i, FieldDefinition opField) + { + // don't replace property call sites in constructors + if (md.Name == ".ctor") + return; + + // does it set a field that we replaced? + if (weaverLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement)) + { + //replace with property + //DLog(td, " replacing " + md.Name + ":" + i); + i.OpCode = OpCodes.Call; + i.Operand = replacement; + //DLog(td, " replaced " + md.Name + ":" + i); + } + } + + // replaces syncvar read access with the NetworkXYZ.get property calls + static void ProcessInstructionGetterField(WeaverLists weaverLists, MethodDefinition md, Instruction i, FieldDefinition opField) + { + // don't replace property call sites in constructors + if (md.Name == ".ctor") + return; + + // does it set a field that we replaced? + if (weaverLists.replacementGetterProperties.TryGetValue(opField, out MethodDefinition replacement)) + { + //replace with property + //DLog(td, " replacing " + md.Name + ":" + i); + i.OpCode = OpCodes.Call; + i.Operand = replacement; + //DLog(td, " replaced " + md.Name + ":" + i); + } + } + + static int ProcessInstruction(WeaverLists weaverLists, MethodDefinition md, Instruction instr, int iCount) + { + if (instr.OpCode == OpCodes.Stfld && instr.Operand is FieldDefinition opFieldst) + { + // this instruction sets the value of a field. cache the field reference. + ProcessInstructionSetterField(weaverLists, md, instr, opFieldst); + } + + if (instr.OpCode == OpCodes.Ldfld && instr.Operand is FieldDefinition opFieldld) + { + // this instruction gets the value of a field. cache the field reference. + ProcessInstructionGetterField(weaverLists, md, instr, opFieldld); + } + + if (instr.OpCode == OpCodes.Ldflda && instr.Operand is FieldDefinition opFieldlda) + { + // loading a field by reference, watch out for initobj instruction + // see https://github.com/vis2k/Mirror/issues/696 + return ProcessInstructionLoadAddress(weaverLists, md, instr, opFieldlda, iCount); + } + + return 1; + } + + static int ProcessInstructionLoadAddress(WeaverLists weaverLists, MethodDefinition md, Instruction instr, FieldDefinition opField, int iCount) + { + // don't replace property call sites in constructors + if (md.Name == ".ctor") + return 1; + + // does it set a field that we replaced? + if (weaverLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement)) + { + // we have a replacement for this property + // is the next instruction a initobj? + Instruction nextInstr = md.Body.Instructions[iCount + 1]; + + if (nextInstr.OpCode == OpCodes.Initobj) + { + // we need to replace this code with: + // var tmp = new MyStruct(); + // this.set_Networkxxxx(tmp); + ILProcessor worker = md.Body.GetILProcessor(); + VariableDefinition tmpVariable = new VariableDefinition(opField.FieldType); + md.Body.Variables.Add(tmpVariable); + + worker.InsertBefore(instr, worker.Create(OpCodes.Ldloca, tmpVariable)); + worker.InsertBefore(instr, worker.Create(OpCodes.Initobj, opField.FieldType)); + worker.InsertBefore(instr, worker.Create(OpCodes.Ldloc, tmpVariable)); + worker.InsertBefore(instr, worker.Create(OpCodes.Call, replacement)); + + worker.Remove(instr); + worker.Remove(nextInstr); + return 4; + } + } + + return 1; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs.meta new file mode 100644 index 0000000..b0fea9a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d48f1ab125e9940a995603796bccc59e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs new file mode 100644 index 0000000..280240c --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs @@ -0,0 +1,216 @@ +// finds all readers and writers and register them +using System.Linq; +using Mono.CecilX; +using Mono.CecilX.Cil; +using Mono.CecilX.Rocks; +using UnityEngine; + +namespace Mirror.Weaver +{ + public static class ReaderWriterProcessor + { + public static bool Process(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed) + { + // find NetworkReader/Writer extensions from Mirror.dll first. + // and NetworkMessage custom writer/reader extensions. + // NOTE: do not include this result in our 'modified' return value, + // otherwise Unity crashes when running tests + ProcessMirrorAssemblyClasses(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed); + + // find readers/writers in the assembly we are in right now. + return ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly, writers, readers, ref WeavingFailed); + } + + static void ProcessMirrorAssemblyClasses(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed) + { + // find Mirror.dll in assembly's references. + // those are guaranteed to be resolvable and correct. + // after all, it references them :) + AssemblyNameReference mirrorAssemblyReference = CurrentAssembly.MainModule.FindReference(Weaver.MirrorAssemblyName); + if (mirrorAssemblyReference != null) + { + // resolve the assembly to load the AssemblyDefinition. + // we need to search all types in it. + // if we only were to resolve one known type like in WeaverTypes, + // then we wouldn't need it. + AssemblyDefinition mirrorAssembly = resolver.Resolve(mirrorAssemblyReference); + if (mirrorAssembly != null) + { + ProcessAssemblyClasses(CurrentAssembly, mirrorAssembly, writers, readers, ref WeavingFailed); + } + else Log.Error($"Failed to resolve {mirrorAssemblyReference}"); + } + else Log.Error("Failed to find Mirror AssemblyNameReference. Can't register Mirror.dll readers/writers."); + } + + static bool ProcessAssemblyClasses(AssemblyDefinition CurrentAssembly, AssemblyDefinition assembly, Writers writers, Readers readers, ref bool WeavingFailed) + { + bool modified = false; + foreach (TypeDefinition klass in assembly.MainModule.Types) + { + // extension methods only live in static classes + // static classes are represented as sealed and abstract + if (klass.IsAbstract && klass.IsSealed) + { + // if assembly has any declared writers then it is "modified" + modified |= LoadDeclaredWriters(CurrentAssembly, klass, writers); + modified |= LoadDeclaredReaders(CurrentAssembly, klass, readers); + } + } + + foreach (TypeDefinition klass in assembly.MainModule.Types) + { + // if assembly has any network message then it is modified + modified |= LoadMessageReadWriter(CurrentAssembly.MainModule, writers, readers, klass, ref WeavingFailed); + } + return modified; + } + + static bool LoadMessageReadWriter(ModuleDefinition module, Writers writers, Readers readers, TypeDefinition klass, ref bool WeavingFailed) + { + bool modified = false; + if (!klass.IsAbstract && !klass.IsInterface && klass.ImplementsInterface()) + { + readers.GetReadFunc(module.ImportReference(klass), ref WeavingFailed); + writers.GetWriteFunc(module.ImportReference(klass), ref WeavingFailed); + modified = true; + } + + foreach (TypeDefinition td in klass.NestedTypes) + { + modified |= LoadMessageReadWriter(module, writers, readers, td, ref WeavingFailed); + } + return modified; + } + + static bool LoadDeclaredWriters(AssemblyDefinition currentAssembly, TypeDefinition klass, Writers writers) + { + // register all the writers in this class. Skip the ones with wrong signature + bool modified = false; + foreach (MethodDefinition method in klass.Methods) + { + if (method.Parameters.Count != 2) + continue; + + if (!method.Parameters[0].ParameterType.Is()) + continue; + + if (!method.ReturnType.Is(typeof(void))) + continue; + + if (!method.HasCustomAttribute()) + continue; + + if (method.HasGenericParameters) + continue; + + TypeReference dataType = method.Parameters[1].ParameterType; + writers.Register(dataType, currentAssembly.MainModule.ImportReference(method)); + modified = true; + } + return modified; + } + + static bool LoadDeclaredReaders(AssemblyDefinition currentAssembly, TypeDefinition klass, Readers readers) + { + // register all the reader in this class. Skip the ones with wrong signature + bool modified = false; + foreach (MethodDefinition method in klass.Methods) + { + if (method.Parameters.Count != 1) + continue; + + if (!method.Parameters[0].ParameterType.Is()) + continue; + + if (method.ReturnType.Is(typeof(void))) + continue; + + if (!method.HasCustomAttribute()) + continue; + + if (method.HasGenericParameters) + continue; + + readers.Register(method.ReturnType, currentAssembly.MainModule.ImportReference(method)); + modified = true; + } + return modified; + } + + // helper function to add [RuntimeInitializeOnLoad] attribute to method + static void AddRuntimeInitializeOnLoadAttribute(AssemblyDefinition assembly, WeaverTypes weaverTypes, MethodDefinition method) + { + // NOTE: previously we used reflection because according paul, + // 'weaving Mirror.dll caused unity to rebuild all dlls but in wrong + // order, which breaks rewired' + // it's not obvious why importing an attribute via reflection instead + // of cecil would break anything. let's use cecil. + + // to add a CustomAttribute, we need the attribute's constructor. + // in this case, there are two: empty, and RuntimeInitializeOnLoadType. + // we want the last one, with the type parameter. + MethodDefinition ctor = weaverTypes.runtimeInitializeOnLoadMethodAttribute.GetConstructors().Last(); + //MethodDefinition ctor = weaverTypes.runtimeInitializeOnLoadMethodAttribute.GetConstructors().First(); + // using ctor directly throws: ArgumentException: Member 'System.Void UnityEditor.InitializeOnLoadMethodAttribute::.ctor()' is declared in another module and needs to be imported + // we need to import it first. + CustomAttribute attribute = new CustomAttribute(assembly.MainModule.ImportReference(ctor)); + // add the RuntimeInitializeLoadType.BeforeSceneLoad argument to ctor + attribute.ConstructorArguments.Add(new CustomAttributeArgument(weaverTypes.Import(), RuntimeInitializeLoadType.BeforeSceneLoad)); + method.CustomAttributes.Add(attribute); + } + + // helper function to add [InitializeOnLoad] attribute to method + // (only works in Editor assemblies. check IsEditorAssembly first.) + static void AddInitializeOnLoadAttribute(AssemblyDefinition assembly, WeaverTypes weaverTypes, MethodDefinition method) + { + // NOTE: previously we used reflection because according paul, + // 'weaving Mirror.dll caused unity to rebuild all dlls but in wrong + // order, which breaks rewired' + // it's not obvious why importing an attribute via reflection instead + // of cecil would break anything. let's use cecil. + + // to add a CustomAttribute, we need the attribute's constructor. + // in this case, there's only one - and it's an empty constructor. + MethodDefinition ctor = weaverTypes.initializeOnLoadMethodAttribute.GetConstructors().First(); + // using ctor directly throws: ArgumentException: Member 'System.Void UnityEditor.InitializeOnLoadMethodAttribute::.ctor()' is declared in another module and needs to be imported + // we need to import it first. + CustomAttribute attribute = new CustomAttribute(assembly.MainModule.ImportReference(ctor)); + method.CustomAttributes.Add(attribute); + } + + // adds Mirror.GeneratedNetworkCode.InitReadWriters() method that + // registers all generated writers into Mirror.Writer static class. + // -> uses [RuntimeInitializeOnLoad] attribute so it's invoke at runtime + // -> uses [InitializeOnLoad] if UnityEditor is referenced so it works + // in Editor and in tests too + // + // use ILSpy to see the result (it's in the DLL's 'Mirror' namespace) + public static void InitializeReaderAndWriters(AssemblyDefinition currentAssembly, WeaverTypes weaverTypes, Writers writers, Readers readers, TypeDefinition GeneratedCodeClass) + { + MethodDefinition initReadWriters = new MethodDefinition("InitReadWriters", MethodAttributes.Public | + MethodAttributes.Static, + weaverTypes.Import(typeof(void))); + + // add [RuntimeInitializeOnLoad] in any case + AddRuntimeInitializeOnLoadAttribute(currentAssembly, weaverTypes, initReadWriters); + + // add [InitializeOnLoad] if UnityEditor is referenced + if (Helpers.IsEditorAssembly(currentAssembly)) + { + AddInitializeOnLoadAttribute(currentAssembly, weaverTypes, initReadWriters); + } + + // fill function body with reader/writer initializers + ILProcessor worker = initReadWriters.Body.GetILProcessor(); + // for debugging: add a log to see if initialized on load + //worker.Emit(OpCodes.Ldstr, $"[InitReadWriters] called!"); + //worker.Emit(OpCodes.Call, Weaver.weaverTypes.logWarningReference); + writers.InitializeWriters(worker); + readers.InitializeReaders(worker); + worker.Emit(OpCodes.Ret); + + GeneratedCodeClass.Methods.Add(initReadWriters); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta new file mode 100644 index 0000000..8d8b30a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3263602f0a374ecd8d08588b1fc2f76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs new file mode 100644 index 0000000..2136e9f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs @@ -0,0 +1,102 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + // Processes [Rpc] methods in NetworkBehaviour + public static class RpcProcessor + { + public static MethodDefinition ProcessRpcInvoke(WeaverTypes weaverTypes, Writers writers, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed) + { + MethodDefinition rpc = new MethodDefinition( + Weaver.InvokeRpcPrefix + md.Name, + MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = rpc.Body.GetILProcessor(); + Instruction label = worker.Create(OpCodes.Nop); + + NetworkBehaviourProcessor.WriteClientActiveCheck(worker, weaverTypes, md.Name, label, "RPC"); + + // setup for reader + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Castclass, td); + + if (!NetworkBehaviourProcessor.ReadArguments(md, readers, Log, worker, RemoteCallType.ClientRpc, ref WeavingFailed)) + return null; + + // invoke actual command function + worker.Emit(OpCodes.Callvirt, rpcCallFunc); + worker.Emit(OpCodes.Ret); + + NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, rpc.Parameters); + td.Methods.Add(rpc); + return rpc; + } + + /* + * generates code like: + + public void RpcTest (int param) + { + NetworkWriter writer = new NetworkWriter (); + writer.WritePackedUInt32((uint)param); + base.SendRPCInternal(typeof(class),"RpcTest", writer, 0); + } + public void CallRpcTest (int param) + { + // whatever the user did before + } + + Originally HLAPI put the send message code inside the Call function + and then proceeded to replace every call to RpcTest with CallRpcTest + + This method moves all the user's code into the "CallRpc" method + and replaces the body of the original method with the send message code. + This way we do not need to modify the code anywhere else, and this works + correctly in dependent assemblies + */ + public static MethodDefinition ProcessRpcCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute clientRpcAttr, ref bool WeavingFailed) + { + MethodDefinition rpc = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed); + + ILProcessor worker = md.Body.GetILProcessor(); + + NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes); + + // add a log message if needed for debugging + //worker.Emit(OpCodes.Ldstr, "Call ClientRpc function " + md.Name); + //worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference); + + NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes); + + // write all the arguments that the user passed to the Rpc call + if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.ClientRpc, ref WeavingFailed)) + return null; + + string rpcName = md.Name; + int channel = clientRpcAttr.GetField("channel", 0); + bool includeOwner = clientRpcAttr.GetField("includeOwner", true); + + // invoke SendInternal and return + // this + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldtoken, td); + // invokerClass + worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference); + worker.Emit(OpCodes.Ldstr, rpcName); + // writer + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ldc_I4, channel); + // includeOwner ? 1 : 0 + worker.Emit(includeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + worker.Emit(OpCodes.Callvirt, weaverTypes.sendRpcInternal); + + NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes); + + worker.Emit(OpCodes.Ret); + + return rpc; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta new file mode 100644 index 0000000..5f94aa7 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3cb7051ff41947e59bba58bdd2b73fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs new file mode 100644 index 0000000..50df598 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs @@ -0,0 +1,154 @@ +// Injects server/client active checks for [Server/Client] attributes +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + static class ServerClientAttributeProcessor + { + public static bool Process(WeaverTypes weaverTypes, Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + bool modified = false; + foreach (MethodDefinition md in td.Methods) + { + modified |= ProcessSiteMethod(weaverTypes, Log, md, ref WeavingFailed); + } + + foreach (TypeDefinition nested in td.NestedTypes) + { + modified |= Process(weaverTypes, Log, nested, ref WeavingFailed); + } + return modified; + } + + static bool ProcessSiteMethod(WeaverTypes weaverTypes, Logger Log, MethodDefinition md, ref bool WeavingFailed) + { + if (md.Name == ".cctor" || + md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || + md.Name.StartsWith(Weaver.InvokeRpcPrefix)) + return false; + + if (md.IsAbstract) + { + if (HasServerClientAttribute(md)) + { + Log.Error("Server or Client Attributes can't be added to abstract method. Server and Client Attributes are not inherited so they need to be applied to the override methods instead.", md); + WeavingFailed = true; + } + return false; + } + + if (md.Body != null && md.Body.Instructions != null) + { + return ProcessMethodAttributes(weaverTypes, md); + } + return false; + } + + public static bool HasServerClientAttribute(MethodDefinition md) + { + foreach (CustomAttribute attr in md.CustomAttributes) + { + switch (attr.Constructor.DeclaringType.ToString()) + { + case "Mirror.ServerAttribute": + case "Mirror.ServerCallbackAttribute": + case "Mirror.ClientAttribute": + case "Mirror.ClientCallbackAttribute": + return true; + default: + break; + } + } + return false; + } + + public static bool ProcessMethodAttributes(WeaverTypes weaverTypes, MethodDefinition md) + { + if (md.HasCustomAttribute()) + InjectServerGuard(weaverTypes, md, true); + else if (md.HasCustomAttribute()) + InjectServerGuard(weaverTypes, md, false); + else if (md.HasCustomAttribute()) + InjectClientGuard(weaverTypes, md, true); + else if (md.HasCustomAttribute()) + InjectClientGuard(weaverTypes, md, false); + else + return false; + + return true; + } + + static void InjectServerGuard(WeaverTypes weaverTypes, MethodDefinition md, bool logWarning) + { + ILProcessor worker = md.Body.GetILProcessor(); + Instruction top = md.Body.Instructions[0]; + + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.NetworkServerGetActive)); + worker.InsertBefore(top, worker.Create(OpCodes.Brtrue, top)); + if (logWarning) + { + worker.InsertBefore(top, worker.Create(OpCodes.Ldstr, $"[Server] function '{md.FullName}' called when server was not active")); + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.logWarningReference)); + } + InjectGuardParameters(md, worker, top); + InjectGuardReturnValue(md, worker, top); + worker.InsertBefore(top, worker.Create(OpCodes.Ret)); + } + + static void InjectClientGuard(WeaverTypes weaverTypes, MethodDefinition md, bool logWarning) + { + ILProcessor worker = md.Body.GetILProcessor(); + Instruction top = md.Body.Instructions[0]; + + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.NetworkClientGetActive)); + worker.InsertBefore(top, worker.Create(OpCodes.Brtrue, top)); + if (logWarning) + { + worker.InsertBefore(top, worker.Create(OpCodes.Ldstr, $"[Client] function '{md.FullName}' called when client was not active")); + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.logWarningReference)); + } + + InjectGuardParameters(md, worker, top); + InjectGuardReturnValue(md, worker, top); + worker.InsertBefore(top, worker.Create(OpCodes.Ret)); + } + + // this is required to early-out from a function with "ref" or "out" parameters + static void InjectGuardParameters(MethodDefinition md, ILProcessor worker, Instruction top) + { + int offset = md.Resolve().IsStatic ? 0 : 1; + for (int index = 0; index < md.Parameters.Count; index++) + { + ParameterDefinition param = md.Parameters[index]; + if (param.IsOut) + { + TypeReference elementType = param.ParameterType.GetElementType(); + + md.Body.Variables.Add(new VariableDefinition(elementType)); + md.Body.InitLocals = true; + + worker.InsertBefore(top, worker.Create(OpCodes.Ldarg, index + offset)); + worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, (byte)(md.Body.Variables.Count - 1))); + worker.InsertBefore(top, worker.Create(OpCodes.Initobj, elementType)); + worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, md.Body.Variables.Count - 1)); + worker.InsertBefore(top, worker.Create(OpCodes.Stobj, elementType)); + } + } + } + + // this is required to early-out from a function with a return value. + static void InjectGuardReturnValue(MethodDefinition md, ILProcessor worker, Instruction top) + { + if (!md.ReturnType.Is(typeof(void))) + { + md.Body.Variables.Add(new VariableDefinition(md.ReturnType)); + md.Body.InitLocals = true; + + worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, (byte)(md.Body.Variables.Count - 1))); + worker.InsertBefore(top, worker.Create(OpCodes.Initobj, md.ReturnType)); + worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, md.Body.Variables.Count - 1)); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta new file mode 100644 index 0000000..ff09ae9 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 024f251bf693bb345b90b9177892d534 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs new file mode 100644 index 0000000..59f0026 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs @@ -0,0 +1,47 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public static class SyncObjectInitializer + { + public static void GenerateSyncObjectInitializer(ILProcessor worker, WeaverTypes weaverTypes, FieldDefinition fd) + { + // register syncobject in network behaviour + GenerateSyncObjectRegistration(worker, weaverTypes, fd); + } + + public static bool ImplementsSyncObject(TypeReference typeRef) + { + try + { + // value types cant inherit from SyncObject + if (typeRef.IsValueType) + { + return false; + } + + return typeRef.Resolve().ImplementsInterface(); + } + catch + { + // sometimes this will fail if we reference a weird library that can't be resolved, so we just swallow that exception and return false + } + + return false; + } + + /* + // generates code like: + this.InitSyncObject(m_sizes); + */ + static void GenerateSyncObjectRegistration(ILProcessor worker, WeaverTypes weaverTypes, FieldDefinition fd) + { + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, fd); + + worker.Emit(OpCodes.Call, weaverTypes.InitSyncObjectReference); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta new file mode 100644 index 0000000..1a0c3cf --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d02219b00b3674e59a2151f41e791688 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs new file mode 100644 index 0000000..c3eedf0 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + public static class SyncObjectProcessor + { + // Finds SyncObjects fields in a type + // Type should be a NetworkBehaviour + public static List FindSyncObjectsFields(Writers writers, Readers readers, Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + List syncObjects = new List(); + + foreach (FieldDefinition fd in td.Fields) + { + if (fd.FieldType.Resolve().ImplementsInterface()) + { + if (fd.IsStatic) + { + Log.Error($"{fd.Name} cannot be static", fd); + WeavingFailed = true; + continue; + } + + GenerateReadersAndWriters(writers, readers, fd.FieldType, ref WeavingFailed); + + syncObjects.Add(fd); + } + } + + + return syncObjects; + } + + // Generates serialization methods for synclists + static void GenerateReadersAndWriters(Writers writers, Readers readers, TypeReference tr, ref bool WeavingFailed) + { + if (tr is GenericInstanceType genericInstance) + { + foreach (TypeReference argument in genericInstance.GenericArguments) + { + if (!argument.IsGenericParameter) + { + readers.GetReadFunc(argument, ref WeavingFailed); + writers.GetWriteFunc(argument, ref WeavingFailed); + } + } + } + + if (tr != null) + { + GenerateReadersAndWriters(writers, readers, tr.Resolve().BaseType, ref WeavingFailed); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta new file mode 100644 index 0000000..82696b6 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 78f71efc83cde4917b7d21efa90bcc9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs new file mode 100644 index 0000000..963cc2b --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs @@ -0,0 +1,488 @@ +using System.Collections.Generic; +using System.Linq; +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + // Processes [SyncVar] in NetworkBehaviour + // not static, because ILPostProcessor is multithreaded + public class SyncVarProcessor + { + // ulong = 64 bytes + const int SyncVarLimit = 64; + + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + WeaverLists weaverLists; + Logger Log; + + string HookParameterMessage(string hookName, TypeReference ValueType) => + $"void {hookName}({ValueType} oldValue, {ValueType} newValue)"; + + public SyncVarProcessor(AssemblyDefinition assembly, WeaverTypes weaverTypes, WeaverLists weaverLists, Logger Log) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.weaverLists = weaverLists; + this.Log = Log; + } + + // Get hook method if any + public MethodDefinition GetHookMethod(TypeDefinition td, FieldDefinition syncVar, ref bool WeavingFailed) + { + CustomAttribute syncVarAttr = syncVar.GetCustomAttribute(); + + if (syncVarAttr == null) + return null; + + string hookFunctionName = syncVarAttr.GetField("hook", null); + + if (hookFunctionName == null) + return null; + + return FindHookMethod(td, syncVar, hookFunctionName, ref WeavingFailed); + } + + MethodDefinition FindHookMethod(TypeDefinition td, FieldDefinition syncVar, string hookFunctionName, ref bool WeavingFailed) + { + List methods = td.GetMethods(hookFunctionName); + + List methodsWith2Param = new List(methods.Where(m => m.Parameters.Count == 2)); + + if (methodsWith2Param.Count == 0) + { + Log.Error($"Could not find hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " + + $"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}", + syncVar); + WeavingFailed = true; + + return null; + } + + foreach (MethodDefinition method in methodsWith2Param) + { + if (MatchesParameters(syncVar, method)) + { + return method; + } + } + + Log.Error($"Wrong type for Parameter in hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " + + $"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}", + syncVar); + WeavingFailed = true; + + return null; + } + + bool MatchesParameters(FieldDefinition syncVar, MethodDefinition method) + { + // matches void onValueChange(T oldValue, T newValue) + return method.Parameters[0].ParameterType.FullName == syncVar.FieldType.FullName && + method.Parameters[1].ParameterType.FullName == syncVar.FieldType.FullName; + } + + public MethodDefinition GenerateSyncVarGetter(FieldDefinition fd, string originalName, FieldDefinition netFieldId) + { + //Create the get method + MethodDefinition get = new MethodDefinition( + "get_Network" + originalName, MethodAttributes.Public | + MethodAttributes.SpecialName | + MethodAttributes.HideBySig, + fd.FieldType); + + ILProcessor worker = get.Body.GetILProcessor(); + + // [SyncVar] GameObject? + if (fd.FieldType.Is()) + { + // return this.GetSyncVarGameObject(ref field, uint netId); + // this. + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netFieldId); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fd); + worker.Emit(OpCodes.Call, weaverTypes.getSyncVarGameObjectReference); + worker.Emit(OpCodes.Ret); + } + // [SyncVar] NetworkIdentity? + else if (fd.FieldType.Is()) + { + // return this.GetSyncVarNetworkIdentity(ref field, uint netId); + // this. + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netFieldId); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fd); + worker.Emit(OpCodes.Call, weaverTypes.getSyncVarNetworkIdentityReference); + worker.Emit(OpCodes.Ret); + } + else if (fd.FieldType.IsDerivedFrom()) + { + // return this.GetSyncVarNetworkBehaviour(ref field, uint netId); + // this. + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netFieldId); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fd); + MethodReference getFunc = weaverTypes.getSyncVarNetworkBehaviourReference.MakeGeneric(assembly.MainModule, fd.FieldType); + worker.Emit(OpCodes.Call, getFunc); + worker.Emit(OpCodes.Ret); + } + // [SyncVar] int, string, etc. + else + { + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, fd); + worker.Emit(OpCodes.Ret); + } + + get.Body.Variables.Add(new VariableDefinition(fd.FieldType)); + get.Body.InitLocals = true; + get.SemanticsAttributes = MethodSemanticsAttributes.Getter; + + return get; + } + + public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId, ref bool WeavingFailed) + { + //Create the set method + MethodDefinition set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public | + MethodAttributes.SpecialName | + MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = set.Body.GetILProcessor(); + + // if (!SyncVarEqual(value, ref playerData)) + Instruction endOfMethod = worker.Create(OpCodes.Nop); + + // this + worker.Emit(OpCodes.Ldarg_0); + // new value to set + worker.Emit(OpCodes.Ldarg_1); + // reference to field to set + // make generic version of SetSyncVar with field type + if (fd.FieldType.Is()) + { + // reference to netId Field to set + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netFieldId); + + worker.Emit(OpCodes.Call, weaverTypes.syncVarGameObjectEqualReference); + } + else if (fd.FieldType.Is()) + { + // reference to netId Field to set + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netFieldId); + + worker.Emit(OpCodes.Call, weaverTypes.syncVarNetworkIdentityEqualReference); + } + else if (fd.FieldType.IsDerivedFrom()) + { + // reference to netId Field to set + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netFieldId); + + MethodReference getFunc = weaverTypes.syncVarNetworkBehaviourEqualReference.MakeGeneric(assembly.MainModule, fd.FieldType); + worker.Emit(OpCodes.Call, getFunc); + } + else + { + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fd); + + GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(weaverTypes.syncVarEqualReference); + syncVarEqualGm.GenericArguments.Add(fd.FieldType); + worker.Emit(OpCodes.Call, syncVarEqualGm); + } + + worker.Emit(OpCodes.Brtrue, endOfMethod); + + // T oldValue = value; + // TODO for GO/NI we need to backup the netId don't we? + VariableDefinition oldValue = new VariableDefinition(fd.FieldType); + set.Body.Variables.Add(oldValue); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, fd); + worker.Emit(OpCodes.Stloc, oldValue); + + // this + worker.Emit(OpCodes.Ldarg_0); + + // new value to set + worker.Emit(OpCodes.Ldarg_1); + + // reference to field to set + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fd); + + // dirty bit + // 8 byte integer aka long + worker.Emit(OpCodes.Ldc_I8, dirtyBit); + + if (fd.FieldType.Is()) + { + // reference to netId Field to set + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netFieldId); + + worker.Emit(OpCodes.Call, weaverTypes.setSyncVarGameObjectReference); + } + else if (fd.FieldType.Is()) + { + // reference to netId Field to set + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netFieldId); + + worker.Emit(OpCodes.Call, weaverTypes.setSyncVarNetworkIdentityReference); + } + else if (fd.FieldType.IsDerivedFrom()) + { + // reference to netId Field to set + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netFieldId); + + MethodReference getFunc = weaverTypes.setSyncVarNetworkBehaviourReference.MakeGeneric(assembly.MainModule, fd.FieldType); + worker.Emit(OpCodes.Call, getFunc); + } + else + { + // make generic version of SetSyncVar with field type + GenericInstanceMethod gm = new GenericInstanceMethod(weaverTypes.setSyncVarReference); + gm.GenericArguments.Add(fd.FieldType); + + // invoke SetSyncVar + worker.Emit(OpCodes.Call, gm); + } + + MethodDefinition hookMethod = GetHookMethod(td, fd, ref WeavingFailed); + + if (hookMethod != null) + { + //if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit)) + Instruction label = worker.Create(OpCodes.Nop); + worker.Emit(OpCodes.Call, weaverTypes.NetworkServerGetLocalClientActive); + worker.Emit(OpCodes.Brfalse, label); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldc_I8, dirtyBit); + worker.Emit(OpCodes.Call, weaverTypes.getSyncVarHookGuard); + worker.Emit(OpCodes.Brtrue, label); + + // setSyncVarHookGuard(dirtyBit, true); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldc_I8, dirtyBit); + worker.Emit(OpCodes.Ldc_I4_1); + worker.Emit(OpCodes.Call, weaverTypes.setSyncVarHookGuard); + + // call hook (oldValue, newValue) + // Generates: OnValueChanged(oldValue, value); + WriteCallHookMethodUsingArgument(worker, hookMethod, oldValue); + + // setSyncVarHookGuard(dirtyBit, false); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldc_I8, dirtyBit); + worker.Emit(OpCodes.Ldc_I4_0); + worker.Emit(OpCodes.Call, weaverTypes.setSyncVarHookGuard); + + worker.Append(label); + } + + worker.Append(endOfMethod); + + worker.Emit(OpCodes.Ret); + + set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType)); + set.SemanticsAttributes = MethodSemanticsAttributes.Setter; + + return set; + } + + public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary syncVarNetIds, long dirtyBit, ref bool WeavingFailed) + { + string originalName = fd.Name; + + // GameObject/NetworkIdentity SyncVars have a new field for netId + FieldDefinition netIdField = null; + // NetworkBehaviour has different field type than other NetworkIdentityFields + if (fd.FieldType.IsDerivedFrom()) + { + netIdField = new FieldDefinition("___" + fd.Name + "NetId", + FieldAttributes.Private, + weaverTypes.Import()); + + syncVarNetIds[fd] = netIdField; + } + else if (fd.FieldType.IsNetworkIdentityField()) + { + netIdField = new FieldDefinition("___" + fd.Name + "NetId", + FieldAttributes.Private, + weaverTypes.Import()); + + syncVarNetIds[fd] = netIdField; + } + + MethodDefinition get = GenerateSyncVarGetter(fd, originalName, netIdField); + MethodDefinition set = GenerateSyncVarSetter(td, fd, originalName, dirtyBit, netIdField, ref WeavingFailed); + + //NOTE: is property even needed? Could just use a setter function? + //create the property + PropertyDefinition propertyDefinition = new PropertyDefinition("Network" + originalName, PropertyAttributes.None, fd.FieldType) + { + GetMethod = get, + SetMethod = set + }; + + //add the methods and property to the type. + td.Methods.Add(get); + td.Methods.Add(set); + td.Properties.Add(propertyDefinition); + weaverLists.replacementSetterProperties[fd] = set; + + // replace getter field if GameObject/NetworkIdentity so it uses + // netId instead + // -> only for GameObjects, otherwise an int syncvar's getter would + // end up in recursion. + if (fd.FieldType.IsNetworkIdentityField()) + { + weaverLists.replacementGetterProperties[fd] = get; + } + } + + public (List syncVars, Dictionary syncVarNetIds) ProcessSyncVars(TypeDefinition td, ref bool WeavingFailed) + { + List syncVars = new List(); + Dictionary syncVarNetIds = new Dictionary(); + + // the mapping of dirtybits to sync-vars is implicit in the order of the fields here. this order is recorded in m_replacementProperties. + // start assigning syncvars at the place the base class stopped, if any + int dirtyBitCounter = weaverLists.GetSyncVarStart(td.BaseType.FullName); + + // find syncvars + foreach (FieldDefinition fd in td.Fields) + { + if (fd.HasCustomAttribute()) + { + if ((fd.Attributes & FieldAttributes.Static) != 0) + { + Log.Error($"{fd.Name} cannot be static", fd); + WeavingFailed = true; + continue; + } + + if (fd.FieldType.IsArray) + { + Log.Error($"{fd.Name} has invalid type. Use SyncLists instead of arrays", fd); + WeavingFailed = true; + continue; + } + + if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType)) + { + Log.Warning($"{fd.Name} has [SyncVar] attribute. SyncLists should not be marked with SyncVar", fd); + } + else + { + syncVars.Add(fd); + + ProcessSyncVar(td, fd, syncVarNetIds, 1L << dirtyBitCounter, ref WeavingFailed); + dirtyBitCounter += 1; + + if (dirtyBitCounter == SyncVarLimit) + { + Log.Error($"{td.Name} has too many SyncVars. Consider refactoring your class into multiple components", td); + WeavingFailed = true; + continue; + } + } + } + } + + // add all the new SyncVar __netId fields + foreach (FieldDefinition fd in syncVarNetIds.Values) + { + td.Fields.Add(fd); + } + weaverLists.SetNumSyncVars(td.FullName, syncVars.Count); + + return (syncVars, syncVarNetIds); + } + + public void WriteCallHookMethodUsingArgument(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue) + { + WriteCallHookMethod(worker, hookMethod, oldValue, null); + } + + public void WriteCallHookMethodUsingField(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue, FieldDefinition newValue, ref bool WeavingFailed) + { + if (newValue == null) + { + Log.Error("NewValue field was null when writing SyncVar hook"); + WeavingFailed = true; + } + + WriteCallHookMethod(worker, hookMethod, oldValue, newValue); + } + + void WriteCallHookMethod(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue, FieldDefinition newValue) + { + WriteStartFunctionCall(); + + // write args + WriteOldValue(); + WriteNewValue(); + + WriteEndFunctionCall(); + + + // *** Local functions used to write OpCodes *** + // Local functions have access to function variables, no need to pass in args + + void WriteOldValue() + { + worker.Emit(OpCodes.Ldloc, oldValue); + } + + void WriteNewValue() + { + // write arg1 or this.field + if (newValue == null) + { + worker.Emit(OpCodes.Ldarg_1); + } + else + { + // this. + worker.Emit(OpCodes.Ldarg_0); + // syncvar.get + worker.Emit(OpCodes.Ldfld, newValue); + } + } + + // Writes this before method if it is not static + void WriteStartFunctionCall() + { + // don't add this (Ldarg_0) if method is static + if (!hookMethod.IsStatic) + { + // this before method call + // e.g. this.onValueChanged + worker.Emit(OpCodes.Ldarg_0); + } + } + + // Calls method + void WriteEndFunctionCall() + { + // only use Callvirt when not static + OpCode opcode = hookMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt; + worker.Emit(opcode, hookMethod); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs.meta new file mode 100644 index 0000000..31c4586 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f52c39bddd95d42b88f9cd554dfd9198 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs new file mode 100644 index 0000000..48b3db0 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs @@ -0,0 +1,139 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + // Processes [TargetRpc] methods in NetworkBehaviour + public static class TargetRpcProcessor + { + // helper functions to check if the method has a NetworkConnection parameter + public static bool HasNetworkConnectionParameter(MethodDefinition md) + { + return md.Parameters.Count > 0 && + md.Parameters[0].ParameterType.Is(); + } + + public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed) + { + MethodDefinition rpc = new MethodDefinition(Weaver.InvokeRpcPrefix + md.Name, MethodAttributes.Family | + MethodAttributes.Static | + MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = rpc.Body.GetILProcessor(); + Instruction label = worker.Create(OpCodes.Nop); + + NetworkBehaviourProcessor.WriteClientActiveCheck(worker, weaverTypes, md.Name, label, "TargetRPC"); + + // setup for reader + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Castclass, td); + + // NetworkConnection parameter is optional + if (HasNetworkConnectionParameter(md)) + { + // on server, the NetworkConnection parameter is a connection to client. + // when the rpc is invoked on the client, it still has the same + // function signature. we pass in the connection to server, + // which is cleaner than just passing null) + //NetworkClient.readyconnection + // + // TODO + // a) .connectionToServer = best solution. no doubt. + // b) NetworkClient.connection for now. add TODO to not use static later. + worker.Emit(OpCodes.Call, weaverTypes.ReadyConnectionReference); + } + + // process reader parameters and skip first one if first one is NetworkConnection + if (!NetworkBehaviourProcessor.ReadArguments(md, readers, Log, worker, RemoteCallType.TargetRpc, ref WeavingFailed)) + return null; + + // invoke actual command function + worker.Emit(OpCodes.Callvirt, rpcCallFunc); + worker.Emit(OpCodes.Ret); + + NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, rpc.Parameters); + td.Methods.Add(rpc); + return rpc; + } + + /* generates code like: + public void TargetTest (NetworkConnection conn, int param) + { + NetworkWriter writer = new NetworkWriter (); + writer.WritePackedUInt32 ((uint)param); + base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val); + } + public void CallTargetTest (NetworkConnection conn, int param) + { + // whatever the user did before + } + + or if optional: + public void TargetTest (int param) + { + NetworkWriter writer = new NetworkWriter (); + writer.WritePackedUInt32 ((uint)param); + base.SendTargetRPCInternal (null, typeof(class), "TargetTest", val); + } + public void CallTargetTest (int param) + { + // whatever the user did before + } + + Originally HLAPI put the send message code inside the Call function + and then proceeded to replace every call to TargetTest with CallTargetTest + + This method moves all the user's code into the "CallTargetRpc" method + and replaces the body of the original method with the send message code. + This way we do not need to modify the code anywhere else, and this works + correctly in dependent assemblies + + */ + public static MethodDefinition ProcessTargetRpcCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute targetRpcAttr, ref bool WeavingFailed) + { + MethodDefinition rpc = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed); + + ILProcessor worker = md.Body.GetILProcessor(); + + NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes); + + NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes); + + // write all the arguments that the user passed to the TargetRpc call + // (skip first one if first one is NetworkConnection) + if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.TargetRpc, ref WeavingFailed)) + return null; + + string rpcName = md.Name; + + // invoke SendInternal and return + // this + worker.Emit(OpCodes.Ldarg_0); + if (HasNetworkConnectionParameter(md)) + { + // connection + worker.Emit(OpCodes.Ldarg_1); + } + else + { + // null + worker.Emit(OpCodes.Ldnull); + } + worker.Emit(OpCodes.Ldtoken, td); + // invokerClass + worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference); + worker.Emit(OpCodes.Ldstr, rpcName); + // writer + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0)); + worker.Emit(OpCodes.Callvirt, weaverTypes.sendTargetRpcInternal); + + NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes); + + worker.Emit(OpCodes.Ret); + + return rpc; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta new file mode 100644 index 0000000..c315349 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb3ce6c6f3f2942ae88178b86f5a8282 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs b/Assets/Mirror/Editor/Weaver/Readers.cs new file mode 100644 index 0000000..ad46f80 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Readers.cs @@ -0,0 +1,383 @@ +using System; +using System.Collections.Generic; +using Mono.CecilX; +using Mono.CecilX.Cil; +// to use Mono.CecilX.Rocks here, we need to 'override references' in the +// Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX.Rocks. +// otherwise we get an unknown import exception. +using Mono.CecilX.Rocks; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public class Readers + { + // Readers are only for this assembly. + // can't be used from another assembly, otherwise we will get: + // "System.ArgumentException: Member ... is declared in another module and needs to be imported" + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + TypeDefinition GeneratedCodeClass; + Logger Log; + + Dictionary readFuncs = + new Dictionary(new TypeReferenceComparer()); + + public Readers(AssemblyDefinition assembly, WeaverTypes weaverTypes, TypeDefinition GeneratedCodeClass, Logger Log) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.GeneratedCodeClass = GeneratedCodeClass; + this.Log = Log; + } + + internal void Register(TypeReference dataType, MethodReference methodReference) + { + if (readFuncs.ContainsKey(dataType)) + { + // TODO enable this again later. + // Reader has some obsolete functions that were renamed. + // Don't want weaver warnings for all of them. + //Weaver.Warning($"Registering a Read method for {dataType.FullName} when one already exists", methodReference); + } + + // we need to import type when we Initialize Readers so import here in case it is used anywhere else + TypeReference imported = assembly.MainModule.ImportReference(dataType); + readFuncs[imported] = methodReference; + } + + void RegisterReadFunc(TypeReference typeReference, MethodDefinition newReaderFunc) + { + Register(typeReference, newReaderFunc); + GeneratedCodeClass.Methods.Add(newReaderFunc); + } + + // Finds existing reader for type, if non exists trys to create one + public MethodReference GetReadFunc(TypeReference variable, ref bool WeavingFailed) + { + if (readFuncs.TryGetValue(variable, out MethodReference foundFunc)) + return foundFunc; + + TypeReference importedVariable = assembly.MainModule.ImportReference(variable); + return GenerateReader(importedVariable, ref WeavingFailed); + } + + MethodReference GenerateReader(TypeReference variableReference, ref bool WeavingFailed) + { + // Arrays are special, if we resolve them, we get the element type, + // so the following ifs might choke on it for scriptable objects + // or other objects that require a custom serializer + // thus check if it is an array and skip all the checks. + if (variableReference.IsArray) + { + if (variableReference.IsMultidimensionalArray()) + { + Log.Error($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference); + WeavingFailed = true; + return null; + } + + return GenerateReadCollection(variableReference, variableReference.GetElementType(), nameof(NetworkReaderExtensions.ReadArray), ref WeavingFailed); + } + + TypeDefinition variableDefinition = variableReference.Resolve(); + + // check if the type is completely invalid + if (variableDefinition == null) + { + Log.Error($"{variableReference.Name} is not a supported type", variableReference); + WeavingFailed = true; + return null; + } + else if (variableReference.IsByReference) + { + // error?? + Log.Error($"Cannot pass type {variableReference.Name} by reference", variableReference); + WeavingFailed = true; + return null; + } + + // use existing func for known types + if (variableDefinition.IsEnum) + { + return GenerateEnumReadFunc(variableReference, ref WeavingFailed); + } + else if (variableDefinition.Is(typeof(ArraySegment<>))) + { + return GenerateArraySegmentReadFunc(variableReference, ref WeavingFailed); + } + else if (variableDefinition.Is(typeof(List<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateReadCollection(variableReference, elementType, nameof(NetworkReaderExtensions.ReadList), ref WeavingFailed); + } + else if (variableReference.IsDerivedFrom()) + { + return GetNetworkBehaviourReader(variableReference); + } + + // check if reader generation is applicable on this type + if (variableDefinition.IsDerivedFrom()) + { + Log.Error($"Cannot generate reader for component type {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableReference.Is()) + { + Log.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableReference.Is()) + { + Log.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableDefinition.HasGenericParameters) + { + Log.Error($"Cannot generate reader for generic variable {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableDefinition.IsInterface) + { + Log.Error($"Cannot generate reader for interface {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableDefinition.IsAbstract) + { + Log.Error($"Cannot generate reader for abstract class {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + + return GenerateClassOrStructReadFunction(variableReference, ref WeavingFailed); + } + + MethodReference GetNetworkBehaviourReader(TypeReference variableReference) + { + // uses generic ReadNetworkBehaviour rather than having weaver create one for each NB + MethodReference generic = weaverTypes.readNetworkBehaviourGeneric; + + MethodReference readFunc = generic.MakeGeneric(assembly.MainModule, variableReference); + + // register function so it is added to Reader + // use Register instead of RegisterWriteFunc because this is not a generated function + Register(variableReference, readFunc); + + return readFunc; + } + + MethodDefinition GenerateEnumReadFunc(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition readerFunc = GenerateReaderFunction(variable); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + + worker.Emit(OpCodes.Ldarg_0); + + TypeReference underlyingType = variable.Resolve().GetEnumUnderlyingType(); + MethodReference underlyingFunc = GetReadFunc(underlyingType, ref WeavingFailed); + + worker.Emit(OpCodes.Call, underlyingFunc); + worker.Emit(OpCodes.Ret); + return readerFunc; + } + + MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable, ref bool WeavingFailed) + { + GenericInstanceType genericInstance = (GenericInstanceType)variable; + TypeReference elementType = genericInstance.GenericArguments[0]; + + MethodDefinition readerFunc = GenerateReaderFunction(variable); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + + // $array = reader.Read<[T]>() + ArrayType arrayType = elementType.MakeArrayType(); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, GetReadFunc(arrayType, ref WeavingFailed)); + + // return new ArraySegment($array); + worker.Emit(OpCodes.Newobj, weaverTypes.ArraySegmentConstructorReference.MakeHostInstanceGeneric(assembly.MainModule, genericInstance)); + worker.Emit(OpCodes.Ret); + return readerFunc; + } + + MethodDefinition GenerateReaderFunction(TypeReference variable) + { + string functionName = "_Read_" + variable.FullName; + + // create new reader for this type + MethodDefinition readerFunc = new MethodDefinition(functionName, + MethodAttributes.Public | + MethodAttributes.Static | + MethodAttributes.HideBySig, + variable); + + readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, weaverTypes.Import())); + readerFunc.Body.InitLocals = true; + RegisterReadFunc(variable, readerFunc); + + return readerFunc; + } + + MethodDefinition GenerateReadCollection(TypeReference variable, TypeReference elementType, string readerFunction, ref bool WeavingFailed) + { + MethodDefinition readerFunc = GenerateReaderFunction(variable); + // generate readers for the element + GetReadFunc(elementType, ref WeavingFailed); + + ModuleDefinition module = assembly.MainModule; + TypeReference readerExtensions = module.ImportReference(typeof(NetworkReaderExtensions)); + MethodReference listReader = Resolvers.ResolveMethod(readerExtensions, assembly, Log, readerFunction, ref WeavingFailed); + + GenericInstanceMethod methodRef = new GenericInstanceMethod(listReader); + methodRef.GenericArguments.Add(elementType); + + // generates + // return reader.ReadList(); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + worker.Emit(OpCodes.Ldarg_0); // reader + worker.Emit(OpCodes.Call, methodRef); // Read + + worker.Emit(OpCodes.Ret); + + return readerFunc; + } + + MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition readerFunc = GenerateReaderFunction(variable); + + // create local for return value + readerFunc.Body.Variables.Add(new VariableDefinition(variable)); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + + TypeDefinition td = variable.Resolve(); + + if (!td.IsValueType) + GenerateNullCheck(worker, ref WeavingFailed); + + CreateNew(variable, worker, td, ref WeavingFailed); + ReadAllFields(variable, worker, ref WeavingFailed); + + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ret); + return readerFunc; + } + + void GenerateNullCheck(ILProcessor worker, ref bool WeavingFailed) + { + // if (!reader.ReadBoolean()) { + // return null; + // } + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, GetReadFunc(weaverTypes.Import(), ref WeavingFailed)); + + Instruction labelEmptyArray = worker.Create(OpCodes.Nop); + worker.Emit(OpCodes.Brtrue, labelEmptyArray); + // return null + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ret); + worker.Append(labelEmptyArray); + } + + // Initialize the local variable with a new instance + void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition td, ref bool WeavingFailed) + { + if (variable.IsValueType) + { + // structs are created with Initobj + worker.Emit(OpCodes.Ldloca, 0); + worker.Emit(OpCodes.Initobj, variable); + } + else if (td.IsDerivedFrom()) + { + GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(weaverTypes.ScriptableObjectCreateInstanceMethod); + genericInstanceMethod.GenericArguments.Add(variable); + worker.Emit(OpCodes.Call, genericInstanceMethod); + worker.Emit(OpCodes.Stloc_0); + } + else + { + // classes are created with their constructor + MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable); + if (ctor == null) + { + Log.Error($"{variable.Name} can't be deserialized because it has no default constructor", variable); + WeavingFailed = true; + return; + } + + MethodReference ctorRef = assembly.MainModule.ImportReference(ctor); + + worker.Emit(OpCodes.Newobj, ctorRef); + worker.Emit(OpCodes.Stloc_0); + } + } + + void ReadAllFields(TypeReference variable, ILProcessor worker, ref bool WeavingFailed) + { + foreach (FieldDefinition field in variable.FindAllPublicFields()) + { + // mismatched ldloca/ldloc for struct/class combinations is invalid IL, which causes crash at runtime + OpCode opcode = variable.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc; + worker.Emit(opcode, 0); + MethodReference readFunc = GetReadFunc(field.FieldType, ref WeavingFailed); + if (readFunc != null) + { + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, readFunc); + } + else + { + Log.Error($"{field.Name} has an unsupported type", field); + WeavingFailed = true; + } + FieldReference fieldRef = assembly.MainModule.ImportReference(field); + + worker.Emit(OpCodes.Stfld, fieldRef); + } + } + + // Save a delegate for each one of the readers into Reader.read + internal void InitializeReaders(ILProcessor worker) + { + ModuleDefinition module = assembly.MainModule; + + TypeReference genericReaderClassRef = module.ImportReference(typeof(Reader<>)); + + System.Reflection.FieldInfo fieldInfo = typeof(Reader<>).GetField(nameof(Reader.read)); + FieldReference fieldRef = module.ImportReference(fieldInfo); + TypeReference networkReaderRef = module.ImportReference(typeof(NetworkReader)); + TypeReference funcRef = module.ImportReference(typeof(Func<,>)); + MethodReference funcConstructorRef = module.ImportReference(typeof(Func<,>).GetConstructors()[0]); + + foreach (KeyValuePair kvp in readFuncs) + { + TypeReference targetType = kvp.Key; + MethodReference readFunc = kvp.Value; + + // create a Func delegate + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, readFunc); + GenericInstanceType funcGenericInstance = funcRef.MakeGenericInstanceType(networkReaderRef, targetType); + MethodReference funcConstructorInstance = funcConstructorRef.MakeHostInstanceGeneric(assembly.MainModule, funcGenericInstance); + worker.Emit(OpCodes.Newobj, funcConstructorInstance); + + // save it in Reader.read + GenericInstanceType genericInstance = genericReaderClassRef.MakeGenericInstanceType(targetType); + FieldReference specializedField = fieldRef.SpecializeField(assembly.MainModule, genericInstance); + worker.Emit(OpCodes.Stsfld, specializedField); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs.meta b/Assets/Mirror/Editor/Weaver/Readers.cs.meta new file mode 100644 index 0000000..e119669 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Readers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be40277098a024539bf63d0205cae824 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Resolvers.cs b/Assets/Mirror/Editor/Weaver/Resolvers.cs new file mode 100644 index 0000000..4f96c2c --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Resolvers.cs @@ -0,0 +1,89 @@ +// all the resolve functions for the weaver +// NOTE: these functions should be made extensions, but right now they still +// make heavy use of Weaver.fail and we'd have to check each one's return +// value for null otherwise. +// (original FieldType.Resolve returns null if not found too, so +// exceptions would be a bit inconsistent here) +using Mono.CecilX; + +namespace Mirror.Weaver +{ + public static class Resolvers + { + public static MethodReference ResolveMethod(TypeReference tr, AssemblyDefinition assembly, Logger Log, string name, ref bool WeavingFailed) + { + if (tr == null) + { + Log.Error($"Cannot resolve method {name} without a class"); + WeavingFailed = true; + return null; + } + MethodReference method = ResolveMethod(tr, assembly, Log, m => m.Name == name, ref WeavingFailed); + if (method == null) + { + Log.Error($"Method not found with name {name} in type {tr.Name}", tr); + WeavingFailed = true; + } + return method; + } + + public static MethodReference ResolveMethod(TypeReference t, AssemblyDefinition assembly, Logger Log, System.Func predicate, ref bool WeavingFailed) + { + foreach (MethodDefinition methodRef in t.Resolve().Methods) + { + if (predicate(methodRef)) + { + return assembly.MainModule.ImportReference(methodRef); + } + } + + Log.Error($"Method not found in type {t.Name}", t); + WeavingFailed = true; + return null; + } + + public static MethodReference TryResolveMethodInParents(TypeReference tr, AssemblyDefinition assembly, string name) + { + if (tr == null) + { + return null; + } + foreach (MethodDefinition methodRef in tr.Resolve().Methods) + { + if (methodRef.Name == name) + { + return assembly.MainModule.ImportReference(methodRef); + } + } + + // Could not find the method in this class, try the parent + return TryResolveMethodInParents(tr.Resolve().BaseType, assembly, name); + } + + public static MethodDefinition ResolveDefaultPublicCtor(TypeReference variable) + { + foreach (MethodDefinition methodRef in variable.Resolve().Methods) + { + if (methodRef.Name == ".ctor" && + methodRef.Resolve().IsPublic && + methodRef.Parameters.Count == 0) + { + return methodRef; + } + } + return null; + } + + public static MethodReference ResolveProperty(TypeReference tr, AssemblyDefinition assembly, string name) + { + foreach (PropertyDefinition pd in tr.Resolve().Properties) + { + if (pd.Name == name) + { + return assembly.MainModule.ImportReference(pd.GetMethod); + } + } + return null; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta b/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta new file mode 100644 index 0000000..38680aa --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3039a59c76aec43c797ad66930430367 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs new file mode 100644 index 0000000..e3c31d5 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // Compares TypeReference using FullName + public class TypeReferenceComparer : IEqualityComparer + { + public bool Equals(TypeReference x, TypeReference y) => + x.FullName == y.FullName; + + public int GetHashCode(TypeReference obj) => + obj.FullName.GetHashCode(); + } +} diff --git a/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs.meta b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs.meta new file mode 100644 index 0000000..1aed28f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55eb9eb8794946f4da7ad39788c9920b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef new file mode 100644 index 0000000..4566bb2 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef @@ -0,0 +1,21 @@ +{ + "name": "Unity.Mirror.CodeGen", + "rootNamespace": "", + "references": [ + "Mirror" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": true, + "precompiledReferences": [ + "Mono.CecilX.dll", + "Mono.CecilX.Rocks.dll" + ], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef.meta b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef.meta new file mode 100644 index 0000000..2ee4754 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1d0b9d21c3ff546a4aa32399dfd33474 +AssemblyDefinitionImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs b/Assets/Mirror/Editor/Weaver/Weaver.cs new file mode 100644 index 0000000..67c230a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Weaver.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + internal class Weaver + { + public const string InvokeRpcPrefix = "InvokeUserCode_"; + + // generated code class + public const string GeneratedCodeNamespace = "Mirror"; + public const string GeneratedCodeClassName = "GeneratedNetworkCode"; + TypeDefinition GeneratedCodeClass; + + // for resolving Mirror.dll in ReaderWriterProcessor, we need to know + // Mirror.dll name + public const string MirrorAssemblyName = "Mirror"; + + WeaverTypes weaverTypes; + WeaverLists weaverLists; + IAssemblyResolver Resolver; + AssemblyDefinition CurrentAssembly; + Writers writers; + Readers readers; + bool WeavingFailed; + + // logger functions can be set from the outside. + // for example, Debug.Log or ILPostProcessor Diagnostics log for + // multi threaded logging. + public Logger Log; + + public Weaver(Logger Log) + { + this.Log = Log; + } + + // returns 'true' if modified (=if we did anything) + bool WeaveNetworkBehavior(TypeDefinition td) + { + if (!td.IsClass) + return false; + + if (!td.IsDerivedFrom()) + { + if (td.IsDerivedFrom()) + MonoBehaviourProcessor.Process(Log, td, ref WeavingFailed); + return false; + } + + // process this and base classes from parent to child order + + List behaviourClasses = new List(); + + TypeDefinition parent = td; + while (parent != null) + { + if (parent.Is()) + { + break; + } + + try + { + behaviourClasses.Insert(0, parent); + parent = parent.BaseType.Resolve(); + } + catch (AssemblyResolutionException) + { + // this can happen for plugins. + //Console.WriteLine("AssemblyResolutionException: "+ ex.ToString()); + break; + } + } + + bool modified = false; + foreach (TypeDefinition behaviour in behaviourClasses) + { + modified |= new NetworkBehaviourProcessor(CurrentAssembly, weaverTypes, weaverLists, writers, readers, Log, behaviour).Process(ref WeavingFailed); + } + return modified; + } + + bool WeaveModule(ModuleDefinition moduleDefinition) + { + bool modified = false; + + Stopwatch watch = Stopwatch.StartNew(); + watch.Start(); + + foreach (TypeDefinition td in moduleDefinition.Types) + { + if (td.IsClass && td.BaseType.CanBeResolved()) + { + modified |= WeaveNetworkBehavior(td); + modified |= ServerClientAttributeProcessor.Process(weaverTypes, Log, td, ref WeavingFailed); + } + } + + watch.Stop(); + Console.WriteLine("Weave behaviours and messages took " + watch.ElapsedMilliseconds + " milliseconds"); + + return modified; + } + + void CreateGeneratedCodeClass() + { + // create "Mirror.GeneratedNetworkCode" class which holds all + // Readers and Writers + GeneratedCodeClass = new TypeDefinition(GeneratedCodeNamespace, GeneratedCodeClassName, + TypeAttributes.BeforeFieldInit | TypeAttributes.Class | TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.Abstract | TypeAttributes.Sealed, + weaverTypes.Import()); + } + + // Weave takes an AssemblyDefinition to be compatible with both old and + // new weavers: + // * old takes a filepath, new takes a in-memory byte[] + // * old uses DefaultAssemblyResolver with added dependencies paths, + // new uses ...? + // + // => assembly: the one we are currently weaving (MyGame.dll) + // => resolver: useful in case we need to resolve any of the assembly's + // assembly.MainModule.AssemblyReferences. + // -> we can resolve ANY of them given that the resolver + // works properly (need custom one for ILPostProcessor) + // -> IMPORTANT: .Resolve() takes an AssemblyNameReference. + // those from assembly.MainModule.AssemblyReferences are + // guaranteed to be resolve-able. + // Parsing from a string for Library/.../Mirror.dll + // would not be guaranteed to be resolve-able because + // for ILPostProcessor we can't assume where Mirror.dll + // is etc. + public bool Weave(AssemblyDefinition assembly, IAssemblyResolver resolver, out bool modified) + { + WeavingFailed = false; + modified = false; + try + { + Resolver = resolver; + CurrentAssembly = assembly; + + // fix "No writer found for ..." error + // https://github.com/vis2k/Mirror/issues/2579 + // -> when restarting Unity, weaver would try to weave a DLL + // again + // -> resulting in two GeneratedNetworkCode classes (see ILSpy) + // -> the second one wouldn't have all the writer types setup + if (CurrentAssembly.MainModule.ContainsClass(GeneratedCodeNamespace, GeneratedCodeClassName)) + { + //Log.Warning($"Weaver: skipping {CurrentAssembly.Name} because already weaved"); + return true; + } + + weaverTypes = new WeaverTypes(CurrentAssembly, Log, ref WeavingFailed); + + // weaverTypes are needed for CreateGeneratedCodeClass + CreateGeneratedCodeClass(); + + // WeaverList depends on WeaverTypes setup because it uses Import + weaverLists = new WeaverLists(); + + // initialize readers & writers with this assembly. + // we need to do this in every Process() call. + // otherwise we would get + // "System.ArgumentException: Member ... is declared in another module and needs to be imported" + // errors when still using the previous module's reader/writer funcs. + writers = new Writers(CurrentAssembly, weaverTypes, GeneratedCodeClass, Log); + readers = new Readers(CurrentAssembly, weaverTypes, GeneratedCodeClass, Log); + + Stopwatch rwstopwatch = Stopwatch.StartNew(); + // Need to track modified from ReaderWriterProcessor too because it could find custom read/write functions or create functions for NetworkMessages + modified = ReaderWriterProcessor.Process(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed); + rwstopwatch.Stop(); + Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds"); + + ModuleDefinition moduleDefinition = CurrentAssembly.MainModule; + Console.WriteLine($"Script Module: {moduleDefinition.Name}"); + + modified |= WeaveModule(moduleDefinition); + + if (WeavingFailed) + { + return false; + } + + if (modified) + { + PropertySiteProcessor.Process(moduleDefinition, weaverLists); + + // add class that holds read/write functions + moduleDefinition.Types.Add(GeneratedCodeClass); + + ReaderWriterProcessor.InitializeReaderAndWriters(CurrentAssembly, weaverTypes, writers, readers, GeneratedCodeClass); + + // DO NOT WRITE here. + // CompilationFinishedHook writes to the file. + // ILPostProcessor writes to in-memory assembly. + // it depends on the caller. + //CurrentAssembly.Write(new WriterParameters{ WriteSymbols = true }); + } + + return true; + } + catch (Exception e) + { + Log.Error("Exception :" + e); + WeavingFailed = true; + return false; + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs.meta b/Assets/Mirror/Editor/Weaver/Weaver.cs.meta new file mode 100644 index 0000000..ec2cb3e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Weaver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de160f52931054064852f2afd7e7a86f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs new file mode 100644 index 0000000..efedd27 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs @@ -0,0 +1,26 @@ +using System; +using System.Runtime.Serialization; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + [Serializable] + public abstract class WeaverException : Exception + { + public MemberReference MemberReference { get; } + + protected WeaverException(string message, MemberReference member) : base(message) + { + MemberReference = member; + } + + protected WeaverException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) {} + } + + [Serializable] + public class GenerateWriterException : WeaverException + { + public GenerateWriterException(string message, MemberReference member) : base(message, member) {} + protected GenerateWriterException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) {} + } +} diff --git a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta new file mode 100644 index 0000000..4c11527 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8aaaf6193bad7424492677f8e81f1b30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Editor/Weaver/WeaverLists.cs b/Assets/Mirror/Editor/Weaver/WeaverLists.cs new file mode 100644 index 0000000..7149638 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverLists.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // This data is flushed each time - if we are run multiple times in the same process/domain + public class WeaverLists + { + // setter functions that replace [SyncVar] member variable references. dict + public Dictionary replacementSetterProperties = + new Dictionary(); + + // getter functions that replace [SyncVar] member variable references. dict + public Dictionary replacementGetterProperties = + new Dictionary(); + + // amount of SyncVars per class. dict + public Dictionary numSyncVars = new Dictionary(); + + public int GetSyncVarStart(string className) + { + return numSyncVars.ContainsKey(className) + ? numSyncVars[className] + : 0; + } + + public void SetNumSyncVars(string className, int num) + { + numSyncVars[className] = num; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/WeaverLists.cs.meta b/Assets/Mirror/Editor/Weaver/WeaverLists.cs.meta new file mode 100644 index 0000000..e59222e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverLists.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6905230c3c4c4e158760065a93380e83 +timeCreated: 1629348618 diff --git a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs new file mode 100644 index 0000000..fdbc93e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs @@ -0,0 +1,163 @@ +using System; +using Mono.CecilX; +using UnityEditor; +using UnityEngine; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public class WeaverTypes + { + public MethodReference ScriptableObjectCreateInstanceMethod; + + public MethodReference NetworkBehaviourDirtyBitsReference; + public MethodReference GetPooledWriterReference; + public MethodReference RecycleWriterReference; + + public MethodReference ReadyConnectionReference; + + public MethodReference CmdDelegateConstructor; + + public MethodReference NetworkServerGetActive; + public MethodReference NetworkServerGetLocalClientActive; + public MethodReference NetworkClientGetActive; + + // custom attribute types + public MethodReference InitSyncObjectReference; + + // array segment + public MethodReference ArraySegmentConstructorReference; + + // syncvar + public MethodReference syncVarEqualReference; + public MethodReference syncVarNetworkIdentityEqualReference; + public MethodReference syncVarGameObjectEqualReference; + public MethodReference setSyncVarReference; + public MethodReference setSyncVarHookGuard; + public MethodReference getSyncVarHookGuard; + public MethodReference setSyncVarGameObjectReference; + public MethodReference getSyncVarGameObjectReference; + public MethodReference setSyncVarNetworkIdentityReference; + public MethodReference getSyncVarNetworkIdentityReference; + public MethodReference syncVarNetworkBehaviourEqualReference; + public MethodReference setSyncVarNetworkBehaviourReference; + public MethodReference getSyncVarNetworkBehaviourReference; + public MethodReference registerCommandDelegateReference; + public MethodReference registerRpcDelegateReference; + public MethodReference getTypeFromHandleReference; + public MethodReference logErrorReference; + public MethodReference logWarningReference; + public MethodReference sendCommandInternal; + public MethodReference sendRpcInternal; + public MethodReference sendTargetRpcInternal; + + public MethodReference readNetworkBehaviourGeneric; + + // attributes + public TypeDefinition initializeOnLoadMethodAttribute; + public TypeDefinition runtimeInitializeOnLoadMethodAttribute; + + AssemblyDefinition assembly; + + public TypeReference Import() => Import(typeof(T)); + + public TypeReference Import(Type t) => assembly.MainModule.ImportReference(t); + + // constructor resolves the types and stores them in fields + public WeaverTypes(AssemblyDefinition assembly, Logger Log, ref bool WeavingFailed) + { + // system types + this.assembly = assembly; + + TypeReference ArraySegmentType = Import(typeof(ArraySegment<>)); + ArraySegmentConstructorReference = Resolvers.ResolveMethod(ArraySegmentType, assembly, Log, ".ctor", ref WeavingFailed); + + TypeReference NetworkServerType = Import(typeof(NetworkServer)); + NetworkServerGetActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_active", ref WeavingFailed); + NetworkServerGetLocalClientActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_localClientActive", ref WeavingFailed); + TypeReference NetworkClientType = Import(typeof(NetworkClient)); + NetworkClientGetActive = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_active", ref WeavingFailed); + + TypeReference cmdDelegateReference = Import(); + CmdDelegateConstructor = Resolvers.ResolveMethod(cmdDelegateReference, assembly, Log, ".ctor", ref WeavingFailed); + + TypeReference NetworkBehaviourType = Import(); + TypeReference RemoteCallHelperType = Import(typeof(RemoteCalls.RemoteCallHelper)); + + TypeReference ScriptableObjectType = Import(); + + ScriptableObjectCreateInstanceMethod = Resolvers.ResolveMethod( + ScriptableObjectType, assembly, Log, + md => md.Name == "CreateInstance" && md.HasGenericParameters, + ref WeavingFailed); + + NetworkBehaviourDirtyBitsReference = Resolvers.ResolveProperty(NetworkBehaviourType, assembly, "syncVarDirtyBits"); + TypeReference NetworkWriterPoolType = Import(typeof(NetworkWriterPool)); + GetPooledWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "GetWriter", ref WeavingFailed); + RecycleWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Recycle", ref WeavingFailed); + + ReadyConnectionReference = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_readyConnection", ref WeavingFailed); + + syncVarEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarEqual", ref WeavingFailed); + syncVarNetworkIdentityEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarNetworkIdentityEqual", ref WeavingFailed); + syncVarGameObjectEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarGameObjectEqual", ref WeavingFailed); + setSyncVarReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVar", ref WeavingFailed); + setSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "setSyncVarHookGuard", ref WeavingFailed); + getSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "getSyncVarHookGuard", ref WeavingFailed); + + setSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVarGameObject", ref WeavingFailed); + getSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarGameObject", ref WeavingFailed); + setSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVarNetworkIdentity", ref WeavingFailed); + getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkIdentity", ref WeavingFailed); + syncVarNetworkBehaviourEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarNetworkBehaviourEqual", ref WeavingFailed); + setSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVarNetworkBehaviour", ref WeavingFailed); + getSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkBehaviour", ref WeavingFailed); + + registerCommandDelegateReference = Resolvers.ResolveMethod(RemoteCallHelperType, assembly, Log, "RegisterCommandDelegate", ref WeavingFailed); + registerRpcDelegateReference = Resolvers.ResolveMethod(RemoteCallHelperType, assembly, Log, "RegisterRpcDelegate", ref WeavingFailed); + + TypeReference unityDebug = Import(typeof(UnityEngine.Debug)); + // these have multiple methods with same name, so need to check parameters too + logErrorReference = Resolvers.ResolveMethod(unityDebug, assembly, Log, md => + md.Name == "LogError" && + md.Parameters.Count == 1 && + md.Parameters[0].ParameterType.FullName == typeof(object).FullName, + ref WeavingFailed); + + logWarningReference = Resolvers.ResolveMethod(unityDebug, assembly, Log, md => + md.Name == "LogWarning" && + md.Parameters.Count == 1 && + md.Parameters[0].ParameterType.FullName == typeof(object).FullName, + ref WeavingFailed); + + TypeReference typeType = Import(typeof(Type)); + getTypeFromHandleReference = Resolvers.ResolveMethod(typeType, assembly, Log, "GetTypeFromHandle", ref WeavingFailed); + sendCommandInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendCommandInternal", ref WeavingFailed); + sendRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendRPCInternal", ref WeavingFailed); + sendTargetRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendTargetRPCInternal", ref WeavingFailed); + + InitSyncObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "InitSyncObject", ref WeavingFailed); + + TypeReference readerExtensions = Import(typeof(NetworkReaderExtensions)); + readNetworkBehaviourGeneric = Resolvers.ResolveMethod(readerExtensions, assembly, Log, (md => + { + return md.Name == nameof(NetworkReaderExtensions.ReadNetworkBehaviour) && + md.HasGenericParameters; + }), + ref WeavingFailed); + + // [InitializeOnLoadMethod] + // 'UnityEditor' is not available in builds. + // we can only import this attribute if we are in an Editor assembly. + if (Helpers.IsEditorAssembly(assembly)) + { + TypeReference initializeOnLoadMethodAttributeRef = Import(typeof(InitializeOnLoadMethodAttribute)); + initializeOnLoadMethodAttribute = initializeOnLoadMethodAttributeRef.Resolve(); + } + + // [RuntimeInitializeOnLoadMethod] + TypeReference runtimeInitializeOnLoadMethodAttributeRef = Import(typeof(RuntimeInitializeOnLoadMethodAttribute)); + runtimeInitializeOnLoadMethodAttribute = runtimeInitializeOnLoadMethodAttributeRef.Resolve(); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta new file mode 100644 index 0000000..e15e589 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2585961bf7fe4c10a9143f4087efdf6f +timeCreated: 1596486854 diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs b/Assets/Mirror/Editor/Weaver/Writers.cs new file mode 100644 index 0000000..85fddc3 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Writers.cs @@ -0,0 +1,341 @@ +using System; +using System.Collections.Generic; +using Mono.CecilX; +using Mono.CecilX.Cil; +// to use Mono.CecilX.Rocks here, we need to 'override references' in the +// Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX.Rocks. +// otherwise we get an unknown import exception. +using Mono.CecilX.Rocks; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public class Writers + { + // Writers are only for this assembly. + // can't be used from another assembly, otherwise we will get: + // "System.ArgumentException: Member ... is declared in another module and needs to be imported" + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + TypeDefinition GeneratedCodeClass; + Logger Log; + + Dictionary writeFuncs = + new Dictionary(new TypeReferenceComparer()); + + public Writers(AssemblyDefinition assembly, WeaverTypes weaverTypes, TypeDefinition GeneratedCodeClass, Logger Log) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.GeneratedCodeClass = GeneratedCodeClass; + this.Log = Log; + } + + public void Register(TypeReference dataType, MethodReference methodReference) + { + if (writeFuncs.ContainsKey(dataType)) + { + // TODO enable this again later. + // Writer has some obsolete functions that were renamed. + // Don't want weaver warnings for all of them. + //Weaver.Warning($"Registering a Write method for {dataType.FullName} when one already exists", methodReference); + } + + // we need to import type when we Initialize Writers so import here in case it is used anywhere else + TypeReference imported = assembly.MainModule.ImportReference(dataType); + writeFuncs[imported] = methodReference; + } + + void RegisterWriteFunc(TypeReference typeReference, MethodDefinition newWriterFunc) + { + Register(typeReference, newWriterFunc); + GeneratedCodeClass.Methods.Add(newWriterFunc); + } + + // Finds existing writer for type, if non exists trys to create one + public MethodReference GetWriteFunc(TypeReference variable, ref bool WeavingFailed) + { + if (writeFuncs.TryGetValue(variable, out MethodReference foundFunc)) + return foundFunc; + + // this try/catch will be removed in future PR and make `GetWriteFunc` throw instead + try + { + TypeReference importedVariable = assembly.MainModule.ImportReference(variable); + return GenerateWriter(importedVariable, ref WeavingFailed); + } + catch (GenerateWriterException e) + { + Log.Error(e.Message, e.MemberReference); + WeavingFailed = true; + return null; + } + } + + //Throws GenerateWriterException when writer could not be generated for type + MethodReference GenerateWriter(TypeReference variableReference, ref bool WeavingFailed) + { + if (variableReference.IsByReference) + { + throw new GenerateWriterException($"Cannot pass {variableReference.Name} by reference", variableReference); + } + + // Arrays are special, if we resolve them, we get the element type, + // e.g. int[] resolves to int + // therefore process this before checks below + if (variableReference.IsArray) + { + if (variableReference.IsMultidimensionalArray()) + { + throw new GenerateWriterException($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference); + } + TypeReference elementType = variableReference.GetElementType(); + return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArray), ref WeavingFailed); + } + + if (variableReference.Resolve()?.IsEnum ?? false) + { + // serialize enum as their base type + return GenerateEnumWriteFunc(variableReference, ref WeavingFailed); + } + + // check for collections + if (variableReference.Is(typeof(ArraySegment<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArraySegment), ref WeavingFailed); + } + if (variableReference.Is(typeof(List<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteList), ref WeavingFailed); + } + + if (variableReference.IsDerivedFrom()) + { + return GetNetworkBehaviourWriter(variableReference); + } + + // check for invalid types + TypeDefinition variableDefinition = variableReference.Resolve(); + if (variableDefinition == null) + { + throw new GenerateWriterException($"{variableReference.Name} is not a supported type. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.IsDerivedFrom()) + { + throw new GenerateWriterException($"Cannot generate writer for component type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableReference.Is()) + { + throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableReference.Is()) + { + throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.HasGenericParameters) + { + throw new GenerateWriterException($"Cannot generate writer for generic type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.IsInterface) + { + throw new GenerateWriterException($"Cannot generate writer for interface {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.IsAbstract) + { + throw new GenerateWriterException($"Cannot generate writer for abstract class {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + + // generate writer for class/struct + return GenerateClassOrStructWriterFunction(variableReference, ref WeavingFailed); + } + + MethodReference GetNetworkBehaviourWriter(TypeReference variableReference) + { + // all NetworkBehaviours can use the same write function + if (writeFuncs.TryGetValue(weaverTypes.Import(), out MethodReference func)) + { + // register function so it is added to writer + // use Register instead of RegisterWriteFunc because this is not a generated function + Register(variableReference, func); + + return func; + } + else + { + // this exception only happens if mirror is missing the WriteNetworkBehaviour method + throw new MissingMethodException($"Could not find writer for NetworkBehaviour"); + } + } + + MethodDefinition GenerateEnumWriteFunc(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition writerFunc = GenerateWriterFunc(variable); + + ILProcessor worker = writerFunc.Body.GetILProcessor(); + + MethodReference underlyingWriter = GetWriteFunc(variable.Resolve().GetEnumUnderlyingType(), ref WeavingFailed); + + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Call, underlyingWriter); + + worker.Emit(OpCodes.Ret); + return writerFunc; + } + + MethodDefinition GenerateWriterFunc(TypeReference variable) + { + string functionName = "_Write_" + variable.FullName; + // create new writer for this type + MethodDefinition writerFunc = new MethodDefinition(functionName, + MethodAttributes.Public | + MethodAttributes.Static | + MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, weaverTypes.Import())); + writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, variable)); + writerFunc.Body.InitLocals = true; + + RegisterWriteFunc(variable, writerFunc); + return writerFunc; + } + + MethodDefinition GenerateClassOrStructWriterFunction(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition writerFunc = GenerateWriterFunc(variable); + + ILProcessor worker = writerFunc.Body.GetILProcessor(); + + if (!variable.Resolve().IsValueType) + WriteNullCheck(worker, ref WeavingFailed); + + if (!WriteAllFields(variable, worker, ref WeavingFailed)) + return null; + + worker.Emit(OpCodes.Ret); + return writerFunc; + } + + void WriteNullCheck(ILProcessor worker, ref bool WeavingFailed) + { + // if (value == null) + // { + // writer.WriteBoolean(false); + // return; + // } + // + + Instruction labelNotNull = worker.Create(OpCodes.Nop); + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Brtrue, labelNotNull); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldc_I4_0); + worker.Emit(OpCodes.Call, GetWriteFunc(weaverTypes.Import(), ref WeavingFailed)); + worker.Emit(OpCodes.Ret); + worker.Append(labelNotNull); + + // write.WriteBoolean(true); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldc_I4_1); + worker.Emit(OpCodes.Call, GetWriteFunc(weaverTypes.Import(), ref WeavingFailed)); + } + + // Find all fields in type and write them + bool WriteAllFields(TypeReference variable, ILProcessor worker, ref bool WeavingFailed) + { + uint fields = 0; + foreach (FieldDefinition field in variable.FindAllPublicFields()) + { + MethodReference writeFunc = GetWriteFunc(field.FieldType, ref WeavingFailed); + // need this null check till later PR when GetWriteFunc throws exception instead + if (writeFunc == null) { return false; } + + FieldReference fieldRef = assembly.MainModule.ImportReference(field); + + fields++; + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Ldfld, fieldRef); + worker.Emit(OpCodes.Call, writeFunc); + } + + return true; + } + + MethodDefinition GenerateCollectionWriter(TypeReference variable, TypeReference elementType, string writerFunction, ref bool WeavingFailed) + { + + MethodDefinition writerFunc = GenerateWriterFunc(variable); + + MethodReference elementWriteFunc = GetWriteFunc(elementType, ref WeavingFailed); + MethodReference intWriterFunc = GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + + // need this null check till later PR when GetWriteFunc throws exception instead + if (elementWriteFunc == null) + { + Log.Error($"Cannot generate writer for {variable}. Use a supported type or provide a custom writer", variable); + WeavingFailed = true; + return writerFunc; + } + + ModuleDefinition module = assembly.MainModule; + TypeReference readerExtensions = module.ImportReference(typeof(NetworkWriterExtensions)); + MethodReference collectionWriter = Resolvers.ResolveMethod(readerExtensions, assembly, Log, writerFunction, ref WeavingFailed); + + GenericInstanceMethod methodRef = new GenericInstanceMethod(collectionWriter); + methodRef.GenericArguments.Add(elementType); + + // generates + // reader.WriteArray(array); + + ILProcessor worker = writerFunc.Body.GetILProcessor(); + worker.Emit(OpCodes.Ldarg_0); // writer + worker.Emit(OpCodes.Ldarg_1); // collection + + worker.Emit(OpCodes.Call, methodRef); // WriteArray + + worker.Emit(OpCodes.Ret); + + return writerFunc; + } + + // Save a delegate for each one of the writers into Writer{T}.write + internal void InitializeWriters(ILProcessor worker) + { + ModuleDefinition module = assembly.MainModule; + + TypeReference genericWriterClassRef = module.ImportReference(typeof(Writer<>)); + + System.Reflection.FieldInfo fieldInfo = typeof(Writer<>).GetField(nameof(Writer.write)); + FieldReference fieldRef = module.ImportReference(fieldInfo); + TypeReference networkWriterRef = module.ImportReference(typeof(NetworkWriter)); + TypeReference actionRef = module.ImportReference(typeof(Action<,>)); + MethodReference actionConstructorRef = module.ImportReference(typeof(Action<,>).GetConstructors()[0]); + + foreach (KeyValuePair kvp in writeFuncs) + { + TypeReference targetType = kvp.Key; + MethodReference writeFunc = kvp.Value; + + // create a Action delegate + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, writeFunc); + GenericInstanceType actionGenericInstance = actionRef.MakeGenericInstanceType(networkWriterRef, targetType); + MethodReference actionRefInstance = actionConstructorRef.MakeHostInstanceGeneric(assembly.MainModule, actionGenericInstance); + worker.Emit(OpCodes.Newobj, actionRefInstance); + + // save it in Writer.write + GenericInstanceType genericInstance = genericWriterClassRef.MakeGenericInstanceType(targetType); + FieldReference specializedField = fieldRef.SpecializeField(assembly.MainModule, genericInstance); + worker.Emit(OpCodes.Stsfld, specializedField); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs.meta b/Assets/Mirror/Editor/Weaver/Writers.cs.meta new file mode 100644 index 0000000..a2f931f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Writers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a90060ad76ea044aba613080dd922709 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples.meta b/Assets/Mirror/Examples.meta new file mode 100644 index 0000000..f02aca2 --- /dev/null +++ b/Assets/Mirror/Examples.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a08b1f591326642d1b140fc818c9c6b1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes.meta b/Assets/Mirror/Examples/AdditiveScenes.meta new file mode 100644 index 0000000..518df51 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b84b2a39b3027c747b21ad714a439214 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers.meta b/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers.meta new file mode 100644 index 0000000..ec709da --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4969918300bfa9a4a8c733975df74016 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller b/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller new file mode 100644 index 0000000..5a7f506 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller @@ -0,0 +1,156 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Tank + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: Fire + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 1107206089488630588} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1101 &1101845105868117086 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Fire + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1102477577393645330} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.45454544 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1101 &1101857281332299900 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: [] + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1102845660080023070} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.058695674 + m_TransitionOffset: 0.41739127 + m_ExitTime: 0.9060869 + m_HasExitTime: 1 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1102 &1102477577393645330 +AnimatorState: + serializedVersion: 5 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Recon_Tank_Rig|Shoot + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 1101857281332299900} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400006, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1102 &1102845660080023070 +AnimatorState: + serializedVersion: 5 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Recon_Tank_Rig|Idle + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 1101845105868117086} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400004, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1107 &1107206089488630588 +AnimatorStateMachine: + serializedVersion: 5 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 1102845660080023070} + m_Position: {x: 132, y: 300, z: 0} + - serializedVersion: 1 + m_State: {fileID: 1102477577393645330} + m_Position: {x: 360, y: 432, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 1102845660080023070} diff --git a/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller.meta b/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller.meta new file mode 100644 index 0000000..8ad6c71 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0dbc8b2f2711a54f9b7ed1358a4c6af +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials.meta new file mode 100644 index 0000000..ebd0798 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ef7a74859259a546b73ed820e449ae8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat new file mode 100644 index 0000000..46d3f50 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Capsule + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0.3 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0.07727194, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat.meta new file mode 100644 index 0000000..9089181 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ec90781e3720544da7fc86055e6cbe6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat new file mode 100644 index 0000000..8245804 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Cube + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0.93989503, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat.meta new file mode 100644 index 0000000..a8af065 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d5f3015968dad04780bf9d2113cc772 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat new file mode 100644 index 0000000..a80edc0 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Cylinder + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0.5943396, b: 0.054526776, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat.meta new file mode 100644 index 0000000..d77fac5 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 439a10ee8f8d14040be9003239449741 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat new file mode 100644 index 0000000..a394fe1 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Player + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat.meta new file mode 100644 index 0000000..d0b34f0 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 792117fe9a386a8489e8010bec746339 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat new file mode 100644 index 0000000..526e91e --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Quad + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.8207547, g: 0.8207547, b: 0.8207547, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat.meta new file mode 100644 index 0000000..cc7fb6e --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6eb3f3ba66756364d8b94e662e7e8af5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat new file mode 100644 index 0000000..e29e5b9 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Shelter + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.8018868, g: 0.52244145, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat.meta new file mode 100644 index 0000000..dc0786b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aef230244d219314fb8453f0365b8176 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat new file mode 100644 index 0000000..329d875 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Sphere + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.9716981, g: 0, b: 0.77970594, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat.meta new file mode 100644 index 0000000..8556d78 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 58936713efca1ec488624ee297b5d687 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat b/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat new file mode 100644 index 0000000..462e16d --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat @@ -0,0 +1,78 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Zone + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 0.039215688} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat.meta b/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat.meta new file mode 100644 index 0000000..88474b2 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a7c679cf124f7ae46a0291ea35848554 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs.meta new file mode 100644 index 0000000..ff4ccaf --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2be4f78570b2a1e4cae84466d35d606c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab new file mode 100644 index 0000000..301aef4 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab @@ -0,0 +1,163 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &954781580484189887 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6907979021268419569} + - component: {fileID: 6000350177490294528} + - component: {fileID: 6206275723814903389} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6907979021268419569 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 954781580484189887} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1076878374699499735} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6000350177490294528 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 954781580484189887} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6206275723814903389 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 954781580484189887} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 3ec90781e3720544da7fc86055e6cbe6, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &1076878374699499732 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1076878374699499735} + - component: {fileID: 2648107611936813301} + - component: {fileID: 5697694911122891659} + - component: {fileID: 1076878374699499734} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1076878374699499735 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1076878374699499732} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 20, y: 1, z: -20} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6907979021268419569} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2648107611936813301 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1076878374699499732} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + m_AssetId: +--- !u!114 &5697694911122891659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1076878374699499732} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + visRange: 5 + visUpdateInterval: 0.1 + checkMethod: 0 + forceHidden: 0 + castLayers: + serializedVersion: 2 + m_Bits: 256 +--- !u!136 &1076878374699499734 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1076878374699499732} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab.meta new file mode 100644 index 0000000..31b37d0 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e1971f4a8c7661546bc509b44bd91b80 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab new file mode 100644 index 0000000..83433af --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab @@ -0,0 +1,162 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4522555068077302800 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 375242947413242802} + - component: {fileID: 6760112923780649517} + - component: {fileID: 2011925250954866551} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &375242947413242802 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4522555068077302800} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 2, y: 2, z: 2} + m_Children: [] + m_Father: {fileID: 5623359707189648426} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6760112923780649517 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4522555068077302800} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2011925250954866551 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4522555068077302800} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1d5f3015968dad04780bf9d2113cc772, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &5623359707189648430 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5623359707189648426} + - component: {fileID: 5623359707189648404} + - component: {fileID: 5623359707189648405} + - component: {fileID: 963943828455949898} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &5623359707189648426 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5623359707189648430} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: 2} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 375242947413242802} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5623359707189648404 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5623359707189648430} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + m_AssetId: +--- !u!114 &5623359707189648405 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5623359707189648430} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + visRange: 5 + visUpdateInterval: 0.1 + checkMethod: 0 + forceHidden: 0 + castLayers: + serializedVersion: 2 + m_Bits: 256 +--- !u!65 &963943828455949898 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5623359707189648430} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 2, y: 2, z: 2} + m_Center: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab.meta new file mode 100644 index 0000000..913306b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4ff300cf6bb3c6342a9552c4f18788c8 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab new file mode 100644 index 0000000..57a3e41 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab @@ -0,0 +1,163 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6852530814182375312 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6852530814182375316} + - component: {fileID: 6852530814182375318} + - component: {fileID: 6852530814182375317} + - component: {fileID: 6852530814182375313} + m_Layer: 0 + m_Name: Cylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &6852530814182375316 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6852530814182375312} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2, y: 1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5318406868242510088} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6852530814182375318 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6852530814182375312} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + m_AssetId: +--- !u!114 &6852530814182375317 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6852530814182375312} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + visRange: 5 + visUpdateInterval: 0.1 + checkMethod: 0 + forceHidden: 0 + castLayers: + serializedVersion: 2 + m_Bits: 256 +--- !u!136 &6852530814182375313 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6852530814182375312} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &7516264595703881855 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5318406868242510088} + - component: {fileID: 5287042839255522751} + - component: {fileID: 8493465729119828566} + m_Layer: 0 + m_Name: Cylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5318406868242510088 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7516264595703881855} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6852530814182375316} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &5287042839255522751 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7516264595703881855} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8493465729119828566 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7516264595703881855} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 439a10ee8f8d14040be9003239449741, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab.meta new file mode 100644 index 0000000..391948a --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 12a4c14e672c00b4b840f937d824b890 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab new file mode 100644 index 0000000..5f9117d --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab @@ -0,0 +1,327 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4415124803507263412 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9057824595171805708} + - component: {fileID: 662729490405160656} + - component: {fileID: 3624570427921084598} + m_Layer: 8 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9057824595171805708 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4415124803507263412} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3254954141432383832} + m_Father: {fileID: 5328458565928408179} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &662729490405160656 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4415124803507263412} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3624570427921084598 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4415124803507263412} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 792117fe9a386a8489e8010bec746339, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &5815001218983416211 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3254954141432383832} + - component: {fileID: 1800893346221236401} + - component: {fileID: 136369082707552984} + m_Layer: 8 + m_Name: Visor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3254954141432383832 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5815001218983416211} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.39999998, z: 0.5} + m_LocalScale: {x: 0.5, y: 0.1, z: 0.2} + m_Children: [] + m_Father: {fileID: 9057824595171805708} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1800893346221236401 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5815001218983416211} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &136369082707552984 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5815001218983416211} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &8872462076811691049 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5328458565928408179} + - component: {fileID: 8537344390966522168} + - component: {fileID: 887491563423388292} + - component: {fileID: 8993127209816276930} + - component: {fileID: 1143206540915927667} + - component: {fileID: 3175779197224890082} + - component: {fileID: 8704659178864205755} + - component: {fileID: 3086414693581178039} + m_Layer: 8 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5328458565928408179 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.08, z: -20} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 9057824595171805708} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8537344390966522168 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: + hasSpawned: 0 +--- !u!114 &887491563423388292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0 + clientAuthority: 1 + localPositionSensitivity: 0.01 + localRotationSensitivity: 0.01 + localScaleSensitivity: 0.01 + compressRotation: 0 + interpolateScale: 0 + syncScale: 0 +--- !u!143 &8993127209816276930 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.08 + m_MinMoveDistance: 0.001 + m_Center: {x: 0, y: 0, z: 0} +--- !u!136 &1143206540915927667 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 1 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &3175779197224890082 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &8704659178864205755 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e8f68561248aaca4fb96847ce24742ee, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 8993127209816276930} + moveSpeed: 8 + turnSensitivity: 5 + maxTurnSpeed: 150 + horizontal: 0 + vertical: 0 + turn: 0 + jumpSpeed: 0 + isGrounded: 1 + isFalling: 0 + velocity: {x: 0, y: 0, z: 0} +--- !u!114 &3086414693581178039 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 42d1f80407105ee4f960f0b51e89452d, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..7d6d9c0 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a5bdca0a2315d43499be7dcef473fbc7 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab new file mode 100644 index 0000000..0384f0d --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab @@ -0,0 +1,162 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &855244094988030905 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 855244094988030909} + - component: {fileID: 855244094988030911} + - component: {fileID: 855244094988030908} + - component: {fileID: 855244094988030904} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &855244094988030909 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 855244094988030905} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2, y: 1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1367021456138387611} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &855244094988030911 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 855244094988030905} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + m_AssetId: +--- !u!114 &855244094988030908 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 855244094988030905} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + visRange: 5 + visUpdateInterval: 0.1 + checkMethod: 0 + forceHidden: 0 + castLayers: + serializedVersion: 2 + m_Bits: 256 +--- !u!135 &855244094988030904 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 855244094988030905} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &1963619543076261731 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1367021456138387611} + - component: {fileID: 2288322405747719638} + - component: {fileID: 5301170368275118189} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1367021456138387611 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1963619543076261731} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 2, y: 2, z: 2} + m_Children: [] + m_Father: {fileID: 855244094988030909} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2288322405747719638 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1963619543076261731} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &5301170368275118189 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1963619543076261731} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 58936713efca1ec488624ee297b5d687, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab.meta new file mode 100644 index 0000000..bfe2367 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f6d08eb9a8e35d84fa30a7e3ae64181a +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab new file mode 100644 index 0000000..560c37c --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab @@ -0,0 +1,599 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &160176457 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 160176456} + - component: {fileID: 160176459} + - component: {fileID: 160176458} + - component: {fileID: 160176461} + - component: {fileID: 160176460} + - component: {fileID: 160176462} + m_Layer: 0 + m_Name: Tank + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &160176456 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160176457} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -20, y: 0, z: -20} + m_LocalScale: {x: 5, y: 5, z: 5} + m_Children: + - {fileID: 3234001708628876000} + - {fileID: 1042389410631263445} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &160176459 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160176457} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + m_AssetId: +--- !u!114 &160176458 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160176457} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + visRange: 10 + visUpdateInterval: 0.1 + checkMethod: 0 + forceHidden: 0 + castLayers: + serializedVersion: 2 + m_Bits: 256 +--- !u!114 &160176461 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160176457} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7f6f3bf89aa97405989c802ba270f815, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + clientAuthority: 0 + animator: {fileID: 160176460} +--- !u!95 &160176460 +Animator: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160176457} + m_Enabled: 1 + m_Avatar: {fileID: 9000000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_Controller: {fileID: 9100000, guid: e0dbc8b2f2711a54f9b7ed1358a4c6af, type: 2} + m_CullingMode: 1 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorControllerStateOnDisable: 0 +--- !u!114 &160176462 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160176457} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7a25c54cd35eb284eb6b8ed19cf60443, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + rotation: {x: 0, y: 0, z: 0, w: 0} + turnSpeed: 0.1 +--- !u!1 &489699669850839237 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6048638457609172120} + m_Layer: 0 + m_Name: Wheel_Rear_L_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6048638457609172120 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 489699669850839237} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0.0021921142, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5371032128924763904} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &739025013192983599 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1766344861363284577} + m_Layer: 0 + m_Name: Wheel_Middle_L + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1766344861363284577 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 739025013192983599} + m_LocalRotation: {x: -0.5, y: 0.5, z: 0.49999994, w: 0.50000006} + m_LocalPosition: {x: -0, y: 0.0011627917, z: 0.0000000010728836} + m_LocalScale: {x: 1, y: 0.99999994, z: 1} + m_Children: + - {fileID: 9163197381092130014} + m_Father: {fileID: 847897825935598517} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1014401586714983030 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7755980514232685276} + m_Layer: 0 + m_Name: Turret + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7755980514232685276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1014401586714983030} + m_LocalRotation: {x: 0, y: -0.000000119209275, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0.0010293524, z: 0} + m_LocalScale: {x: 1, y: 0.99999994, z: 1} + m_Children: + - {fileID: 1517159280684637724} + m_Father: {fileID: 1703734463393124925} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1218215768088827738 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5371032128924763904} + m_Layer: 0 + m_Name: Wheel_Rear_L + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5371032128924763904 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218215768088827738} + m_LocalRotation: {x: -0.5, y: 0.5, z: 0.49999994, w: 0.50000006} + m_LocalPosition: {x: -0, y: 0.0011627917, z: -0.0026999994} + m_LocalScale: {x: 1, y: 0.99999994, z: 1} + m_Children: + - {fileID: 6048638457609172120} + m_Father: {fileID: 847897825935598517} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2620739405153902494 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7509984371715941402} + m_Layer: 0 + m_Name: Barrel_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7509984371715941402 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2620739405153902494} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0.0063666296, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1517159280684637724} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4300763244710219681 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3234001708628876000} + - component: {fileID: 2715744559599808281} + - component: {fileID: 4300454509241183841} + m_Layer: 0 + m_Name: Recon_Tank + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3234001708628876000 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4300763244710219681} + m_LocalRotation: {x: -0.7071068, y: 0, z: -0, w: 0.7071067} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 100, y: 100, z: 100} + m_Children: [] + m_Father: {fileID: 160176456} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!137 &2715744559599808281 +SkinnedMeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4300763244710219681} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2e67e42170aa64aa9a33424f8045ac89, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + serializedVersion: 2 + m_Quality: 0 + m_UpdateWhenOffscreen: 0 + m_SkinnedMotionVectors: 1 + m_Mesh: {fileID: 4300000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_Bones: + - {fileID: 847897825935598517} + - {fileID: 1703734463393124925} + - {fileID: 7755980514232685276} + - {fileID: 1517159280684637724} + - {fileID: 7124543900430328667} + - {fileID: 1766344861363284577} + - {fileID: 5371032128924763904} + m_BlendShapeWeights: [] + m_RootBone: {fileID: 847897825935598517} + m_AABB: + m_Center: {x: 0, y: 0.0041689305, z: 0.0018957809} + m_Extent: {x: 0.0028734768, y: 0.004266139, z: 0.006842426} + m_DirtyAABB: 0 +--- !u!64 &4300454509241183841 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4300763244710219681} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Convex: 0 + m_CookingOptions: 14 + m_Mesh: {fileID: 4300000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} +--- !u!1 &4728827432125738153 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 847897825935598517} + m_Layer: 0 + m_Name: Root + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &847897825935598517 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4728827432125738153} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071067} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1703734463393124925} + - {fileID: 7124543900430328667} + - {fileID: 1766344861363284577} + - {fileID: 5371032128924763904} + m_Father: {fileID: 1042389410631263445} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5311698857118067376 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7124543900430328667} + m_Layer: 0 + m_Name: Wheel_Front_L + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7124543900430328667 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5311698857118067376} + m_LocalRotation: {x: -0.5, y: 0.5, z: 0.49999994, w: 0.50000006} + m_LocalPosition: {x: -0, y: 0.0011627917, z: 0.0027000008} + m_LocalScale: {x: 1, y: 0.99999994, z: 1} + m_Children: + - {fileID: 5752532462053122769} + m_Father: {fileID: 847897825935598517} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5804173475777962202 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1703734463393124925} + m_Layer: 0 + m_Name: Chasis + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1703734463393124925 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5804173475777962202} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0.0015, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7755980514232685276} + m_Father: {fileID: 847897825935598517} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6536093484198670798 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1517159280684637724} + m_Layer: 0 + m_Name: Barrel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1517159280684637724 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6536093484198670798} + m_LocalRotation: {x: 0.00000017845065, y: 0.7071068, z: 0.7071067, w: 0.000000009863265} + m_LocalPosition: {x: 5.6542865e-10, y: 0.0015793034, z: 0.00237158} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7509984371715941402} + m_Father: {fileID: 7755980514232685276} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &7509875135952387032 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1042389410631263445} + m_Layer: 0 + m_Name: Recon_Tank_Rig + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1042389410631263445 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7509875135952387032} + m_LocalRotation: {x: -0.7071068, y: 0, z: -0, w: 0.7071067} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 100, y: 100, z: 100} + m_Children: + - {fileID: 847897825935598517} + m_Father: {fileID: 160176456} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &7895955422738415095 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5752532462053122769} + m_Layer: 0 + m_Name: Wheel_Front_L_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5752532462053122769 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7895955422738415095} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0.0021921142, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7124543900430328667} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8824818431311294599 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9163197381092130014} + m_Layer: 0 + m_Name: Wheel_Middle_L_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9163197381092130014 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8824818431311294599} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0.0021921142, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1766344861363284577} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab.meta new file mode 100644 index 0000000..e16f65c --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ab222ed73ada1ac4ba2f61e843d7627c +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab new file mode 100644 index 0000000..84c5aae --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab @@ -0,0 +1,60 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3460729395543957449 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3460729395543957453} + - component: {fileID: 3460729395543957454} + - component: {fileID: 3460729395543957443} + m_Layer: 8 + m_Name: Zone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &3460729395543957453 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3460729395543957449} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!135 &3460729395543957454 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3460729395543957449} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 16 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &3460729395543957443 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3460729395543957449} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 884ed76587eb5854abe6b428b791fdcd, type: 3} + m_Name: + m_EditorClassIdentifier: + subScene: Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity diff --git a/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab.meta b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab.meta new file mode 100644 index 0000000..c079324 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: de939020b5e2aa5489ebcc4002d75d54 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/README.md b/Assets/Mirror/Examples/AdditiveScenes/README.md new file mode 100644 index 0000000..032acd1 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/README.md @@ -0,0 +1,24 @@ +# Additive Scenes Example + +IMPORTANT: Make sure you have a layer in project settings called Player for this example to work well. + +In Build Settings, remove all scenes and add all of the scenes from the Examples\AdditiveScenes\Scenes folder in the following order: +- MainScene +- SubScene + +Open the MainScene in the Editor and make sure the Sub Scenes list in the Network scene object contains the SubScene scene. This is already setup by default, but if the MainScene was opened and saved before putting the scenes in the Build Settings list, the Sub Scenes list may be cleared accidentally. + +File -> Build and Run + +Start up to 3 built instances: These will all be client players. + +Press Play in the Editor and click Host (Server + Client) in the HUD +- This will be the host and the 1st player of up to 4. You can also use Server Only if you prefer. + +Click Client in the built instances. +- WASDQE keys to move & turn your player capsule. +- There are objects in the corners of the scene hidden by Proximity Checkers. +- The big area in the middle is where the subscene will be loaded when you get near the shelter. +- There are also networked objects inside the subscene, also with Proximity Checkers. +- Since subscenes are only loaded for individual clients, other clients that are outside the middle Zone won't see what those in the subscene can see. +- If you play a built instance as Host or Server and play as client in the editor, you'll see the subscene content load and unload in the hierarchy as you move in and out of the middle Zone. diff --git a/Assets/Mirror/Examples/AdditiveScenes/README.md.meta b/Assets/Mirror/Examples/AdditiveScenes/README.md.meta new file mode 100644 index 0000000..53021c1 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0a023e0d7315ac74094703ab69348733 +TextScriptImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes.meta new file mode 100644 index 0000000..06714e8 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e989860f377e7764bb7787086ef44ea4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity new file mode 100644 index 0000000..8e074cb --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity @@ -0,0 +1,2083 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.17276844, g: 0.21589246, b: 0.2978263, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 10 + m_AtlasSize: 512 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 0 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 256 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000004, guid: b287b2046ddc6af4b9ddc48ab35ca3cb, + type: 2} + m_UseShadowmask: 0 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &34755345 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 34755346} + - component: {fileID: 34755348} + - component: {fileID: 34755347} + m_Layer: 0 + m_Name: VisibleRangeCapsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &34755346 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34755345} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 20, y: 1, z: -20} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &34755347 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34755345} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &34755348 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34755345} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &47225730 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 47225731} + m_Layer: 0 + m_Name: ProximityVisualizers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &47225731 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 47225730} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1727677799} + - {fileID: 62078680} + - {fileID: 34755346} + - {fileID: 589935541} + m_Father: {fileID: 909502395} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &62078679 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 62078680} + - component: {fileID: 62078682} + - component: {fileID: 62078681} + m_Layer: 0 + m_Name: VisibleRangeCylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &62078680 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62078679} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 20, y: 1, z: 20} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &62078681 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62078679} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &62078682 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62078679} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &160176455 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalPosition.x + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalPosition.z + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.w + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.y + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 45 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176457, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_Name + value: reconTank + objectReference: {fileID: 0} + - target: {fileID: 160176458, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176459, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: sceneId + value: 1521238664 + objectReference: {fileID: 0} + - target: {fileID: 160176459, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_AssetId + value: ab222ed73ada1ac4ba2f61e843d7627c + objectReference: {fileID: 0} + - target: {fileID: 160176459, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_SceneId + value: 705590806 + objectReference: {fileID: 0} + - target: {fileID: 160176459, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalPlayerAuthority + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} +--- !u!4 &160176456 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, + type: 3} + m_PrefabInstance: {fileID: 160176455} + m_PrefabAsset: {fileID: 0} +--- !u!1 &178547537 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 178547538} + - component: {fileID: 178547539} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &178547538 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178547537} + m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 1.08, z: 20} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!114 &178547539 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178547537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &534669902 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 534669905} + - component: {fileID: 534669904} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &534669904 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 40 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &534669905 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 70, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &589935540 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 589935541} + - component: {fileID: 589935543} + - component: {fileID: 589935542} + m_Layer: 0 + m_Name: VisibleRangeTank + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &589935541 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589935540} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -20, y: 1, z: -20} + m_LocalScale: {x: 20, y: 20, z: 20} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &589935542 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589935540} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &589935543 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589935540} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &612284967 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 612284968} + - component: {fileID: 612284971} + - component: {fileID: 612284970} + - component: {fileID: 612284969} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &612284968 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 8, y: 3, z: -8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &612284969 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &612284970 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &612284971 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &652875644 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 652875645} + - component: {fileID: 652875646} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &652875645 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 652875644} + m_LocalRotation: {x: 0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 20, y: 1.08, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 270, z: 0} +--- !u!114 &652875646 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 652875644} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &691846569 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 691846570} + - component: {fileID: 691846571} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &691846570 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 691846569} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.08, z: -20} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &691846571 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 691846569} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &748207074 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 855244094988030905, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + - target: {fileID: 855244094988030908, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.x + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.z + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 135 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: sceneId + value: 744240842 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_AssetId + value: f6d08eb9a8e35d84fa30a7e3ae64181a + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_SceneId + value: 529586728 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, type: 3} +--- !u!4 &748207075 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + m_PrefabInstance: {fileID: 748207074} + m_PrefabAsset: {fileID: 0} +--- !u!1 &794922164 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 794922165} + - component: {fileID: 794922168} + - component: {fileID: 794922167} + - component: {fileID: 794922166} + m_Layer: 0 + m_Name: Roof + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &794922165 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 6, z: 0} + m_LocalScale: {x: 20, y: 0.2, z: 20} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &794922166 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &794922167 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &794922168 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &856402103 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 856402104} + - component: {fileID: 856402107} + - component: {fileID: 856402106} + - component: {fileID: 856402105} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &856402104 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -8, y: 3, z: 8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &856402105 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &856402106 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &856402107 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &901271862 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 6852530814182375312, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_Name + value: Cylinder + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.x + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.z + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.38268325 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.9238796 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 225 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375317, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: sceneId + value: 1418438611 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_SceneId + value: 568164022 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 12a4c14e672c00b4b840f937d824b890, type: 3} +--- !u!4 &901271863 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + m_PrefabInstance: {fileID: 901271862} + m_PrefabAsset: {fileID: 0} +--- !u!1 &909502394 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 909502395} + m_Layer: 0 + m_Name: Prefabs + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &909502395 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 909502394} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 160176456} + - {fileID: 901271863} + - {fileID: 748207075} + - {fileID: 1284471874} + - {fileID: 47225731} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1047741290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1047741291} + - component: {fileID: 1047741294} + - component: {fileID: 1047741293} + - component: {fileID: 1047741292} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1047741291 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -8, y: 3, z: -8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &1047741292 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1047741293 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1047741294 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1172568541 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1172568542} + m_Layer: 0 + m_Name: StartPositions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1172568542 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1172568541} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 178547538} + - {fileID: 1816951100} + - {fileID: 652875645} + - {fileID: 691846570} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &1284471874 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + m_PrefabInstance: {fileID: 1076878375580925077} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1405375878 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1405375880} + - component: {fileID: 1405375879} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1405375879 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1405375878} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.9622642, g: 0.90969414, b: 0.748932, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1405375880 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1405375878} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &1461518024 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1461518032} + - component: {fileID: 1461518031} + - component: {fileID: 1461518030} + - component: {fileID: 1461518029} + - component: {fileID: 1461518028} + - component: {fileID: 1461518027} + - component: {fileID: 1461518026} + - component: {fileID: 1461518025} + m_Layer: 0 + m_Name: Quad + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!65 &1461518025 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 0.01, z: 3} + m_Center: {x: 0, y: -0.5, z: -1.5} +--- !u!65 &1461518026 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 0.01, z: 3} + m_Center: {x: 0, y: 0.5, z: -1.5} +--- !u!65 &1461518027 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.01, y: 1, z: 3} + m_Center: {x: 0.5, y: 0, z: -1.5} +--- !u!65 &1461518028 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.01, y: 1, z: 3} + m_Center: {x: -0.5, y: 0, z: -1.5} +--- !u!64 &1461518029 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1461518030 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6eb3f3ba66756364d8b94e662e7e8af5, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1461518031 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1461518032 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461518024} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 50, y: 50, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &1462312433 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1462312434} + - component: {fileID: 1462312437} + - component: {fileID: 1462312436} + - component: {fileID: 1462312435} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1462312434 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 8, y: 3, z: 8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &1462312435 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1462312436 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1462312437 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1608696204 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1608696205} + m_Layer: 0 + m_Name: Shelter + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1608696205 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1608696204} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1047741291} + - {fileID: 612284968} + - {fileID: 1462312434} + - {fileID: 856402104} + - {fileID: 794922165} + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1630383476 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1630383479} + - component: {fileID: 1630383478} + - component: {fileID: 1630383477} + m_Layer: 0 + m_Name: ZoneVisualizer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!23 &1630383477 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1630383476} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1630383478 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1630383476} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1630383479 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1630383476} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 32, y: 32, z: 32} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1661834277 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1661834279} + - component: {fileID: 1661834281} + - component: {fileID: 1661834278} + - component: {fileID: 1661834280} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!114 &1661834278 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 34d1daf9e7dbcb64aa647cb332054ea6, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + PersistNetworkManagerToOfflineScene: 0 + runInBackground: 1 + autoStartServerBuild: 1 + serverTickRate: 30 + offlineScene: + onlineScene: + transport: {fileID: 1661834280} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 8872462076811691049, guid: a5bdca0a2315d43499be7dcef473fbc7, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: [] + Zone: {fileID: 3460729395543957449, guid: de939020b5e2aa5489ebcc4002d75d54, type: 3} + subScenes: + - Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity +--- !u!4 &1661834279 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1661834280 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + NonAlloc: 1 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1661834281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + offsetX: 0 + offsetY: 0 +--- !u!1 &1727677796 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1727677799} + - component: {fileID: 1727677798} + - component: {fileID: 1727677797} + m_Layer: 0 + m_Name: VisibleRangeSphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!23 &1727677797 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1727677796} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1727677798 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1727677796} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1727677799 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1727677796} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -20, y: 1, z: 20} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1816951099 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1816951100} + - component: {fileID: 1816951101} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1816951100 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1816951099} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: -20, y: 1.08, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!114 &1816951101 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1816951099} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &1076878375580925077 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_Name + value: Capsule + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_StaticEditorFlags + value: 4294967295 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.x + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.z + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.92387944 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.3826836 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 315 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: sceneId + value: 2757245015 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_SceneId + value: 2061538488 + objectReference: {fileID: 0} + - target: {fileID: 5697694911122891659, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e1971f4a8c7661546bc509b44bd91b80, type: 3} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity.meta new file mode 100644 index 0000000..8c5b47b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7a0eee2f518e9dc4fb628d96dc452faf +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity b/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity new file mode 100644 index 0000000..f66f697 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity @@ -0,0 +1,858 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 2 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 112000002, guid: b287b2046ddc6af4b9ddc48ab35ca3cb, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &21610633 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 21610634} + - component: {fileID: 21610636} + - component: {fileID: 21610635} + m_Layer: 0 + m_Name: VisibleRange + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &21610634 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 21610633} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 3, y: 1, z: -3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &21610635 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 21610633} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &21610636 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 21610633} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &174598777 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_Name + value: Capsule + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_StaticEditorFlags + value: 4294967295 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.x + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.z + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 135 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_SceneId + value: 15452677 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: sceneId + value: 3231330715 + objectReference: {fileID: 0} + - target: {fileID: 5697694911122891659, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: castLayers.m_Bits + value: 256 + objectReference: {fileID: 0} + - target: {fileID: 5697694911122891659, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e1971f4a8c7661546bc509b44bd91b80, type: 3} +--- !u!1 &222935521 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 222935522} + - component: {fileID: 222935524} + - component: {fileID: 222935523} + m_Layer: 0 + m_Name: VisibleRange + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &222935522 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 222935521} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -3, y: 1, z: 3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &222935523 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 222935521} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &222935524 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 222935521} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &507729669 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 507729670} + - component: {fileID: 507729672} + - component: {fileID: 507729671} + m_Layer: 0 + m_Name: VisibleRange + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &507729670 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507729669} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 3, y: 1, z: 3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &507729671 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507729669} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &507729672 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507729669} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1690140970 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1690140971} + m_Layer: 0 + m_Name: ProximityVisualizers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1690140971 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690140970} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1722279649} + - {fileID: 222935522} + - {fileID: 507729670} + - {fileID: 21610634} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1722279648 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1722279649} + - component: {fileID: 1722279651} + - component: {fileID: 1722279650} + m_Layer: 0 + m_Name: VisibleRange + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1722279649 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722279648} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -3, y: 1, z: -3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1722279650 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722279648} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1722279651 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722279648} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &855244095324068329 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 855244094988030905, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + - target: {fileID: 855244094988030908, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: castLayers.m_Bits + value: 256 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030908, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.x + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.z + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.3826836 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.92387944 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 315 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_SceneId + value: 11893259 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: sceneId + value: 1396685688 + objectReference: {fileID: 0} + - target: {fileID: 855244096231524078, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_CastShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244096231524078, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_ReceiveShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244096231524078, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_ReflectionProbeUsage + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, type: 3} +--- !u!1001 &5623359707641229621 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 5623359706949397433, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_CastShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359706949397433, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_ReceiveShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359706949397433, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_ReflectionProbeUsage + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648404, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_SceneId + value: 4733130 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648404, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: sceneId + value: 86995073 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648405, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: castLayers.m_Bits + value: 256 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648405, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalPosition.x + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalPosition.z + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.9238796 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.38268325 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 225 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648430, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_Name + value: Cube + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648430, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_Icon + value: + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 4ff300cf6bb3c6342a9552c4f18788c8, type: 3} +--- !u!1001 &6852530815080958608 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 6852530814182375312, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_Name + value: Cylinder + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.x + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.z + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 45 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375317, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: castLayers.m_Bits + value: 256 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375317, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: forceHidden + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_AssetId + value: 12a4c14e672c00b4b840f937d824b890 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_SceneId + value: 4633990 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: sceneId + value: 1889713496 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 12a4c14e672c00b4b840f937d824b890, type: 3} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity.meta new file mode 100644 index 0000000..25341d3 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7f4fd683fc6d866418c95f99977533a6 +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts.meta new file mode 100644 index 0000000..6aebeb5 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9c36b0deb5d9b245b7c97e3d6eeed29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs new file mode 100644 index 0000000..a022c2c --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs @@ -0,0 +1,63 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.Additive +{ + [AddComponentMenu("")] + public class AdditiveNetworkManager : NetworkManager + { + [Tooltip("Trigger Zone Prefab")] + public GameObject Zone; + + [Scene] + [Tooltip("Add all sub-scenes to this list")] + public string[] subScenes; + + public override void OnStartServer() + { + base.OnStartServer(); + + // load all subscenes on the server only + StartCoroutine(LoadSubScenes()); + + // Instantiate Zone Handler on server only + Instantiate(Zone); + } + + IEnumerator LoadSubScenes() + { + Debug.Log("Loading Scenes"); + + foreach (string sceneName in subScenes) + { + yield return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); + // Debug.Log($"Loaded {sceneName}"); + } + } + + public override void OnStopServer() + { + StartCoroutine(UnloadScenes()); + } + + public override void OnStopClient() + { + StartCoroutine(UnloadScenes()); + } + + IEnumerator UnloadScenes() + { + Debug.Log("Unloading Subscenes"); + + foreach (string sceneName in subScenes) + if (SceneManager.GetSceneByName(sceneName).IsValid() || SceneManager.GetSceneByPath(sceneName).IsValid()) + { + yield return SceneManager.UnloadSceneAsync(sceneName); + // Debug.Log($"Unloaded {sceneName}"); + } + + yield return Resources.UnloadUnusedAssets(); + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta new file mode 100644 index 0000000..7b92eb6 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34d1daf9e7dbcb64aa647cb332054ea6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs new file mode 100644 index 0000000..de38b81 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs @@ -0,0 +1,110 @@ +using UnityEngine; + +namespace Mirror.Examples.Additive +{ + [RequireComponent(typeof(CapsuleCollider))] + [RequireComponent(typeof(CharacterController))] + [RequireComponent(typeof(NetworkTransform))] + [RequireComponent(typeof(Rigidbody))] + public class PlayerController : NetworkBehaviour + { + public CharacterController characterController; + + void OnValidate() + { + if (characterController == null) + characterController = GetComponent(); + } + + void Start() + { + characterController.enabled = isLocalPlayer; + } + + public override void OnStartLocalPlayer() + { + Camera.main.orthographic = false; + Camera.main.transform.SetParent(transform); + Camera.main.transform.localPosition = new Vector3(0f, 3f, -8f); + Camera.main.transform.localEulerAngles = new Vector3(10f, 0f, 0f); + } + + void OnDisable() + { + if (isLocalPlayer && Camera.main != null) + { + Camera.main.orthographic = true; + Camera.main.transform.SetParent(null); + Camera.main.transform.localPosition = new Vector3(0f, 70f, 0f); + Camera.main.transform.localEulerAngles = new Vector3(90f, 0f, 0f); + } + } + + [Header("Movement Settings")] + public float moveSpeed = 8f; + public float turnSensitivity = 5f; + public float maxTurnSpeed = 150f; + + [Header("Diagnostics")] + public float horizontal; + public float vertical; + public float turn; + public float jumpSpeed; + public bool isGrounded = true; + public bool isFalling; + public Vector3 velocity; + + void Update() + { + if (!isLocalPlayer || !characterController.enabled) + return; + + horizontal = Input.GetAxis("Horizontal"); + vertical = Input.GetAxis("Vertical"); + + // Q and E cancel each other out, reducing the turn to zero + if (Input.GetKey(KeyCode.Q)) + turn = Mathf.MoveTowards(turn, -maxTurnSpeed, turnSensitivity); + if (Input.GetKey(KeyCode.E)) + turn = Mathf.MoveTowards(turn, maxTurnSpeed, turnSensitivity); + if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E)) + turn = Mathf.MoveTowards(turn, 0, turnSensitivity); + if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E)) + turn = Mathf.MoveTowards(turn, 0, turnSensitivity); + + if (isGrounded) + isFalling = false; + + if ((isGrounded || !isFalling) && jumpSpeed < 1f && Input.GetKey(KeyCode.Space)) + { + jumpSpeed = Mathf.Lerp(jumpSpeed, 1f, 0.5f); + } + else if (!isGrounded) + { + isFalling = true; + jumpSpeed = 0; + } + } + + void FixedUpdate() + { + if (!isLocalPlayer || characterController == null) + return; + + transform.Rotate(0f, turn * Time.fixedDeltaTime, 0f); + + Vector3 direction = new Vector3(horizontal, jumpSpeed, vertical); + direction = Vector3.ClampMagnitude(direction, 1f); + direction = transform.TransformDirection(direction); + direction *= moveSpeed; + + if (jumpSpeed > 0) + characterController.Move(direction * Time.fixedDeltaTime); + else + characterController.SimpleMove(direction); + + isGrounded = characterController.isGrounded; + velocity = characterController.velocity; + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs.meta new file mode 100644 index 0000000..98c0e27 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e8f68561248aaca4fb96847ce24742ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs new file mode 100644 index 0000000..34d650a --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace Mirror.Examples.Additive +{ + public class RandomColor : NetworkBehaviour + { + public override void OnStartServer() + { + base.OnStartServer(); + color = Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f); + } + + // Color32 packs to 4 bytes + [SyncVar(hook = nameof(SetColor))] + public Color32 color = Color.black; + + // Unity clones the material when GetComponent().material is called + // Cache it here and destroy it in OnDestroy to prevent a memory leak + Material cachedMaterial; + + void SetColor(Color32 _, Color32 newColor) + { + if (cachedMaterial == null) cachedMaterial = GetComponentInChildren().material; + cachedMaterial.color = newColor; + } + + void OnDestroy() + { + Destroy(cachedMaterial); + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs.meta new file mode 100644 index 0000000..d3c401f --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42d1f80407105ee4f960f0b51e89452d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs new file mode 100644 index 0000000..155d7ce --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs @@ -0,0 +1,59 @@ +using UnityEngine; + +namespace Mirror.Examples.Additive +{ + // This script demonstrates the NetworkAnimator and how to leverage + // the built-in observers system to track players. + // Note that all ProximityCheckers should be restricted to the Player layer. + public class ShootingTankBehaviour : NetworkBehaviour + { + [SyncVar] + public Quaternion rotation; + + NetworkAnimator networkAnimator; + + [ServerCallback] + void Start() + { + networkAnimator = GetComponent(); + } + + [Range(0, 1)] + public float turnSpeed = 0.1f; + + void Update() + { + if (isServer && netIdentity.observers.Count > 0) + ShootNearestPlayer(); + + if (isClient) + transform.rotation = Quaternion.Slerp(transform.rotation, rotation, turnSpeed); + } + + [Server] + void ShootNearestPlayer() + { + GameObject target = null; + float distance = 100f; + + foreach (NetworkConnection networkConnection in netIdentity.observers.Values) + { + GameObject tempTarget = networkConnection.identity.gameObject; + float tempDistance = Vector3.Distance(tempTarget.transform.position, transform.position); + + if (target == null || distance > tempDistance) + { + target = tempTarget; + distance = tempDistance; + } + } + + if (target != null) + { + transform.LookAt(target.transform.position + Vector3.down); + rotation = transform.rotation; + networkAnimator.SetTrigger("Fire"); + } + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta new file mode 100644 index 0000000..315914a --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a25c54cd35eb284eb6b8ed19cf60443 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs new file mode 100644 index 0000000..a09bafc --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs @@ -0,0 +1,39 @@ +using UnityEngine; + +namespace Mirror.Examples.Additive +{ + // This script is attached to a prefab called Zone that is on the Player layer + // AdditiveNetworkManager, in OnStartServer, instantiates the prefab only on the server. + // It never exists for clients (other than host client if there is one). + // The prefab has a Sphere Collider with isTrigger = true. + // These OnTrigger events only run on the server and will only send a message to the + // client that entered the Zone to load the subscene assigned to the subscene property. + public class ZoneHandler : MonoBehaviour + { + [Scene] + [Tooltip("Assign the sub-scene to load for this zone")] + public string subScene; + + void OnTriggerEnter(Collider other) + { + if (!NetworkServer.active) return; + + // Debug.LogFormat(LogType.Log, "Loading {0}", subScene); + + NetworkIdentity networkIdentity = other.gameObject.GetComponent(); + SceneMessage message = new SceneMessage{ sceneName = subScene, sceneOperation = SceneOperation.LoadAdditive }; + networkIdentity.connectionToClient.Send(message); + } + + void OnTriggerExit(Collider other) + { + if (!NetworkServer.active) return; + + // Debug.LogFormat(LogType.Log, "Unloading {0}", subScene); + + NetworkIdentity networkIdentity = other.gameObject.GetComponent(); + SceneMessage message = new SceneMessage{ sceneName = subScene, sceneOperation = SceneOperation.UnloadAdditive }; + networkIdentity.connectionToClient.Send(message); + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta new file mode 100644 index 0000000..88adef5 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 884ed76587eb5854abe6b428b791fdcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic.meta b/Assets/Mirror/Examples/Basic.meta new file mode 100644 index 0000000..b61f55f --- /dev/null +++ b/Assets/Mirror/Examples/Basic.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ea49fcefbc864e19a94091a170fc06c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Prefabs.meta b/Assets/Mirror/Examples/Basic/Prefabs.meta new file mode 100644 index 0000000..261c187 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f821a97809492a479cac0843442e245 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab new file mode 100644 index 0000000..2f6dd94 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab @@ -0,0 +1,71 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &897184729387425976 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 897184729387425978} + - component: {fileID: 897184729387425977} + - component: {fileID: 8550999602067651493} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &897184729387425978 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 897184729387425976} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 562, y: 368, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &897184729387425977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 897184729387425976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + m_AssetId: + hasSpawned: 0 +--- !u!114 &8550999602067651493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 897184729387425976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a472ac3ae1701d149861871cf416a46d, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + playerUIPrefab: {fileID: 5152941909035078397, guid: 22f1fa3a0aff72b46a371f667bb4fb30, + type: 3} + playerNumber: 0 + playerData: 0 + playerColor: + serializedVersion: 2 + rgba: 4294967295 diff --git a/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..07fac0c --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dc2c4328591bef748abb8df795c17202 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab new file mode 100644 index 0000000..2dda39c --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab @@ -0,0 +1,250 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &507587715476979468 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7941985369064644521} + - component: {fileID: 263176703837159862} + - component: {fileID: 862087973501639025} + m_Layer: 5 + m_Name: PlayerDataText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7941985369064644521 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507587715476979468} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5939842025755258307} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 60, y: -45} + m_SizeDelta: {x: 120, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &263176703837159862 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507587715476979468} + m_CullTransparentMesh: 0 +--- !u!114 &862087973501639025 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507587715476979468} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 22 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: 'Data: 000' +--- !u!1 &5152941909035078397 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5939842025755258307} + - component: {fileID: 6858069060858394075} + - component: {fileID: 1130938342127810670} + - component: {fileID: 1800193220786703771} + m_Layer: 5 + m_Name: PlayerUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5939842025755258307 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 290719538378481902} + - {fileID: 7941985369064644521} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 120, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6858069060858394075 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_CullTransparentMesh: 0 +--- !u!114 &1130938342127810670 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &1800193220786703771 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 64acca8c87e5ceb44bcbd56ef21e2950, type: 3} + m_Name: + m_EditorClassIdentifier: + image: {fileID: 1130938342127810670} + playerNameText: {fileID: 2551726036882886172} + playerDataText: {fileID: 862087973501639025} +--- !u!1 &5516013313779480533 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 290719538378481902} + - component: {fileID: 1473077327790139714} + - component: {fileID: 2551726036882886172} + m_Layer: 5 + m_Name: PlayerNameText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &290719538378481902 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5516013313779480533} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5939842025755258307} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 60, y: -15} + m_SizeDelta: {x: 120, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1473077327790139714 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5516013313779480533} + m_CullTransparentMesh: 0 +--- !u!114 &2551726036882886172 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5516013313779480533} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 22 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: Player 00 diff --git a/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta new file mode 100644 index 0000000..c522c6f --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 22f1fa3a0aff72b46a371f667bb4fb30 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/README.md b/Assets/Mirror/Examples/Basic/README.md new file mode 100644 index 0000000..5b39b3a --- /dev/null +++ b/Assets/Mirror/Examples/Basic/README.md @@ -0,0 +1,16 @@ +# Basic Example + +This is a bare bones example of a running game with Network Manager and UI prefab players: + +1. Remove all scenes from Build Settings, then add the Example scene alone. + +2. Open the Example scene and build the project. + +3. In the editor, click Play, and Server + Client or Server Only...it will be listening on port 7777. + - If you clicked Host (Server + Client), the host player will appear as Player 00. + +4. Run one or more instances (up to 16 total players) of the built application. + +5. Click Client on each instance. + +6. Now you will see all players in the editor and the clients, all with data being updated and synchronized. diff --git a/Assets/Mirror/Examples/Basic/README.md.meta b/Assets/Mirror/Examples/Basic/README.md.meta new file mode 100644 index 0000000..ce85eed --- /dev/null +++ b/Assets/Mirror/Examples/Basic/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 67177defd4d334a549e535f10506cc66 +TextScriptImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Scenes.meta b/Assets/Mirror/Examples/Basic/Scenes.meta new file mode 100644 index 0000000..56c0473 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16f46473489d3364badc2f37c4db8634 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Scenes/Example.unity b/Assets/Mirror/Examples/Basic/Scenes/Example.unity new file mode 100644 index 0000000..e4d2e4a --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scenes/Example.unity @@ -0,0 +1,730 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 1 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &249891953 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 249891957} + - component: {fileID: 249891954} + - component: {fileID: 249891956} + - component: {fileID: 249891955} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &249891954 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + offsetX: 0 + offsetY: 0 +--- !u!114 &249891955 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + NonAlloc: 1 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &249891956 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 20460c43f0320ed4baf8c1dcf953eafa, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + PersistNetworkManagerToOfflineScene: 0 + runInBackground: 1 + autoStartServerBuild: 1 + serverTickRate: 30 + offlineScene: + onlineScene: + transport: {fileID: 249891955} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 897184729387425976, guid: dc2c4328591bef748abb8df795c17202, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: [] + mainPanel: {fileID: 1712119861} + playersPanel: {fileID: 379082679} +--- !u!4 &249891957 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -10, y: 4, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &288173824 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 288173827} + - component: {fileID: 288173826} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &288173826 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 288173824} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &288173827 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 288173824} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -1} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &379082678 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 379082679} + - component: {fileID: 379082681} + - component: {fileID: 379082682} + - component: {fileID: 379082680} + - component: {fileID: 379082683} + m_Layer: 5 + m_Name: PlayersPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &379082679 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 864730913} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 2.5} + m_SizeDelta: {x: -10, y: -15} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &379082680 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 5 + m_Right: 5 + m_Top: 5 + m_Bottom: 5 + m_ChildAlignment: 0 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 120, y: 65} + m_Spacing: {x: 20, y: 20} + m_Constraint: 0 + m_ConstraintCount: 2 +--- !u!222 &379082681 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_CullTransparentMesh: 0 +--- !u!114 &379082682 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.039215688} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &379082683 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &533055200 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 533055204} + - component: {fileID: 533055203} + - component: {fileID: 533055202} + - component: {fileID: 533055201} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &533055201 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &533055202 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &533055203 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &533055204 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1712119861} + m_Father: {fileID: 0} + 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_Pivot: {x: 0, y: 0} +--- !u!1 &864730912 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 864730913} + - component: {fileID: 864730916} + - component: {fileID: 864730914} + m_Layer: 5 + m_Name: BorderPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &864730913 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864730912} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 379082679} + m_Father: {fileID: 1712119861} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -55} + m_SizeDelta: {x: -40, y: -150} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &864730914 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864730912} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 0 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &864730916 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864730912} + m_CullTransparentMesh: 0 +--- !u!1 &1356257340 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1356257343} + - component: {fileID: 1356257342} + - component: {fileID: 1356257341} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1356257341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1356257340} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1356257342 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1356257340} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1356257343 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1356257340} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1712119860 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1712119861} + - component: {fileID: 1712119863} + - component: {fileID: 1712119862} + m_Layer: 5 + m_Name: MainPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1712119861 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712119860} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 864730913} + m_Father: {fileID: 533055204} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1712119862 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712119860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1712119863 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712119860} + m_CullTransparentMesh: 0 diff --git a/Assets/Mirror/Examples/Basic/Scenes/Example.unity.meta b/Assets/Mirror/Examples/Basic/Scenes/Example.unity.meta new file mode 100644 index 0000000..7d2a8de --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scenes/Example.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b30904751905d3f4dacde62ac85ec7c2 +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Scripts.meta b/Assets/Mirror/Examples/Basic/Scripts.meta new file mode 100644 index 0000000..b5807e6 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c5291659f25af9409bbc25a2d37d628 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs new file mode 100644 index 0000000..bd88f7d --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +/* + Documentation: https://mirror-networking.gitbook.io/docs/components/network-manager + API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkManager.html +*/ + +namespace Mirror.Examples.Basic +{ + [AddComponentMenu("")] + public class BasicNetManager : NetworkManager + { + [Header("Canvas UI")] + + [Tooltip("Assign Main Panel so it can be turned on from Player:OnStartClient")] + public RectTransform mainPanel; + + [Tooltip("Assign Players Panel for instantiating PlayerUI as child")] + public RectTransform playersPanel; + + /// + /// Called on the server when a client adds a new player with NetworkClient.AddPlayer. + /// The default implementation for this function creates a new player object from the playerPrefab. + /// + /// Connection from client. + public override void OnServerAddPlayer(NetworkConnection conn) + { + base.OnServerAddPlayer(conn); + Player.ResetPlayerNumbers(); + } + + /// + /// Called on the server when a client disconnects. + /// This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected. + /// + /// Connection from client. + public override void OnServerDisconnect(NetworkConnection conn) + { + base.OnServerDisconnect(conn); + Player.ResetPlayerNumbers(); + } + + } +} diff --git a/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta new file mode 100644 index 0000000..d249881 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20460c43f0320ed4baf8c1dcf953eafa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Scripts/Player.cs b/Assets/Mirror/Examples/Basic/Scripts/Player.cs new file mode 100644 index 0000000..31949dc --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/Player.cs @@ -0,0 +1,138 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror.Examples.Basic +{ + public class Player : NetworkBehaviour + { + // Events that the UI will subscribe to + public event System.Action OnPlayerNumberChanged; + public event System.Action OnPlayerColorChanged; + public event System.Action OnPlayerDataChanged; + + // Players List to manage playerNumber + internal static readonly List playersList = new List(); + + internal static void ResetPlayerNumbers() + { + int playerNumber = 0; + foreach (Player player in playersList) + { + player.playerNumber = playerNumber++; + } + } + + [Header("Player UI")] + public GameObject playerUIPrefab; + GameObject playerUI; + + [Header("SyncVars")] + + /// + /// This is appended to the player name text, e.g. "Player 01" + /// + [SyncVar(hook = nameof(PlayerNumberChanged))] + public int playerNumber = 0; + + /// + /// This is updated by UpdateData which is called from OnStartServer via InvokeRepeating + /// + [SyncVar(hook = nameof(PlayerDataChanged))] + public int playerData = 0; + + /// + /// Random color for the playerData text, assigned in OnStartServer + /// + [SyncVar(hook = nameof(PlayerColorChanged))] + public Color32 playerColor = Color.white; + + // This is called by the hook of playerNumber SyncVar above + void PlayerNumberChanged(int _, int newPlayerNumber) + { + OnPlayerNumberChanged?.Invoke(newPlayerNumber); + } + + // This is called by the hook of playerData SyncVar above + void PlayerDataChanged(int _, int newPlayerData) + { + OnPlayerDataChanged?.Invoke(newPlayerData); + } + + // This is called by the hook of playerColor SyncVar above + void PlayerColorChanged(Color32 _, Color32 newPlayerColor) + { + OnPlayerColorChanged?.Invoke(newPlayerColor); + } + + /// + /// This is invoked for NetworkBehaviour objects when they become active on the server. + /// This could be triggered by NetworkServer.Listen() for objects in the scene, or by NetworkServer.Spawn() for objects that are dynamically created. + /// This will be called for objects on a "host" as well as for object on a dedicated server. + /// + public override void OnStartServer() + { + base.OnStartServer(); + + // Add this to the static Players List + playersList.Add(this); + + // set the Player Color SyncVar + playerColor = Random.ColorHSV(0f, 1f, 0.9f, 0.9f, 1f, 1f); + + // Start generating updates + InvokeRepeating(nameof(UpdateData), 1, 1); + } + + /// + /// Invoked on the server when the object is unspawned + /// Useful for saving object data in persistent storage + /// + public override void OnStopServer() + { + CancelInvoke(); + playersList.Remove(this); + } + + // This only runs on the server, called from OnStartServer via InvokeRepeating + [ServerCallback] + void UpdateData() + { + playerData = Random.Range(100, 1000); + } + + /// + /// Called on every NetworkBehaviour when it is activated on a client. + /// Objects on the host have this function called, as there is a local client on the host. The values of SyncVars on object are guaranteed to be initialized correctly with the latest state from the server when this function is called on the client. + /// + public override void OnStartClient() + { + // Activate the main panel + ((BasicNetManager)NetworkManager.singleton).mainPanel.gameObject.SetActive(true); + + // Instantiate the player UI as child of the Players Panel + playerUI = Instantiate(playerUIPrefab, ((BasicNetManager)NetworkManager.singleton).playersPanel); + + // Set this player object in PlayerUI to wire up event handlers + playerUI.GetComponent().SetPlayer(this, isLocalPlayer); + + // Invoke all event handlers with the current data + OnPlayerNumberChanged.Invoke(playerNumber); + OnPlayerColorChanged.Invoke(playerColor); + OnPlayerDataChanged.Invoke(playerData); + } + + /// + /// This is invoked on clients when the server has caused this object to be destroyed. + /// This can be used as a hook to invoke effects or do client specific cleanup. + /// + public override void OnStopClient() + { + // Remove this player's UI object + Destroy(playerUI); + + // Disable the main panel for local player + if (isLocalPlayer) + ((BasicNetManager)NetworkManager.singleton).mainPanel.gameObject.SetActive(false); + } + } +} diff --git a/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta new file mode 100644 index 0000000..3be1823 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a472ac3ae1701d149861871cf416a46d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs new file mode 100644 index 0000000..b11be79 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs @@ -0,0 +1,64 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.Basic +{ + public class PlayerUI : MonoBehaviour + { + [Header("Player Components")] + public Image image; + + [Header("Child Text Objects")] + public Text playerNameText; + public Text playerDataText; + + Player player; + + /// + /// Caches the controlling Player object, subscribes to its events + /// + /// Player object that controls this UI + /// true if the Player object is the Local Player + public void SetPlayer(Player player, bool isLocalPlayer) + { + // cache reference to the player that controls this UI object + this.player = player; + + // subscribe to the events raised by SyncVar Hooks on the Player object + player.OnPlayerNumberChanged += OnPlayerNumberChanged; + player.OnPlayerColorChanged += OnPlayerColorChanged; + player.OnPlayerDataChanged += OnPlayerDataChanged; + + // add a visual background for the local player in the UI + if (isLocalPlayer) + image.color = new Color(1f, 1f, 1f, 0.1f); + } + + void OnDisable() + { + player.OnPlayerNumberChanged -= OnPlayerNumberChanged; + player.OnPlayerColorChanged -= OnPlayerColorChanged; + player.OnPlayerDataChanged -= OnPlayerDataChanged; + } + + // This value can change as clients leave and join + void OnPlayerNumberChanged(int newPlayerNumber) + { + playerNameText.text = string.Format("Player {0:00}", newPlayerNumber); + } + + // Random color set by Player::OnStartServer + void OnPlayerColorChanged(Color32 newPlayerColor) + { + playerNameText.color = newPlayerColor; + } + + // This updates from Player::UpdateData via InvokeRepeating on server + void OnPlayerDataChanged(int newPlayerData) + { + // Show the data in the UI + playerDataText.text = string.Format("Data: {0:000}", newPlayerData); + } + + } +} diff --git a/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta new file mode 100644 index 0000000..f5eaa15 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64acca8c87e5ceb44bcbd56ef21e2950 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark.meta b/Assets/Mirror/Examples/Benchmark.meta new file mode 100644 index 0000000..5e1f04c --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a0b6db5b77ec4177a6e47b68ea7d064 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Materials.meta b/Assets/Mirror/Examples/Benchmark/Materials.meta new file mode 100644 index 0000000..1ac3c41 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba4e4f7749e6b437aac187bd7625cf28 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Materials/Red.mat b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat new file mode 100644 index 0000000..5c24968 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta new file mode 100644 index 0000000..a976752 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 451c5da2c5056496297cffba02216286 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Materials/White.mat b/Assets/Mirror/Examples/Benchmark/Materials/White.mat new file mode 100644 index 0000000..aaf3087 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/White.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: White + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta b/Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta new file mode 100644 index 0000000..2c7446d --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff8f106e5c9e34da28ad9cee6edb2255 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs.meta b/Assets/Mirror/Examples/Benchmark/Prefabs.meta new file mode 100644 index 0000000..21e533a --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29276b4f741904266bb3eb6331bee4ab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab new file mode 100644 index 0000000..0c78b0d --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab @@ -0,0 +1,146 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: 3679374677650722848} + - component: {fileID: 8309506939003697769} + m_Layer: 0 + m_Name: Monster + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 451c5da2c5056496297cffba02216286, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: + hasSpawned: 0 +--- !u!114 &3679374677650722848 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + clientAuthority: 0 + sendInterval: 0.05 + syncPosition: 1 + syncRotation: 0 + syncScale: 0 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + bufferTimeMultiplier: 3 + catchupThreshold: 6 + catchupMultiplier: 0.1 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} +--- !u!114 &8309506939003697769 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9cddc2e496c474e538a494465be0192a, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + speed: 1 + movementProbability: 0.5 + movementDistance: 20 diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta new file mode 100644 index 0000000..af6f683 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 30b8f251d03d84284b70601e691d474f +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab new file mode 100644 index 0000000..2ed6853 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab @@ -0,0 +1,148 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: 3679374677650722848} + - component: {fileID: 644305951047116972} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + 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!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8f106e5c9e34da28ad9cee6edb2255, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: e1299008405d14b17b1ca459a6cd44a2 + hasSpawned: 0 +--- !u!114 &3679374677650722848 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + clientAuthority: 1 + sendInterval: 0.05 + syncPosition: 1 + syncRotation: 0 + syncScale: 0 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + bufferTimeMultiplier: 3 + catchupThreshold: 6 + catchupMultiplier: 0.1 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} +--- !u!114 &644305951047116972 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c482338c8cc6d4a3cba81934c0151972, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + speed: 20 diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..36bbff1 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e1299008405d14b17b1ca459a6cd44a2 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Scenes.meta b/Assets/Mirror/Examples/Benchmark/Scenes.meta new file mode 100644 index 0000000..5af04cf --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1507ce547cd6a42ddb4ba60c3552dc48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity b/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity new file mode 100644 index 0000000..8a09733 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity @@ -0,0 +1,439 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936774} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &88936774 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 150 + maxLogCount: 50 + hotKey: 293 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.39215687, g: 0.58431375, b: 0.92941177, a: 1} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 35 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.38268343, y: 0, z: 0, w: 0.92387956} + m_LocalPosition: {x: 0, y: 50, z: -80} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: SpawnPosition + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001521} + - component: {fileID: 1282001522} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f0f6e2c4566084948a433ee5285d3fb7, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + runInBackground: 1 + autoStartServerBuild: 1 + showDebugMessages: 0 + serverTickRate: 30 + serverBatching: 1 + serverBatchInterval: 0 + offlineScene: + onlineScene: + transport: {fileID: 1282001521} + networkAddress: localhost + maxConnections: 1000 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 449802645721213856, guid: e1299008405d14b17b1ca459a6cd44a2, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 449802645721213856, guid: 30b8f251d03d84284b70601e691d474f, type: 3} + spawnPrefab: {fileID: 449802645721213856, guid: 30b8f251d03d84284b70601e691d474f, + type: 3} + spawnAmount: 1000 + interleave: 1 +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + NoDelay: 1 + Interval: 10 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 39adc6e09d5544ed955a50ce8600355a, type: 3} + m_Name: + m_EditorClassIdentifier: + visRange: 999 + rebuildInterval: 1 + checkMethod: 0 + showSlider: 1 +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity.meta b/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity.meta new file mode 100644 index 0000000..5f0f907 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3b956c7d68b6144dd8e6c36636e25b52 +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Scripts.meta b/Assets/Mirror/Examples/Benchmark/Scripts.meta new file mode 100644 index 0000000..868debf --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56ec73164c7f24072b822ed0d1e4d03e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs new file mode 100644 index 0000000..ba54712 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs @@ -0,0 +1,51 @@ +using UnityEngine; + +namespace Mirror.Examples.Benchmark +{ + public class BenchmarkNetworkManager : NetworkManager + { + [Header("Spawns")] + public GameObject spawnPrefab; + public int spawnAmount = 5000; + public float interleave = 1; + + void SpawnAll() + { + // calculate sqrt so we can spawn N * N = Amount + float sqrt = Mathf.Sqrt(spawnAmount); + + // calculate spawn xz start positions + // based on spawnAmount * distance + float offset = -sqrt / 2 * interleave; + + // spawn exactly the amount, not one more. + int spawned = 0; + for (int spawnX = 0; spawnX < sqrt; ++spawnX) + { + for (int spawnZ = 0; spawnZ < sqrt; ++spawnZ) + { + // spawn exactly the amount, not any more + // (our sqrt method isn't 100% precise) + if (spawned < spawnAmount) + { + // instantiate & position + GameObject go = Instantiate(spawnPrefab); + float x = offset + spawnX * interleave; + float z = offset + spawnZ * interleave; + go.transform.position = new Vector3(x, 0, z); + + // spawn + NetworkServer.Spawn(go); + ++spawned; + } + } + } + } + + public override void OnStartServer() + { + base.OnStartServer(); + SpawnAll(); + } + } +} diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta new file mode 100644 index 0000000..34f34b7 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0f6e2c4566084948a433ee5285d3fb7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs new file mode 100644 index 0000000..2ef7fae --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace Mirror.Examples.Benchmark +{ + public class MonsterMovement : NetworkBehaviour + { + public float speed = 1; + public float movementProbability = 0.5f; + public float movementDistance = 20; + + bool moving; + Vector3 start; + Vector3 destination; + + public override void OnStartServer() + { + start = transform.position; + } + + [ServerCallback] + void Update() + { + if (moving) + { + if (Vector3.Distance(transform.position, destination) <= 0.01f) + { + moving = false; + } + else + { + transform.position = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime); + } + } + else + { + float r = Random.value; + if (r < movementProbability * Time.deltaTime) + { + Vector2 circlePos = Random.insideUnitCircle; + Vector3 dir = new Vector3(circlePos.x, 0, circlePos.y); + Vector3 dest = transform.position + dir * movementDistance; + + // within move dist around start? + // (don't want to wander off) + if (Vector3.Distance(start, dest) <= movementDistance) + { + destination = dest; + moving = true; + } + } + } + } + } +} diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta new file mode 100644 index 0000000..23d46c4 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cddc2e496c474e538a494465be0192a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs new file mode 100644 index 0000000..6865123 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace Mirror.Examples.Benchmark +{ + public class PlayerMovement : NetworkBehaviour + { + public float speed = 5; + + void Update() + { + if (!isLocalPlayer) return; + + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + Vector3 dir = new Vector3(h, 0, v); + transform.position += dir.normalized * (Time.deltaTime * speed); + } + } +} diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta new file mode 100644 index 0000000..7eb5367 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c482338c8cc6d4a3cba81934c0151972 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat.meta b/Assets/Mirror/Examples/Chat.meta new file mode 100644 index 0000000..d9b8551 --- /dev/null +++ b/Assets/Mirror/Examples/Chat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 92165d23a248449f58d0be75d794a127 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Prefabs.meta b/Assets/Mirror/Examples/Chat/Prefabs.meta new file mode 100644 index 0000000..ea5ec30 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 55a4e4e8824ec4e329adf12e2cfb02a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab new file mode 100644 index 0000000..c4fb98f --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab @@ -0,0 +1,64 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5075528875289742095 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3351063249001228125} + - component: {fileID: 718303009120396421} + - component: {fileID: 114398755512196590} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3351063249001228125 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075528875289742095} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 718.76324, y: 411.311, z: -4.8041315} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &718303009120396421 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075528875289742095} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3addc5ad220944ed6888319897606739, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + playerName: +--- !u!114 &114398755512196590 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075528875289742095} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + serverOnly: 0 + m_AssetId: + m_SceneId: 0 diff --git a/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..c1264aa --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e5905ffa27de84009b346b49d518ba03 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Scenes.meta b/Assets/Mirror/Examples/Chat/Scenes.meta new file mode 100644 index 0000000..63a8fe5 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 71f6f21bb51d14dc0b231a8488826aac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Scenes/Main.unity b/Assets/Mirror/Examples/Chat/Scenes/Main.unity new file mode 100644 index 0000000..96772f3 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scenes/Main.unity @@ -0,0 +1,3616 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &20782995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 20782996} + - component: {fileID: 20782998} + - component: {fileID: 20782997} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &20782996 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20782995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 851154180} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5000019} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &20782997 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20782995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text... +--- !u!222 &20782998 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20782995} + m_CullTransparentMesh: 0 +--- !u!1 &75860995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 75860996} + - component: {fileID: 75860999} + - component: {fileID: 75860998} + - component: {fileID: 75860997} + - component: {fileID: 75861000} + - component: {fileID: 75861001} + m_Layer: 5 + m_Name: Chat + m_TagString: ChatWindow + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &75860996 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 762534976} + - {fileID: 1231350850} + - {fileID: 1286463573} + - {fileID: 1863915625} + m_Father: {fileID: 1453327788} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -40, y: -40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &75860997 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.19607843} + m_EffectDistance: {x: 10, y: -10} + m_UseGraphicAlpha: 1 +--- !u!114 &75860998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.92941177} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &75860999 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_CullTransparentMesh: 0 +--- !u!114 &75861000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2c102f62d739545269250f48327d4429, type: 3} + m_Name: + m_EditorClassIdentifier: + chatMessage: {fileID: 1231350851} + chatHistory: {fileID: 827598817} + scrollbar: {fileID: 423302021} +--- !u!114 &75861001 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 1581524575 + serverOnly: 0 + visible: 0 + m_AssetId: + hasSpawned: 0 +--- !u!1 &90143746 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 90143747} + - component: {fileID: 90143749} + - component: {fileID: 90143748} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &90143747 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 90143746} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1231350850} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &90143748 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 90143746} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &90143749 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 90143746} + m_CullTransparentMesh: 0 +--- !u!1 &107824418 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 107824419} + - component: {fileID: 107824421} + - component: {fileID: 107824420} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &107824419 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107824418} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1063265579} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &107824420 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107824418} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Connect +--- !u!222 &107824421 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107824418} + m_CullTransparentMesh: 0 +--- !u!1 &293460942 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 293460943} + - component: {fileID: 293460945} + - component: {fileID: 293460944} + - component: {fileID: 293460946} + m_Layer: 5 + m_Name: Username + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &293460943 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 293460942} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1143498589} + - {fileID: 1481045373} + - {fileID: 851154180} + - {fileID: 1523854170} + m_Father: {fileID: 1453327788} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 600, y: 400} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &293460944 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 293460942} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.92941177} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &293460945 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 293460942} + m_CullTransparentMesh: 0 +--- !u!114 &293460946 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 293460942} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5} + m_EffectDistance: {x: 20, y: -20} + m_UseGraphicAlpha: 1 +--- !u!1 &423302019 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 423302020} + - component: {fileID: 423302023} + - component: {fileID: 423302022} + - component: {fileID: 423302021} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &423302020 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 731902021} + m_Father: {fileID: 1863915625} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 0} + m_Pivot: {x: 1, y: 1} +--- !u!114 &423302021 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1616857743} + m_HandleRect: {fileID: 1616857742} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &423302022 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &423302023 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_CullTransparentMesh: 0 +--- !u!1 &576238261 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 576238262} + - component: {fileID: 576238264} + - component: {fileID: 576238263} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &576238262 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576238261} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 851154180} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5000019} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &576238263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576238261} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &576238264 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576238261} + m_CullTransparentMesh: 0 +--- !u!1 &591385423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 591385424} + - component: {fileID: 591385426} + - component: {fileID: 591385425} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &591385424 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 591385423} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027272348} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5000019} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &591385425 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 591385423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &591385426 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 591385423} + m_CullTransparentMesh: 0 +--- !u!1 &719610385 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 719610386} + - component: {fileID: 719610388} + - component: {fileID: 719610387} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &719610386 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719610385} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1231350850} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &719610387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719610385} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text... +--- !u!222 &719610388 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719610385} + m_CullTransparentMesh: 0 +--- !u!1 &731902020 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 731902021} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &731902021 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 731902020} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1616857742} + m_Father: {fileID: 423302020} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &762534975 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 762534976} + - component: {fileID: 762534978} + - component: {fileID: 762534977} + m_Layer: 5 + m_Name: Header + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &762534976 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 762534975} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 75860996} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0.000048637, y: -30} + m_SizeDelta: {x: 300, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &762534977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 762534975} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Mirror Chat Example +--- !u!222 &762534978 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 762534975} + m_CullTransparentMesh: 0 +--- !u!1 &780870085 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 780870086} + - component: {fileID: 780870089} + - component: {fileID: 780870088} + - component: {fileID: 780870087} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &780870086 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1335915325} + m_Father: {fileID: 1863915625} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &780870087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &780870088 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_CullTransparentMesh: 0 +--- !u!114 &780870089 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &827598815 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 827598816} + - component: {fileID: 827598818} + - component: {fileID: 827598817} + m_Layer: 5 + m_Name: ChatHistory + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &827598816 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 827598815} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1335915325} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 440, y: -5} + m_SizeDelta: {x: 870, y: 137} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &827598817 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 827598815} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: +--- !u!222 &827598818 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 827598815} + m_CullTransparentMesh: 0 +--- !u!1 &851154179 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 851154180} + - component: {fileID: 851154183} + - component: {fileID: 851154182} + - component: {fileID: 851154181} + m_Layer: 5 + m_Name: UsernameInput + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &851154180 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 20782996} + - {fileID: 576238262} + m_Father: {fileID: 293460943} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 102, y: 37} + m_SizeDelta: {x: 300, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &851154181 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 851154182} + m_TextComponent: {fileID: 576238263} + m_Placeholder: {fileID: 20782997} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1783103025} + m_MethodName: set_PlayerName + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &851154182 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &851154183 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_CullTransparentMesh: 0 +--- !u!1 &1018203013 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1018203014} + - component: {fileID: 1018203016} + - component: {fileID: 1018203015} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1018203014 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018203013} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1286463573} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1018203015 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018203013} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Send + +' +--- !u!222 &1018203016 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018203013} + m_CullTransparentMesh: 0 +--- !u!1 &1027272347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1027272348} + - component: {fileID: 1027272351} + - component: {fileID: 1027272350} + - component: {fileID: 1027272349} + m_Layer: 5 + m_Name: NetworkAddressInput + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1027272348 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1170876675} + - {fileID: 591385424} + m_Father: {fileID: 1499096249} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 102, y: 37} + m_SizeDelta: {x: 300, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1027272349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1027272350} + m_TextComponent: {fileID: 591385425} + m_Placeholder: {fileID: 1170876676} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1783103025} + m_MethodName: SetHostname + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1027272350 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1027272351 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_CullTransparentMesh: 0 +--- !u!1 &1063265578 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1063265579} + - component: {fileID: 1063265582} + - component: {fileID: 1063265581} + - component: {fileID: 1063265580} + m_Layer: 5 + m_Name: ClientButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1063265579 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 107824419} + m_Father: {fileID: 1499096249} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 187, y: -102} + m_SizeDelta: {x: 300, y: 73.2} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1063265580 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1063265581} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1499096248} + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1783103025} + m_MethodName: StartClient + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 2 +--- !u!114 &1063265581 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1063265582 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_CullTransparentMesh: 0 +--- !u!1 &1143498588 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1143498589} + - component: {fileID: 1143498591} + - component: {fileID: 1143498590} + m_Layer: 5 + m_Name: Header + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1143498589 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1143498588} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 293460943} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -0.000012398, y: 141} + m_SizeDelta: {x: 300, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1143498590 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1143498588} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Mirror Chat Example +--- !u!222 &1143498591 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1143498588} + m_CullTransparentMesh: 0 +--- !u!1 &1170876674 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1170876675} + - component: {fileID: 1170876677} + - component: {fileID: 1170876676} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1170876675 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1170876674} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027272348} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5000019} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1170876676 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1170876674} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: localhost +--- !u!222 &1170876677 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1170876674} + m_CullTransparentMesh: 0 +--- !u!1 &1231350849 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1231350850} + - component: {fileID: 1231350853} + - component: {fileID: 1231350852} + - component: {fileID: 1231350851} + m_Layer: 5 + m_Name: MessageField + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1231350850 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 719610386} + - {fileID: 90143747} + m_Father: {fileID: 75860996} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 26, y: 12} + m_SizeDelta: {x: -176.4, y: 41} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1231350851 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1231350852} + m_TextComponent: {fileID: 90143748} + m_Placeholder: {fileID: 719610387} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1231350852 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1231350853 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_CullTransparentMesh: 0 +--- !u!1 &1264446057 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1264446058} + - component: {fileID: 1264446060} + - component: {fileID: 1264446059} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1264446058 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1264446057} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1523854170} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1264446059 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1264446057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Next +--- !u!222 &1264446060 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1264446057} + m_CullTransparentMesh: 0 +--- !u!1 &1286463572 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1286463573} + - component: {fileID: 1286463576} + - component: {fileID: 1286463575} + - component: {fileID: 1286463574} + m_Layer: 5 + m_Name: SendButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1286463573 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1018203014} + m_Father: {fileID: 75860996} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -26, y: 12} + m_SizeDelta: {x: 116.9, y: 41} + m_Pivot: {x: 1, y: 0} +--- !u!114 &1286463574 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1286463575} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 75861000} + m_MethodName: OnSend + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1286463575 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1286463576 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_CullTransparentMesh: 0 +--- !u!1 &1335915324 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1335915325} + - component: {fileID: 1335915327} + - component: {fileID: 1335915326} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1335915325 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335915324} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 827598816} + m_Father: {fileID: 780870086} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 1, y: 0} + m_SizeDelta: {x: -1, y: -220.9} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1335915326 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335915324} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!114 &1335915327 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335915324} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 5 + m_Right: 5 + m_Top: 5 + m_Bottom: 5 + m_ChildAlignment: 0 + m_Spacing: 2 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 1 + m_ChildControlHeight: 1 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &1453327784 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1453327788} + - component: {fileID: 1453327787} + - component: {fileID: 1453327786} + - component: {fileID: 1453327785} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1453327785 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1453327786 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1453327787 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1453327788 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 293460943} + - {fileID: 1499096249} + - {fileID: 75860996} + m_Father: {fileID: 0} + 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_Pivot: {x: 0, y: 0} +--- !u!1 &1481045372 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1481045373} + - component: {fileID: 1481045375} + - component: {fileID: 1481045374} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1481045373 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481045372} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 293460943} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -128, y: 37} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1481045374 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481045372} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'User name:' +--- !u!222 &1481045375 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481045372} + m_CullTransparentMesh: 0 +--- !u!1 &1499096248 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1499096249} + - component: {fileID: 1499096252} + - component: {fileID: 1499096251} + - component: {fileID: 1499096250} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1499096249 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1909588651} + - {fileID: 1995652016} + - {fileID: 1027272348} + - {fileID: 1904406265} + - {fileID: 1063265579} + m_Father: {fileID: 1453327788} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 750, y: 400} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1499096250 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5} + m_EffectDistance: {x: 20, y: -20} + m_UseGraphicAlpha: 1 +--- !u!114 &1499096251 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.92941177} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1499096252 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_CullTransparentMesh: 0 +--- !u!1 &1523854169 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1523854170} + - component: {fileID: 1523854173} + - component: {fileID: 1523854172} + - component: {fileID: 1523854171} + m_Layer: 5 + m_Name: NextButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1523854170 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1523854169} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1264446058} + m_Father: {fileID: 293460943} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.000011444, y: -102} + m_SizeDelta: {x: 183.6, y: 73.2} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1523854171 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1523854169} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1523854172} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 293460942} + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1499096248} + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 2 +--- !u!114 &1523854172 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1523854169} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1523854173 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1523854169} + m_CullTransparentMesh: 0 +--- !u!1 &1569758148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1569758149} + - component: {fileID: 1569758151} + - component: {fileID: 1569758150} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1569758149 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1569758148} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1904406265} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1569758150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1569758148} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Start Server +--- !u!222 &1569758151 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1569758148} + m_CullTransparentMesh: 0 +--- !u!1 &1616857741 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1616857742} + - component: {fileID: 1616857744} + - component: {fileID: 1616857743} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1616857742 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1616857741} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 731902021} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1616857743 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1616857741} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1616857744 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1616857741} + m_CullTransparentMesh: 0 +--- !u!1 &1667679449 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1667679451} + - component: {fileID: 1667679450} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1667679450 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1667679449} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1667679451 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1667679449} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1783103022 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1783103026} + - component: {fileID: 1783103025} + - component: {fileID: 1783103023} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1783103023 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1783103022} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + NonAlloc: 1 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1783103025 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1783103022} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0cd72391a563461f88eb3ddf120efef, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + PersistNetworkManagerToOfflineScene: 0 + runInBackground: 1 + autoStartServerBuild: 1 + serverTickRate: 30 + offlineScene: + onlineScene: + transport: {fileID: 1783103023} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 5075528875289742095, guid: e5905ffa27de84009b346b49d518ba03, + type: 3} + autoCreatePlayer: 0 + playerSpawnMethod: 0 + spawnPrefabs: [] + chatWindow: {fileID: 75861000} +--- !u!4 &1783103026 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1783103022} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.78, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1863915624 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1863915625} + - component: {fileID: 1863915628} + - component: {fileID: 1863915627} + - component: {fileID: 1863915626} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1863915625 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 780870086} + - {fileID: 423302020} + m_Father: {fileID: 75860996} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0.000061035156, y: 5.5} + m_SizeDelta: {x: -52, y: -111.1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1863915626 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1863915627 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_CullTransparentMesh: 0 +--- !u!114 &1863915628 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1335915325} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 1 + m_Elasticity: 0.1 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 1 + m_Viewport: {fileID: 780870086} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 423302021} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1897504366 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1897504369} + - component: {fileID: 1897504368} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &1897504368 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1897504366} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1897504369 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1897504366} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1904406264 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1904406265} + - component: {fileID: 1904406268} + - component: {fileID: 1904406267} + - component: {fileID: 1904406266} + m_Layer: 5 + m_Name: HostButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1904406265 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1569758149} + m_Father: {fileID: 1499096249} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -187, y: -102} + m_SizeDelta: {x: 300, y: 73.2} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1904406266 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1904406267} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1499096248} + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1783103025} + m_MethodName: StartHost + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 2 +--- !u!114 &1904406267 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1904406268 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_CullTransparentMesh: 0 +--- !u!1 &1909588650 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1909588651} + - component: {fileID: 1909588653} + - component: {fileID: 1909588652} + m_Layer: 5 + m_Name: Header + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1909588651 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1909588650} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1499096249} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: -0.000012398, y: -59} + m_SizeDelta: {x: 300, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1909588652 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1909588650} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Mirror Chat Example +--- !u!222 &1909588653 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1909588650} + m_CullTransparentMesh: 0 +--- !u!1 &1923358029 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1923358032} + - component: {fileID: 1923358031} + - component: {fileID: 1923358030} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1923358030 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923358029} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1923358031 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923358029} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1923358032 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923358029} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1995652015 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1995652016} + - component: {fileID: 1995652018} + - component: {fileID: 1995652017} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1995652016 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995652015} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1499096249} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -128, y: 37} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1995652017 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995652015} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Server:' +--- !u!222 &1995652018 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995652015} + m_CullTransparentMesh: 0 diff --git a/Assets/Mirror/Examples/Chat/Scenes/Main.unity.meta b/Assets/Mirror/Examples/Chat/Scenes/Main.unity.meta new file mode 100644 index 0000000..cf81526 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scenes/Main.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f4e8d4de4484e44bba666f2d1f66c73e +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Scripts.meta b/Assets/Mirror/Examples/Chat/Scripts.meta new file mode 100644 index 0000000..e1c9c15 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81da49d71176c41169a24259df78e50a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs new file mode 100644 index 0000000..34bbceb --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs @@ -0,0 +1,51 @@ +using UnityEngine; + +namespace Mirror.Examples.Chat +{ + [AddComponentMenu("")] + public class ChatNetworkManager : NetworkManager + { + [Header("Chat GUI")] + public ChatWindow chatWindow; + + // Set by UI element UsernameInput OnValueChanged + public string PlayerName { get; set; } + + // Called by UI element NetworkAddressInput.OnValueChanged + public void SetHostname(string hostname) + { + networkAddress = hostname; + } + + public struct CreatePlayerMessage : NetworkMessage + { + public string name; + } + + public override void OnStartServer() + { + base.OnStartServer(); + NetworkServer.RegisterHandler(OnCreatePlayer); + } + + public override void OnClientConnect(NetworkConnection conn) + { + base.OnClientConnect(conn); + + // tell the server to create a player with this name + conn.Send(new CreatePlayerMessage { name = PlayerName }); + } + + void OnCreatePlayer(NetworkConnection connection, CreatePlayerMessage createPlayerMessage) + { + // create a gameobject using the name supplied by client + GameObject playergo = Instantiate(playerPrefab); + playergo.GetComponent().playerName = createPlayerMessage.name; + + // set it as the player + NetworkServer.AddPlayerForConnection(connection, playergo); + + chatWindow.gameObject.SetActive(true); + } + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta new file mode 100644 index 0000000..fd00d18 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0cd72391a563461f88eb3ddf120efef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatWindow.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatWindow.cs new file mode 100644 index 0000000..821d01c --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatWindow.cs @@ -0,0 +1,60 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.Chat +{ + public class ChatWindow : MonoBehaviour + { + public InputField chatMessage; + public Text chatHistory; + public Scrollbar scrollbar; + + public void Awake() + { + Player.OnMessage += OnPlayerMessage; + } + + void OnPlayerMessage(Player player, string message) + { + string prettyMessage = player.isLocalPlayer ? + $"{player.playerName}: {message}" : + $"{player.playerName}: {message}"; + AppendMessage(prettyMessage); + + Debug.Log(message); + } + + // Called by UI element SendButton.OnClick + public void OnSend() + { + if (chatMessage.text.Trim() == "") + return; + + // get our player + Player player = NetworkClient.connection.identity.GetComponent(); + + // send a message + player.CmdSend(chatMessage.text.Trim()); + + chatMessage.text = ""; + } + + internal void AppendMessage(string message) + { + StartCoroutine(AppendAndScroll(message)); + } + + IEnumerator AppendAndScroll(string message) + { + chatHistory.text += message + "\n"; + + // it takes 2 frames for the UI to update ?!?! + yield return null; + yield return null; + + // slam the scrollbar down + scrollbar.value = 0; + } + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatWindow.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatWindow.cs.meta new file mode 100644 index 0000000..6b6dedb --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c102f62d739545269250f48327d4429 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Chat/Scripts/Player.cs b/Assets/Mirror/Examples/Chat/Scripts/Player.cs new file mode 100644 index 0000000..3aa0d2f --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/Player.cs @@ -0,0 +1,25 @@ +using System; + +namespace Mirror.Examples.Chat +{ + public class Player : NetworkBehaviour + { + [SyncVar] + public string playerName; + + public static event Action OnMessage; + + [Command] + public void CmdSend(string message) + { + if (message.Trim() != "") + RpcReceive(message.Trim()); + } + + [ClientRpc] + public void RpcReceive(string message) + { + OnMessage?.Invoke(this, message); + } + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta new file mode 100644 index 0000000..4a7ac91 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3addc5ad220944ed6888319897606739 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Discovery.meta b/Assets/Mirror/Examples/Discovery.meta new file mode 100644 index 0000000..ba76865 --- /dev/null +++ b/Assets/Mirror/Examples/Discovery.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 450d6133608b04c57a6ebd6830d455fd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Discovery/Prefabs.meta b/Assets/Mirror/Examples/Discovery/Prefabs.meta new file mode 100644 index 0000000..b9080f8 --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d8abc53a4efb4544ad9cb7a44b4840a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab new file mode 100644 index 0000000..2d917ed --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab @@ -0,0 +1,110 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &9081919128954505657 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8463701767414927392} + - component: {fileID: 435337138507318507} + - component: {fileID: 8589595951595565844} + - component: {fileID: 8188542106662419882} + - component: {fileID: 1410032569926419539} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8463701767414927392 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &435337138507318507 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8589595951595565844 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!136 &8188542106662419882 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &1410032569926419539 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + serverOnly: 0 + m_AssetId: + m_SceneId: 0 diff --git a/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..c40645c --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ecd52c53a6ef7496693343d3e32dace1 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Discovery/Scenes.meta b/Assets/Mirror/Examples/Discovery/Scenes.meta new file mode 100644 index 0000000..4cf810a --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ceaf2344f4e6944258442667a9fbbfdf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity b/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity new file mode 100644 index 0000000..658d03b --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity @@ -0,0 +1,731 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 2 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &62199026 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 62199028} + - component: {fileID: 62199027} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &62199027 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62199026} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &62199028 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62199026} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &441913360 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 441913362} + - component: {fileID: 441913361} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &441913361 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441913360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &441913362 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441913360} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.78, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &919124423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 919124425} + - component: {fileID: 919124424} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &919124424 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919124423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &919124425 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919124423} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.09, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &970214386 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 970214388} + - component: {fileID: 970214387} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &970214387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 970214386} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &970214388 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 970214386} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.99, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1392889995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1392889998} + - component: {fileID: 1392889997} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &1392889997 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1392889995} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1392889998 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1392889995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1556883243 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1556883247} + - component: {fileID: 1556883245} + - component: {fileID: 1556883244} + - component: {fileID: 1556883248} + - component: {fileID: 1556883246} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1556883244 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + NoDelay: 1 + Interval: 10 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1556883245 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + runInBackground: 1 + autoStartServerBuild: 1 + showDebugMessages: 0 + serverTickRate: 30 + serverBatching: 0 + serverBatchInterval: 0 + offlineScene: + onlineScene: + transport: {fileID: 1556883244} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 9081919128954505657, guid: ecd52c53a6ef7496693343d3e32dace1, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 0 + spawnPrefabs: [] +--- !u!114 &1556883246 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 88c37d3deca7a834d80cfd8d3cfcc510, type: 3} + m_Name: + m_EditorClassIdentifier: + networkDiscovery: {fileID: 1556883248} +--- !u!4 &1556883247 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1556883248 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c761308e733c51245b2e8bb4201f46dc, type: 3} + m_Name: + m_EditorClassIdentifier: + secretHandshake: 1558261479176021378 + serverBroadcastListenPort: 47777 + ActiveDiscoveryInterval: 3 + transport: {fileID: 0} + OnServerFound: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1556883246} + m_MethodName: OnDiscoveredServer + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &1611696151 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1611696153} + - component: {fileID: 1611696152} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1611696152 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1611696151} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1611696153 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1611696151} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4.6, y: 0, z: -1.43} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1730851146 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1730851148} + - component: {fileID: 1730851147} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1730851147 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1730851146} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1730851148 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1730851146} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1911023976 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1911023978} + - component: {fileID: 1911023977} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1911023977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911023976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1911023978 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911023976} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.78, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1958729888 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1958729890} + - component: {fileID: 1958729889} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1958729889 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1958729888} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1958729890 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1958729888} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4.6, y: 0, z: -4.08} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2054361114 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054361116} + - component: {fileID: 2054361115} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2054361115 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054361114} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &2054361116 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054361114} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.99, y: 0, z: -1.43} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity.meta b/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity.meta new file mode 100644 index 0000000..1f4f24e --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 90fddc74fa21c423599167eb28b09dd1 +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/Mirror.Examples.asmdef b/Assets/Mirror/Examples/Mirror.Examples.asmdef new file mode 100644 index 0000000..c4f942e --- /dev/null +++ b/Assets/Mirror/Examples/Mirror.Examples.asmdef @@ -0,0 +1,15 @@ +{ + "name": "Mirror.Examples", + "references": [ + "Mirror", + "Mirror.Components" + ], + "optionalUnityReferences": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/Mirror.Examples.asmdef.meta b/Assets/Mirror/Examples/Mirror.Examples.asmdef.meta new file mode 100644 index 0000000..b68d67b --- /dev/null +++ b/Assets/Mirror/Examples/Mirror.Examples.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fecf25954bb196642ab50657689761d6 +AssemblyDefinitionImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes.meta new file mode 100644 index 0000000..d9d9280 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 792b2d05e371c3c47ac7c4b1fa0dbfe2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta new file mode 100644 index 0000000..edd3710 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef54d3fc8c3b6c845bb29f2d04ea7edb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta new file mode 100644 index 0000000..13d0938 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5ae92b6f97224e418115c9f16c50fd8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial new file mode 100644 index 0000000..d350850 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Icosphere + dynamicFriction: 0.4 + staticFriction: 0.5 + bounciness: 0.8 + frictionCombine: 1 + bounceCombine: 2 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta new file mode 100644 index 0000000..7bb76bd --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47163bc0301c1a146bbaa4d539a6ac36 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial new file mode 100644 index 0000000..bd2d613 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Player + dynamicFriction: 0.3 + staticFriction: 0.5 + bounciness: 0.2 + frictionCombine: 1 + bounceCombine: 2 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta new file mode 100644 index 0000000..2016cde --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2debad4ac21a6644faf4fc93bd5b5869 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial new file mode 100644 index 0000000..43d6617 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: RoomBounce + dynamicFriction: 0.8 + staticFriction: 0.8 + bounciness: 0.8 + frictionCombine: 1 + bounceCombine: 2 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta new file mode 100644 index 0000000..9a6653e --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e179c076d5d0924dbf5a2de0630bdb1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta new file mode 100644 index 0000000..26b8d43 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e79e44ac19c0d9244bb54a0e960210e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat new file mode 100644 index 0000000..f39520d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: PlayArea + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _NORMALMAP _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 2800000, guid: 1ef4aad253cf7e9488305da905643f09, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 8, y: 8} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: 0ce4715b95ec59e4ca799c740a5e144a, type: 3} + m_Scale: {x: 8, y: 8} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.8867924, g: 0.84346247, b: 0.7654859, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta new file mode 100644 index 0000000..dcdfd42 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 42fe0bcfbb65da3429ae2c289686e024 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat new file mode 100644 index 0000000..a394fe1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Player + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta new file mode 100644 index 0000000..1c930eb --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2089070a3452e6f4d866c53e51aae8f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat new file mode 100644 index 0000000..08f5003 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Prize + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta new file mode 100644 index 0000000..551120b --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2becd2014627a774e9e8f668f281f1d2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta new file mode 100644 index 0000000..0cf8693 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 758bdb1e6d29abf4e96198a11d34f313 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta new file mode 100644 index 0000000..45126aa --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea3fb2e0d8b9abc43b8b628e3e550872 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj new file mode 100644 index 0000000..c6dcf15 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj @@ -0,0 +1,119 @@ +mtllib ./IcosphereC.mtl +g Icosphere +v 1.192093E-07 0.187595 0.9822463 +v 0.5257312 0.7946554 0.3035289 +v 0.8506509 -0.1875913 0.4911242 +v -0.5257308 0.7946554 0.3035289 +v 1.192093E-07 0.7946525 -0.6070641 +v 0.8506509 0.1875908 -0.4911239 +v -0.8506508 -0.1875913 0.4911242 +v 1.192093E-07 -0.7946531 0.6070642 +v 0.5257312 -0.7946556 -0.3035287 +v 1.192093E-07 -0.1875954 -0.9822463 +v -0.8506508 0.1875908 -0.4911239 +v -0.5257308 -0.7946556 -0.3035287 + +vn 0.5773501 0.3333353 0.7453553 +vn 0 0.7453575 0.666665 +vn 0 1 -3.272848E-06 +vn 0.5773502 0.745355 -0.3333357 +vn 0.9341724 0.3333336 0.127321 +vn -0.57735 0.3333354 0.7453552 +vn 0.3568219 -0.3333308 0.8726791 +vn 0.9341724 -0.3333337 -0.127321 +vn 0.3568221 0.3333309 -0.8726789 +vn -0.5773502 0.745355 -0.3333356 +vn -0.5773502 -0.7453552 0.3333353 +vn 0 -1 2.749192E-06 +vn 0 -0.7453578 -0.6666646 +vn -0.5773502 -0.3333355 -0.7453551 +vn -0.9341723 -0.3333339 -0.1273212 +vn -0.3568219 -0.3333308 0.8726791 +vn 0.5773503 -0.7453551 0.3333354 +vn 0.5773503 -0.3333354 -0.7453551 +vn -0.356822 0.3333309 -0.8726789 +vn -0.9341723 0.3333338 0.1273211 + +vt -0.5257311 1.376382 +vt 0 1.701302 +vt 0.3249197 0.8506508 +vt 1.051462 0 +vt 0 0 +vt 0.5257311 0.8506508 +vt 0.5257311 -0.8506508 +vt 0 0 +vt 1.051462 0 +vt -0.3249197 0.8506508 +vt 0 1.701302 +vt 0.5257311 1.376382 +vt -0.5257311 0.8506508 +vt 0 1.701302 +vt 0.5257311 0.8506508 +vt -1.376382 0.8506508 +vt -1.051462 1.701302 +vt -0.5257311 1.376382 +vt -0.5257311 0.3249197 +vt -0.5257311 1.376382 +vt 0.3249197 0.8506508 +vt 0 0 +vt -0.5257311 0.8506508 +vt 0.5257311 0.8506508 +vt 0.5257311 0.3249197 +vt -0.3249197 0.8506508 +vt 0.5257311 1.376382 +vt 1.376382 0.8506508 +vt 0.5257311 1.376382 +vt 1.051462 1.701302 +vt -0.5257311 0.3249197 +vt -1.051462 0 +vt -1.376382 0.8506508 +vt 0 0 +vt -1.051462 0 +vt -0.5257311 0.8506508 +vt -0.5257311 -0.8506508 +vt -1.051462 0 +vt 0 0 +vt 1.376382 0.8506508 +vt 1.051462 0 +vt 0.5257311 0.3249197 +vt 0.5257311 0.8506508 +vt 0 0 +vt -0.5257311 0.8506508 +vt -0.5257311 1.376382 +vt -0.5257311 0.3249197 +vt -1.376382 0.8506508 +vt 0.3249197 0.8506508 +vt 0 0 +vt -0.5257311 0.3249197 +vt -0.3249197 0.8506508 +vt 0.5257311 0.3249197 +vt 0 0 +vt 0.5257311 1.376382 +vt 1.376382 0.8506508 +vt 0.5257311 0.3249197 +vt 0 1.701302 +vt 0.5257311 0.8506508 +vt -0.5257311 0.8506508 + +usemtl IcosphereMat +usemap IcosphereMat +f 3/3/1 2/2/1 1/1/1 +f 1/6/2 2/5/2 4/4/2 +f 4/9/3 2/8/3 5/7/3 +f 5/12/4 2/11/4 6/10/4 +f 6/15/5 2/14/5 3/13/5 +f 1/18/6 4/17/6 7/16/6 +f 3/21/7 1/20/7 8/19/7 +f 6/24/8 3/23/8 9/22/8 +f 5/27/9 6/26/9 10/25/9 +f 4/30/10 5/29/10 11/28/10 +f 7/33/11 12/32/11 8/31/11 +f 8/36/12 12/35/12 9/34/12 +f 9/39/13 12/38/13 10/37/13 +f 10/42/14 12/41/14 11/40/14 +f 11/45/15 12/44/15 7/43/15 +f 7/48/16 8/47/16 1/46/16 +f 8/51/17 9/50/17 3/49/17 +f 9/54/18 10/53/18 6/52/18 +f 10/57/19 11/56/19 5/55/19 +f 11/60/20 7/59/20 4/58/20 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta new file mode 100644 index 0000000..26d5bc8 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 1fe56a0e685b8434ebfeb53c69b59a5e +ModelImporter: + serializedVersion: 23 + fileIDToRecycleName: + 100000: Icosphere + 100002: //RootNode + 400000: Icosphere + 400002: //RootNode + 2100000: IcosphereMat + 2300000: Icosphere + 3300000: Icosphere + 4300000: Icosphere + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: ProBuilderDefault + second: {fileID: 2100000, guid: 883a7db7f994aab478a4380ad50eda70, type: 2} + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + motionNodeName: '' + rigImportErrors: '' + rigImportWarnings: '' + animationImportErrors: '' + animationImportWarnings: '' + animationRetargetingWarnings: '' + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + keepQuads: 0 + weldVertices: 1 + preserveHierarchy: 0 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + useFileScale: 1 + previousCalculatedGlobalScale: 1 + hasPreviousCalculatedGlobalScale: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + serializedVersion: 2 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + rootMotionBoneName: '' + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 0 + humanoidOversampling: 1 + additionalBone: 0 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta new file mode 100644 index 0000000..a9904b2 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2c07f54121eb4534e85f72041ec0f196 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat new file mode 100644 index 0000000..e01a611 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Icosphere + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta new file mode 100644 index 0000000..4fb049f --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e6bf26596c6f564097734c7cc319e15 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta new file mode 100644 index 0000000..41ae6a3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90a1d98ef5d99304095438cdf9cbdc10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab new file mode 100644 index 0000000..16b861d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab @@ -0,0 +1,221 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5513112217680870096 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5513112217680897776} + - component: {fileID: 5513112217677473488} + - component: {fileID: 5513112217678603280} + - component: {fileID: 456454062324168415} + m_Layer: 0 + m_Name: Icosphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5513112217680897776 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5513112217680897778} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &5513112217677473488 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_Mesh: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} +--- !u!23 &5513112217678603280 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!64 &456454062324168415 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_Material: {fileID: 13400000, guid: 47163bc0301c1a146bbaa4d539a6ac36, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 1 + m_CookingOptions: 30 + m_Mesh: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} +--- !u!1 &5513112217680870098 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5513112217680897778} + - component: {fileID: -7012348765844800875} + - component: {fileID: -5073764247860119520} + - component: {fileID: 8774992865005872063} + - component: {fileID: -73998256042230442} + - component: {fileID: -2850352209440038129} + m_Layer: 0 + m_Name: Icosphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5513112217680897778 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 0.8, y: 0.8, z: 0.8} + m_Children: + - {fileID: 5513112217680897776} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &-7012348765844800875 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: + hasSpawned: 0 +--- !u!114 &-5073764247860119520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0 + clientAuthority: 0 + localPositionSensitivity: 0.01 + localRotationSensitivity: 0.01 + localScaleSensitivity: 0.01 + compressRotation: 0 + interpolateScale: 0 + interpolateRotation: 1 + interpolatePosition: 1 + syncScale: 0 +--- !u!114 &8774992865005872063 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 218520098fbe58b4b8f0963ef41953f7, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!54 &-73998256042230442 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + serializedVersion: 2 + m_Mass: 0.1 + m_Drag: 0.1 + m_AngularDrag: 0 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &-2850352209440038129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c709489168fec9348b7f8290ee2e8466, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + force: 12 + rigidbody3D: {fileID: -73998256042230442} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta new file mode 100644 index 0000000..aad8827 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a104de86221e66a48832c222471d4f1e +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab new file mode 100644 index 0000000..565f254 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab @@ -0,0 +1,349 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1430875437483682 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4216737524944602} + - component: {fileID: 33190644788701022} + - component: {fileID: 23708975923909982} + m_Layer: 0 + m_Name: Visor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4216737524944602 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.39999998, z: 0.5} + m_LocalScale: {x: 0.5, y: 0.1, z: 0.2} + m_Children: [] + m_Father: {fileID: 3138541494209382947} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &33190644788701022 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &23708975923909982 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &1480027675339556 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4822224316094678} + - component: {fileID: 114402732107420660} + - component: {fileID: 114265392388239132} + - component: {fileID: 143011667059871024} + - component: {fileID: 4839740653866577337} + - component: {fileID: 1849877933717427647} + - component: {fileID: 114892629901890886} + - component: {fileID: 6261579163786439309} + - component: {fileID: 115187108610643062} + m_Layer: 0 + m_Name: Player + m_TagString: Player + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4822224316094678 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3138541494209382947} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &114402732107420660 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: + hasSpawned: 0 +--- !u!114 &114265392388239132 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0 + clientAuthority: 1 + localPositionSensitivity: 0.01 + localRotationSensitivity: 0.01 + localScaleSensitivity: 0.01 + compressRotation: 0 + interpolateScale: 0 + interpolateRotation: 1 + interpolatePosition: 1 + syncScale: 0 +--- !u!143 &143011667059871024 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.001 + m_MinMoveDistance: 0.001 + m_Center: {x: 0, y: 0, z: 0} +--- !u!136 &4839740653866577337 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Material: {fileID: 13400000, guid: 2debad4ac21a6644faf4fc93bd5b5869, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.8 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &1849877933717427647 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &114892629901890886 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 479a5196564ede84791870b414a13645, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 143011667059871024} + moveSpeed: 8 + turnSensitivity: 5 + maxTurnSpeed: 150 + horizontal: 0 + vertical: 0 + turn: 0 + jumpSpeed: 0 + isGrounded: 1 + isFalling: 0 + velocity: {x: 0, y: 0, z: 0} +--- !u!114 &6261579163786439309 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 218520098fbe58b4b8f0963ef41953f7, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!114 &115187108610643062 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8be750efa9df50f47b65ae156053d149, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0 + playerNumber: 0 + scoreIndex: 0 + matchIndex: 0 + score: 0 + clientMatchIndex: -1 +--- !u!1 &4926068573968176962 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3138541494209382947} + - component: {fileID: 1736510165009824269} + - component: {fileID: 4008900414740136170} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3138541494209382947 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4216737524944602} + m_Father: {fileID: 4822224316094678} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1736510165009824269 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &4008900414740136170 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2089070a3452e6f4d866c53e51aae8f2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..16c9602 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f4d376d8ca693049abd1744e4c79fad +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab new file mode 100644 index 0000000..c08171f --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab @@ -0,0 +1,196 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1139254171913846 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4362442735993418} + - component: {fileID: 135606878775227198} + - component: {fileID: 6909319328281960030} + - component: {fileID: 114251241889735402} + - component: {fileID: 114048121767222990} + - component: {fileID: 7669440687796875101} + m_Layer: 0 + m_Name: Prize + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &4362442735993418 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7524893234998283593} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!135 &135606878775227198 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.3 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &6909319328281960030 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &114251241889735402 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: + hasSpawned: 0 +--- !u!114 &114048121767222990 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 10da7fdf8caa1eb4697658bf129457fa, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + available: 1 + randomColor: {fileID: 7669440687796875101} +--- !u!114 &7669440687796875101 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 218520098fbe58b4b8f0963ef41953f7, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!1 &5133204039361288107 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7524893234998283593} + - component: {fileID: 8440477969432842110} + - component: {fileID: 6355089084613864400} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7524893234998283593 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5133204039361288107} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.3, y: 0.3, z: 0.3} + m_Children: [] + m_Father: {fileID: 4362442735993418} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8440477969432842110 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5133204039361288107} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6355089084613864400 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5133204039361288107} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2becd2014627a774e9e8f668f281f1d2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab.meta new file mode 100644 index 0000000..8bdf5f1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8cec47ed46e0eff45966a5173d3aa0d3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md new file mode 100644 index 0000000..29fd22a --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md @@ -0,0 +1,34 @@ +# Multiple Additive Scenes Example + +In Build Settings, remove all scenes and add both of the scenes from the Scenes folder in the following order: + +- Main +- Game + +Open the Main scene in the Editor and make sure the Game Scene field in the MultiScene Network Manager on the Network scene object contains the Game scene. This is already setup by default, but if the Main scene was opened and saved before putting the scenes in the Build Settings list, the Game Scene field may be cleared accidentally. + +## MultiScene Network Manager + +The MultiScene Network Manager is derived from the base Network Manager and is responsible for additively loading the subscene instances and placing the players in their respective subscene instances and initializing player SyncVars. It has a Game Scene field where the Game subscene is assigned, and an Instances field to set how many instances are loaded on the server. + +In this example, the subscene instances are additively loaded on the server with `localPhysicsMode = LocalPhysicsMode.Physics3D`. Physics subscenes do not auto-simulate, so each scene has a game object with a generic `PhysicsSimulator` script on it. This script does nothing on the client, only on the server. + +Clients only ever have one instance of the subscene additively loaded (without `localPhysicsMode`), while server has them all. All networked objects have a `NetworkSceneChecker` component which is what isolates them to their specific subscene. + +## Playing in the Instances + +File -\> Build and Run + +Start at least 3 built instances: These will all be client players. + +Press Play in the Editor and click Host (Server + Client) in the HUD - This will be the host and the 1st player. You can also use Server Only if you prefer. + +Click Client in the built instances. + +- WASDQE keys to move & turn your player capsule, Space to jump. + +- Colliding with the small colored spheres scores points base on their color. + +- Colliding with the larger tumblers sends them rolling around...they're server-side non-kinematic rigidbodies. + +- Only scores for the players in the same subscene are shown at the top of the game window. diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta new file mode 100644 index 0000000..dbf036c --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 915d7b115a88c7c409dadf5bfc543737 +TextScriptImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta new file mode 100644 index 0000000..01b8f9d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 060de58cc46acdf4b92e21c43400aa58 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity new file mode 100644 index 0000000..7227de4 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity @@ -0,0 +1,735 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000002, guid: 83612f89e0d5b404fbd99891bda78df4, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &473309615 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 473309616} + m_Layer: 0 + m_Name: Tumblers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &473309616 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 473309615} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 535961556} + - {fileID: 1069065321} + - {fileID: 2061474489} + - {fileID: 1072549450} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &535961555 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 2357680917 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &535961556 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 535961555} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1069065320 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 2631545699 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &1069065321 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 1069065320} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1072549449 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 634817531 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &1072549450 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 1072549449} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1305256737 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1305256745} + - component: {fileID: 1305256744} + - component: {fileID: 1305256742} + - component: {fileID: 1305256743} + - component: {fileID: 1305256741} + - component: {fileID: 1305256740} + - component: {fileID: 1305256739} + - component: {fileID: 1305256738} + m_Layer: 0 + m_Name: PlayArea + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &1305256738 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 8, z: 0.1} + m_Center: {x: 0, y: 4, z: 5} +--- !u!65 &1305256739 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 8, z: 0.1} + m_Center: {x: 0, y: 4, z: -5} +--- !u!65 &1305256740 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 8, z: 10} + m_Center: {x: 5, y: 4, z: 0} +--- !u!65 &1305256741 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 8, z: 10} + m_Center: {x: -5, y: 4, z: 0} +--- !u!23 &1305256742 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 42fe0bcfbb65da3429ae2c289686e024, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!64 &1305256743 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &1305256744 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1305256745 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 4, y: 1, z: 4} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1713236906 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1713236908} + - component: {fileID: 1713236907} + m_Layer: 0 + m_Name: PhysicsSimulator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1713236907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1713236906} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 78e3051d2c03f27429276d8a55a6d15c, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1713236908 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1713236906} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &2061474488 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 2066882912 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &2061474489 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 2061474488} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity.meta new file mode 100644 index 0000000..274c183 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d45ed07e5475d4740812c97ae565255c +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity new file mode 100644 index 0000000..b01ced7 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity @@ -0,0 +1,801 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 690741348} + m_IndirectSpecularColor: {r: 0.17276844, g: 0.21589246, b: 0.2978263, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &2272925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2272928} + - component: {fileID: 2272927} + - component: {fileID: 2272926} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &2272926 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2272925} + m_Enabled: 1 +--- !u!20 &2272927 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2272925} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 25 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &2272928 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2272925} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &69965666 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 69965670} + - component: {fileID: 69965669} + - component: {fileID: 69965667} + - component: {fileID: 69965671} + - component: {fileID: 69965668} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &69965667 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + offsetX: 0 + offsetY: 0 +--- !u!114 &69965668 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b979f26c95d34324ba005bfacfa9c4fc, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &69965669 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b982a1fd37427e64e8310a863d03d2c9, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + PersistNetworkManagerToOfflineScene: 0 + runInBackground: 1 + autoStartServerBuild: 1 + serverTickRate: 30 + offlineScene: + onlineScene: + transport: {fileID: 69965671} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 1480027675339556, guid: 1f4d376d8ca693049abd1744e4c79fad, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 1139254171913846, guid: 8cec47ed46e0eff45966a5173d3aa0d3, type: 3} + rewardPrefab: {fileID: 1139254171913846, guid: 8cec47ed46e0eff45966a5173d3aa0d3, + type: 3} + instances: 2 + gameScene: Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity +--- !u!4 &69965670 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &69965671 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + NonAlloc: 1 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!1 &204334129 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 204334130} + - component: {fileID: 204334131} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &204334130 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 204334129} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &204334131 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 204334129} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &263230754 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 263230755} + - component: {fileID: 263230756} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &263230755 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 263230754} + m_LocalRotation: {x: 0, y: 0.38268343, z: 0, w: 0.92387956} + m_LocalPosition: {x: -15, y: 0, z: -15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0} +--- !u!114 &263230756 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 263230754} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &290557149 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 290557150} + - component: {fileID: 290557151} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &290557150 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 290557149} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: -15, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!114 &290557151 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 290557149} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &690741347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 690741349} + - component: {fileID: 690741348} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &690741348 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 690741347} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.990566, g: 0.9496818, b: 0.82702917, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.7 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &690741349 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 690741347} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &733367779 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 733367780} + - component: {fileID: 733367781} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &733367780 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733367779} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 0, z: 15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!114 &733367781 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733367779} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &990635329 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 990635330} + - component: {fileID: 990635331} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &990635330 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 990635329} + m_LocalRotation: {x: 0, y: 0.92387956, z: 0, w: 0.38268343} + m_LocalPosition: {x: -15, y: 0, z: 15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 135, z: 0} +--- !u!114 &990635331 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 990635329} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1445635739 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1445635740} + m_Layer: 0 + m_Name: StartPositions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1445635740 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1445635739} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 2, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 733367780} + - {fileID: 2127619492} + - {fileID: 1975674813} + - {fileID: 1760045337} + - {fileID: 204334130} + - {fileID: 263230755} + - {fileID: 290557150} + - {fileID: 990635330} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1760045336 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1760045337} + - component: {fileID: 1760045338} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1760045337 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1760045336} + m_LocalRotation: {x: 0, y: 0.3826836, z: -0, w: -0.92387944} + m_LocalPosition: {x: 15, y: 0, z: -15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 315, z: 0} +--- !u!114 &1760045338 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1760045336} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1975674812 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1975674813} + - component: {fileID: 1975674814} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1975674813 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1975674812} + m_LocalRotation: {x: 0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 15, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 270, z: 0} +--- !u!114 &1975674814 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1975674812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2127619491 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2127619492} + - component: {fileID: 2127619493} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2127619492 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2127619491} + m_LocalRotation: {x: 0, y: 0.9238796, z: -0, w: -0.38268325} + m_LocalPosition: {x: 15, y: 0, z: 15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 225, z: 0} +--- !u!114 &2127619493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2127619491} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity.meta new file mode 100644 index 0000000..365d1c5 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0fa8b7965660de64f8aefd6b64f18a08 +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta new file mode 100644 index 0000000..2b4112f --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6d930bed284ca5040b2743524031cc13 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs new file mode 100644 index 0000000..b296e31 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs @@ -0,0 +1,146 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + [AddComponentMenu("")] + public class MultiSceneNetManager : NetworkManager + { + [Header("Spawner Setup")] + [Tooltip("Reward Prefab for the Spawner")] + public GameObject rewardPrefab; + + [Header("MultiScene Setup")] + public int instances = 3; + + [Scene] + public string gameScene; + + // This is set true after server loads all subscene instances + bool subscenesLoaded; + + // subscenes are added to this list as they're loaded + readonly List subScenes = new List(); + + // Sequential index used in round-robin deployment of players into instances and score positioning + int clientIndex; + + #region Server System Callbacks + + /// + /// Called on the server when a client adds a new player with NetworkClient.AddPlayer. + /// The default implementation for this function creates a new player object from the playerPrefab. + /// + /// Connection from client. + public override void OnServerAddPlayer(NetworkConnection conn) + { + StartCoroutine(OnServerAddPlayerDelayed(conn)); + } + + // This delay is mostly for the host player that loads too fast for the + // server to have subscenes async loaded from OnStartServer ahead of it. + IEnumerator OnServerAddPlayerDelayed(NetworkConnection conn) + { + // wait for server to async load all subscenes for game instances + while (!subscenesLoaded) + yield return null; + + // Send Scene message to client to additively load the game scene + conn.Send(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.LoadAdditive }); + + // Wait for end of frame before adding the player to ensure Scene Message goes first + yield return new WaitForEndOfFrame(); + + base.OnServerAddPlayer(conn); + + PlayerScore playerScore = conn.identity.GetComponent(); + playerScore.playerNumber = clientIndex; + playerScore.scoreIndex = clientIndex / subScenes.Count; + playerScore.matchIndex = clientIndex % subScenes.Count; + + clientIndex++; + + // Do this only on server, not on clients + // This is what allows the NetworkSceneChecker on player and scene objects + // to isolate matches per scene instance on server. + if (subScenes.Count > 0) + SceneManager.MoveGameObjectToScene(conn.identity.gameObject, subScenes[clientIndex % subScenes.Count]); + } + + #endregion + + #region Start & Stop Callbacks + + /// + /// This is invoked when a server is started - including when a host is started. + /// StartServer has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartServer() + { + StartCoroutine(ServerLoadSubScenes()); + } + + // We're additively loading scenes, so GetSceneAt(0) will return the main "container" scene, + // therefore we start the index at one and loop through instances value inclusively. + // If instances is zero, the loop is bypassed entirely. + IEnumerator ServerLoadSubScenes() + { + for (int index = 1; index <= instances; index++) + { + yield return SceneManager.LoadSceneAsync(gameScene, new LoadSceneParameters { loadSceneMode = LoadSceneMode.Additive, localPhysicsMode = LocalPhysicsMode.Physics3D }); + + Scene newScene = SceneManager.GetSceneAt(index); + subScenes.Add(newScene); + Spawner.InitialSpawn(newScene); + } + + subscenesLoaded = true; + } + + /// + /// This is called when a server is stopped - including when a host is stopped. + /// + public override void OnStopServer() + { + NetworkServer.SendToAll(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.UnloadAdditive }); + StartCoroutine(ServerUnloadSubScenes()); + clientIndex = 0; + } + + // Unload the subScenes and unused assets and clear the subScenes list. + IEnumerator ServerUnloadSubScenes() + { + for (int index = 0; index < subScenes.Count; index++) + yield return SceneManager.UnloadSceneAsync(subScenes[index]); + + subScenes.Clear(); + subscenesLoaded = false; + + yield return Resources.UnloadUnusedAssets(); + } + + /// + /// This is called when a client is stopped. + /// + public override void OnStopClient() + { + // make sure we're not in host mode + if (mode == NetworkManagerMode.ClientOnly) + StartCoroutine(ClientUnloadSubScenes()); + } + + // Unload all but the active scene, which is the "container" scene + IEnumerator ClientUnloadSubScenes() + { + for (int index = 0; index < SceneManager.sceneCount; index++) + { + if (SceneManager.GetSceneAt(index) != SceneManager.GetActiveScene()) + yield return SceneManager.UnloadSceneAsync(SceneManager.GetSceneAt(index)); + } + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta new file mode 100644 index 0000000..fc86894 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b982a1fd37427e64e8310a863d03d2c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs new file mode 100644 index 0000000..221c00b --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + [RequireComponent(typeof(Rigidbody))] + public class PhysicsCollision : NetworkBehaviour + { + [Tooltip("how forcefully to push this object")] + public float force = 12; + + public Rigidbody rigidbody3D; + + void OnValidate() + { + if (rigidbody3D == null) + rigidbody3D = GetComponent(); + } + + void Start() + { + rigidbody3D.isKinematic = !isServer; + } + + [ServerCallback] + void OnCollisionStay(Collision other) + { + if (other.gameObject.CompareTag("Player")) + { + // get direction from which player is contacting object + Vector3 direction = other.contacts[0].normal; + + // zero the y and normalize so we don't shove this through the floor or launch this over the wall + direction.y = 0; + direction = direction.normalized; + + // push this away from player...a bit less force for host player + if (other.gameObject.GetComponent().connectionToClient.connectionId == NetworkConnection.LocalConnectionId) + rigidbody3D.AddForce(direction * force * .5f); + else + rigidbody3D.AddForce(direction * force); + } + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta new file mode 100644 index 0000000..0aae7a1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c709489168fec9348b7f8290ee2e8466 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs new file mode 100644 index 0000000..a7a7394 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs @@ -0,0 +1,40 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + public class PhysicsSimulator : MonoBehaviour + { + PhysicsScene physicsScene; + PhysicsScene2D physicsScene2D; + + bool simulatePhysicsScene; + bool simulatePhysicsScene2D; + + void Awake() + { + if (NetworkServer.active) + { + physicsScene = gameObject.scene.GetPhysicsScene(); + simulatePhysicsScene = physicsScene.IsValid() && physicsScene != Physics.defaultPhysicsScene; + + physicsScene2D = gameObject.scene.GetPhysicsScene2D(); + simulatePhysicsScene2D = physicsScene2D.IsValid() && physicsScene2D != Physics2D.defaultPhysicsScene; + } + else + { + enabled = false; + } + } + + void FixedUpdate() + { + if (!NetworkServer.active) return; + + if (simulatePhysicsScene) + physicsScene.Simulate(Time.fixedDeltaTime); + + if (simulatePhysicsScene2D) + physicsScene2D.Simulate(Time.fixedDeltaTime); + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs.meta new file mode 100644 index 0000000..fa7c2b5 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 78e3051d2c03f27429276d8a55a6d15c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs new file mode 100644 index 0000000..4d869d1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs @@ -0,0 +1,112 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + [RequireComponent(typeof(CapsuleCollider))] + [RequireComponent(typeof(CharacterController))] + [RequireComponent(typeof(NetworkTransform))] + [RequireComponent(typeof(Rigidbody))] + public class PlayerController : NetworkBehaviour + { + public CharacterController characterController; + + void OnValidate() + { + if (characterController == null) + characterController = GetComponent(); + } + + void Start() + { + characterController.enabled = isLocalPlayer; + } + + public override void OnStartLocalPlayer() + { + Camera.main.orthographic = false; + Camera.main.transform.SetParent(transform); + Camera.main.transform.localPosition = new Vector3(0f, 3f, -8f); + Camera.main.transform.localEulerAngles = new Vector3(10f, 0f, 0f); + } + + void OnDisable() + { + if (isLocalPlayer && Camera.main != null) + { + Camera.main.orthographic = true; + Camera.main.transform.SetParent(null); + SceneManager.MoveGameObjectToScene(Camera.main.gameObject, SceneManager.GetActiveScene()); + Camera.main.transform.localPosition = new Vector3(0f, 70f, 0f); + Camera.main.transform.localEulerAngles = new Vector3(90f, 0f, 0f); + } + } + + [Header("Movement Settings")] + public float moveSpeed = 8f; + public float turnSensitivity = 5f; + public float maxTurnSpeed = 150f; + + [Header("Diagnostics")] + public float horizontal; + public float vertical; + public float turn; + public float jumpSpeed; + public bool isGrounded = true; + public bool isFalling; + public Vector3 velocity; + + void Update() + { + if (!isLocalPlayer || !characterController.enabled) + return; + + horizontal = Input.GetAxis("Horizontal"); + vertical = Input.GetAxis("Vertical"); + + // Q and E cancel each other out, reducing the turn to zero + if (Input.GetKey(KeyCode.Q)) + turn = Mathf.MoveTowards(turn, -maxTurnSpeed, turnSensitivity); + if (Input.GetKey(KeyCode.E)) + turn = Mathf.MoveTowards(turn, maxTurnSpeed, turnSensitivity); + if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E)) + turn = Mathf.MoveTowards(turn, 0, turnSensitivity); + if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E)) + turn = Mathf.MoveTowards(turn, 0, turnSensitivity); + + if (isGrounded) + isFalling = false; + + if ((isGrounded || !isFalling) && jumpSpeed < 1f && Input.GetKey(KeyCode.Space)) + { + jumpSpeed = Mathf.Lerp(jumpSpeed, 1f, 0.5f); + } + else if (!isGrounded) + { + isFalling = true; + jumpSpeed = 0; + } + } + + void FixedUpdate() + { + if (!isLocalPlayer || characterController == null) + return; + + transform.Rotate(0f, turn * Time.fixedDeltaTime, 0f); + + Vector3 direction = new Vector3(horizontal, jumpSpeed, vertical); + direction = Vector3.ClampMagnitude(direction, 1f); + direction = transform.TransformDirection(direction); + direction *= moveSpeed; + + if (jumpSpeed > 0) + characterController.Move(direction * Time.fixedDeltaTime); + else + characterController.SimpleMove(direction); + + isGrounded = characterController.isGrounded; + velocity = characterController.velocity; + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs.meta new file mode 100644 index 0000000..9d5e109 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 479a5196564ede84791870b414a13645 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs new file mode 100644 index 0000000..08238b2 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + public class PlayerScore : NetworkBehaviour + { + [SyncVar] + public int playerNumber; + + [SyncVar] + public int scoreIndex; + + [SyncVar] + public int matchIndex; + + [SyncVar] + public uint score; + + public int clientMatchIndex = -1; + + void OnGUI() + { + if (!isServerOnly && !isLocalPlayer && clientMatchIndex < 0) + clientMatchIndex = NetworkClient.connection.identity.GetComponent().matchIndex; + + if (isLocalPlayer || matchIndex == clientMatchIndex) + GUI.Box(new Rect(10f + (scoreIndex * 110), 10f, 100f, 25f), $"P{playerNumber}: {score}"); + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta new file mode 100644 index 0000000..a20c7ca --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8be750efa9df50f47b65ae156053d149 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs new file mode 100644 index 0000000..d6d2ac8 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + public class RandomColor : NetworkBehaviour + { + public override void OnStartServer() + { + base.OnStartServer(); + color = Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f); + } + + // Color32 packs to 4 bytes + [SyncVar(hook = nameof(SetColor))] + public Color32 color = Color.black; + + // Unity clones the material when GetComponent().material is called + // Cache it here and destroy it in OnDestroy to prevent a memory leak + Material cachedMaterial; + + void SetColor(Color32 _, Color32 newColor) + { + if (cachedMaterial == null) cachedMaterial = GetComponentInChildren().material; + cachedMaterial.color = newColor; + } + + void OnDestroy() + { + Destroy(cachedMaterial); + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs.meta new file mode 100644 index 0000000..7a9c6f1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 218520098fbe58b4b8f0963ef41953f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs new file mode 100644 index 0000000..ea7516d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs @@ -0,0 +1,52 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + [RequireComponent(typeof(RandomColor))] + public class Reward : NetworkBehaviour + { + public bool available = true; + public RandomColor randomColor; + + void OnValidate() + { + if (randomColor == null) + randomColor = GetComponent(); + } + + [ServerCallback] + void OnTriggerEnter(Collider other) + { + if (other.gameObject.CompareTag("Player")) + ClaimPrize(other.gameObject); + } + + // This is called from PlayerController.CmdClaimPrize which is invoked by PlayerController.OnControllerColliderHit + // This only runs on the server + public void ClaimPrize(GameObject player) + { + if (available) + { + // This is a fast switch to prevent two players claiming the prize in a bang-bang close contest for it. + // First hit turns it off, pending the object being destroyed a few frames later. + available = false; + + Color32 color = randomColor.color; + + // calculate the points from the color ... lighter scores higher as the average approaches 255 + // UnityEngine.Color RGB values are float fractions of 255 + uint points = (uint)(((color.r) + (color.g) + (color.b)) / 3); + // Debug.LogFormat(LogType.Log, "Scored {0} points R:{1} G:{2} B:{3}", points, color.r, color.g, color.b); + + // award the points via SyncVar on the PlayerController + player.GetComponent().score += points; + + // spawn a replacement + Spawner.SpawnReward(gameObject.scene); + + // destroy this one + NetworkServer.Destroy(gameObject); + } + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta new file mode 100644 index 0000000..931aa47 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 10da7fdf8caa1eb4697658bf129457fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs new file mode 100644 index 0000000..8646b1b --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + internal class Spawner + { + internal static void InitialSpawn(Scene scene) + { + if (!NetworkServer.active) return; + + for (int i = 0; i < 10; i++) + SpawnReward(scene); + } + + internal static void SpawnReward(Scene scene) + { + if (!NetworkServer.active) return; + + Vector3 spawnPosition = new Vector3(Random.Range(-19, 20), 1, Random.Range(-19, 20)); + GameObject reward = Object.Instantiate(((MultiSceneNetManager)NetworkManager.singleton).rewardPrefab, spawnPosition, Quaternion.identity); + SceneManager.MoveGameObjectToScene(reward, scene); + NetworkServer.Spawn(reward); + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta new file mode 100644 index 0000000..602d86a --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f522bf510b49da44caa9f3ca0ac17f3b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches.meta b/Assets/Mirror/Examples/MultipleMatches.meta new file mode 100644 index 0000000..10786b5 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e1be7be6da8e2448ba40eba0daa44b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs.meta new file mode 100644 index 0000000..c61a3fb --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad2253a5702ed854995bf034be09a1ae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab new file mode 100644 index 0000000..6fb790b --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab @@ -0,0 +1,144 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4903779300334215825 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8667093524748208693} + - component: {fileID: 792638734159983555} + - component: {fileID: 2985632515421915780} + - component: {fileID: 9218727033388977555} + - component: {fileID: 2439948753870522382} + m_Layer: 5 + m_Name: CellGUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8667093524748208693 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + 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_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &792638734159983555 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_CullTransparentMesh: 0 +--- !u!114 &2985632515421915780 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 +--- !u!114 &9218727033388977555 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2985632515421915780} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2439948753870522382} + m_MethodName: MakePlay + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &2439948753870522382 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9cda2a394a443474689a3c6d6044f7b0, type: 3} + m_Name: + m_EditorClassIdentifier: + matchController: {fileID: 0} + cellValue: 0 + image: {fileID: 2985632515421915780} + button: {fileID: 9218727033388977555} + playerIdentity: {fileID: 0} diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta new file mode 100644 index 0000000..a4b23e0 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5ab8c221183f0094eb04b7f6eb569e7b +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab new file mode 100644 index 0000000..cba01f5 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab @@ -0,0 +1,2169 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2555295541931690112 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9152319602512786093} + - component: {fileID: 5340387473365754403} + - component: {fileID: 6419338461327946957} + m_Layer: 5 + m_Name: Grid + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9152319602512786093 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2555295541931690112} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7845801290156398150} + - {fileID: 6007826401523109089} + - {fileID: 2045714052640889548} + - {fileID: 5012654960586055004} + - {fileID: 5768719360570285027} + - {fileID: 3581888124560234741} + - {fileID: 1213482271452262600} + - {fileID: 8092575970934441626} + - {fileID: 134186364329385301} + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -230} + m_SizeDelta: {x: 200, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5340387473365754403 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2555295541931690112} + m_CullTransparentMesh: 0 +--- !u!114 &6419338461327946957 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2555295541931690112} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 50, y: 50} + m_Spacing: {x: 10, y: 10} + m_Constraint: 1 + m_ConstraintCount: 3 +--- !u!1 &2923784255186993310 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2234053401096987375} + - component: {fileID: 7453676321493443231} + - component: {fileID: 4598621321729434398} + - component: {fileID: 4694292283357099176} + - component: {fileID: 1964986598517419573} + - component: {fileID: 400263754679705305} + - component: {fileID: 4082668978785527835} + - component: {fileID: 6069480080749678769} + m_Layer: 5 + m_Name: MatchController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2234053401096987375 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 6235856198463648228} + - {fileID: 9152319602512786093} + - {fileID: 8089560656303244059} + - {fileID: 5427396184031506795} + - {fileID: 3332139760985286172} + - {fileID: 6549136291348945526} + m_Father: {fileID: 0} + 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_Pivot: {x: 0, y: 0} +--- !u!223 &7453676321493443231 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &4598621321729434398 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!225 &4694292283357099176 +CanvasGroup: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_Alpha: 0 + m_Interactable: 0 + m_BlocksRaycasts: 0 + m_IgnoreParentGroups: 0 +--- !u!114 &1964986598517419573 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &400263754679705305 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: e101d385946c91b4c81f318efc723a88 + hasSpawned: 0 +--- !u!114 &4082668978785527835 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5d17e718851449a6879986e45c458fb7, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 +--- !u!114 &6069480080749678769 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9ccb1dd1fc7cc624e9bff1d0d7a5c741, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 + canvasGroup: {fileID: 4694292283357099176} + gameText: {fileID: 3623013869500637742} + exitButton: {fileID: 3578082239447023245} + playAgainButton: {fileID: 505721148531914274} + winCountLocal: {fileID: 1799015512609000790} + winCountOpponent: {fileID: 5140715663012776105} + canvasController: {fileID: 0} + player1: {fileID: 0} + player2: {fileID: 0} + startingPlayer: {fileID: 0} + currentPlayer: {fileID: 0} +--- !u!1 &3002539098384373397 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5427396184031506795} + - component: {fileID: 1482480893644091453} + - component: {fileID: 5971814406204202327} + - component: {fileID: 3578082239447023245} + m_Layer: 5 + m_Name: BackButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5427396184031506795 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6237100814274483571} + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 80, y: -360} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1482480893644091453 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_CullTransparentMesh: 0 +--- !u!114 &5971814406204202327 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &3578082239447023245 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 5971814406204202327} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 6069480080749678769} + m_MethodName: RequestExitGame + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &3827598301957981835 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8089560656303244059} + - component: {fileID: 4347360514208405509} + - component: {fileID: 3285613769939000379} + - component: {fileID: 505721148531914274} + m_Layer: 5 + m_Name: ReplayButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8089560656303244059 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5868794740851378326} + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: -80, y: -360} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4347360514208405509 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_CullTransparentMesh: 0 +--- !u!114 &3285613769939000379 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &505721148531914274 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 3285613769939000379} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 6069480080749678769} + m_MethodName: RequestPlayAgain + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &4626758344199994040 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6549136291348945526} + - component: {fileID: 8917506311834154436} + - component: {fileID: 5140715663012776105} + - component: {fileID: 676122213734729856} + m_Layer: 5 + m_Name: OpponentWinCount + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6549136291348945526 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 200, y: -220} + m_SizeDelta: {x: 150, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8917506311834154436 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_CullTransparentMesh: 0 +--- !u!114 &5140715663012776105 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!114 &676122213734729856 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 1, g: 1, b: 1, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!1 &4990186583940393891 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6235856198463648228} + - component: {fileID: 3131614140979920454} + - component: {fileID: 3623013869500637742} + - component: {fileID: 24521910774297013} + m_Layer: 5 + m_Name: GameText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6235856198463648228 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -100} + m_SizeDelta: {x: 600, y: 134} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3131614140979920454 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_CullTransparentMesh: 0 +--- !u!114 &3623013869500637742 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!114 &24521910774297013 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 1, g: 1, b: 1, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!1 &6520692455078726128 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3332139760985286172} + - component: {fileID: 6960075187593147498} + - component: {fileID: 1799015512609000790} + - component: {fileID: 4004526050613360083} + m_Layer: 5 + m_Name: LocalWinCount + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3332139760985286172 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: -200, y: -220} + m_SizeDelta: {x: 150, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6960075187593147498 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_CullTransparentMesh: 0 +--- !u!114 &1799015512609000790 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!114 &4004526050613360083 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 1, g: 1, b: 1, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!1 &7074721236105841979 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5868794740851378326} + - component: {fileID: 7905154098717810396} + - component: {fileID: 7932145844108874787} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5868794740851378326 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7074721236105841979} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8089560656303244059} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7905154098717810396 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7074721236105841979} + m_CullTransparentMesh: 0 +--- !u!114 &7932145844108874787 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7074721236105841979} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 18 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Play Again +--- !u!1 &8221244113287092374 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6237100814274483571} + - component: {fileID: 5779956055286566608} + - component: {fileID: 630561348298258014} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6237100814274483571 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8221244113287092374} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5427396184031506795} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5779956055286566608 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8221244113287092374} + m_CullTransparentMesh: 0 +--- !u!114 &630561348298258014 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8221244113287092374} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 18 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Back to Lobby +--- !u!1001 &579039501550898351 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 128 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: B3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &8092575970934441626 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 579039501550898351} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1487965888931322995 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: A1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &7845801290156398150 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 1487965888931322995} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2902895493631791574 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 16 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: B2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &5768719360570285027 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 2902895493631791574} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &3109636500741621460 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: B1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &6007826401523109089 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 3109636500741621460} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &4456088094002665321 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: A2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &5012654960586055004 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 4456088094002665321} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &5328567489950307008 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 32 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: C2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &3581888124560234741 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 5328567489950307008} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7216004328368886009 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: C1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &2045714052640889548 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 7216004328368886009} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7534684980187888381 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 64 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: A3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &1213482271452262600 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 7534684980187888381} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &8762608952144385888 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 256 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: C3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &134186364329385301 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 8762608952144385888} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta new file mode 100644 index 0000000..e1cda8d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e101d385946c91b4c81f318efc723a88 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab new file mode 100644 index 0000000..5a929fd --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab @@ -0,0 +1,293 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &732536732566260629 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6013388882030083517} + - component: {fileID: 2895310434674857523} + - component: {fileID: 7191823870515597218} + m_Layer: 5 + m_Name: Players + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6013388882030083517 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 732536732566260629} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3533216216399874122} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -10, y: 0} + m_SizeDelta: {x: 60, y: 30} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &2895310434674857523 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 732536732566260629} + m_CullTransparentMesh: 0 +--- !u!114 &7191823870515597218 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 732536732566260629} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.78431374} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: X / X +--- !u!1 &3533216216399874123 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3533216216399874122} + - component: {fileID: 3533216216399874119} + - component: {fileID: 8159776287394259959} + - component: {fileID: 8871144159682159596} + - component: {fileID: 114572912279416540} + m_Layer: 5 + m_Name: MatchGUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3533216216399874122 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8536989563668766087} + - {fileID: 6013388882030083517} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3533216216399874119 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_CullTransparentMesh: 0 +--- !u!114 &8159776287394259959 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.19607843} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 +--- !u!114 &8871144159682159596 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 2109663825, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8159776287394259959} + toggleTransition: 1 + graphic: {fileID: 0} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 0 +--- !u!114 &114572912279416540 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e875a237ce12c3145b20f17222f10b68, type: 3} + m_Name: + m_EditorClassIdentifier: + image: {fileID: 8159776287394259959} + toggleButton: {fileID: 8871144159682159596} + matchName: {fileID: 4525608779212400833} + playerCount: {fileID: 7191823870515597218} + canvasController: {fileID: 0} +--- !u!1 &5341423849544309394 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8536989563668766087} + - component: {fileID: 3979716480785526962} + - component: {fileID: 4525608779212400833} + m_Layer: 5 + m_Name: Name + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8536989563668766087 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5341423849544309394} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3533216216399874122} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: 200, y: 30} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &3979716480785526962 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5341423849544309394} + m_CullTransparentMesh: 0 +--- !u!114 &4525608779212400833 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5341423849544309394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.78431374} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Match X diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta new file mode 100644 index 0000000..3096ce4 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: df3727c2222378b4ca786485a8b09981 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab new file mode 100644 index 0000000..dd41ad6 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab @@ -0,0 +1,65 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3559083313143303799 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1204658229548937417} + - component: {fileID: 7660209086417859164} + - component: {fileID: -3992624706284245286} + m_Layer: 0 + m_Name: MatchPlayer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1204658229548937417 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3559083313143303799} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &7660209086417859164 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3559083313143303799} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + serverOnly: 0 + visible: 0 + m_AssetId: 11d2414f1e120a14c98cba6866e5348f + hasSpawned: 0 +--- !u!114 &-3992624706284245286 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3559083313143303799} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5d17e718851449a6879986e45c458fb7, type: 3} + m_Name: + m_EditorClassIdentifier: + syncMode: 0 + syncInterval: 0.1 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta new file mode 100644 index 0000000..1c8503f --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 11d2414f1e120a14c98cba6866e5348f +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab new file mode 100644 index 0000000..4c7a2ab --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab @@ -0,0 +1,182 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2742256683483721700 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4805460816392144898} + - component: {fileID: 4240234839557606510} + - component: {fileID: 733636089880751452} + - component: {fileID: 8081368318735942264} + m_Layer: 5 + m_Name: PlayerGUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4805460816392144898 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4975002542353798605} + m_Father: {fileID: 0} + 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: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4240234839557606510 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_CullTransparentMesh: 0 +--- !u!114 &733636089880751452 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.2509804, g: 0.2509804, b: 0.2509804, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 +--- !u!114 &8081368318735942264 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f61e9bc3715eb904b91222a5526f63d8, type: 3} + m_Name: + m_EditorClassIdentifier: + playerName: {fileID: 893070459539714110} +--- !u!1 &4667088617155248724 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4975002542353798605} + - component: {fileID: 8874787277914191185} + - component: {fileID: 893070459539714110} + - component: {fileID: 1559385578385937998} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4975002542353798605 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4805460816392144898} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8874787277914191185 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_CullTransparentMesh: 0 +--- !u!114 &893070459539714110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 25 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Player X +--- !u!114 &1559385578385937998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -900027084, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta new file mode 100644 index 0000000..7dbc934 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 504f86497324bc040be44f6f88b6cc73 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/README.md b/Assets/Mirror/Examples/MultipleMatches/README.md new file mode 100644 index 0000000..a6da1e3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/README.md @@ -0,0 +1,9 @@ +# MultipleMatches Example + +This example demonstrates how to run a large number of non-physics games concurrently in a single game server instance. + +This would be most appropriate for Card, Board, Puzzle, and Arcade games where there is no physics involved, just presentation and messaging. + +While this example is turn-based, real-time games work just as well. + +When a match is started, a MatchController and Player objects are spawned, all with a Network Match Checker component with the same matchId set. Only clients with the same matchID get messages about each others actions and about their own match. They don't receive any data about other matches that may be running concurrently. diff --git a/Assets/Mirror/Examples/MultipleMatches/README.md.meta b/Assets/Mirror/Examples/MultipleMatches/README.md.meta new file mode 100644 index 0000000..3c529de --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9749e23e4e90e0646afc81061710a927 +TextScriptImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Scenes.meta b/Assets/Mirror/Examples/MultipleMatches/Scenes.meta new file mode 100644 index 0000000..085483e --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a92fd9255da5fe9449e612566195a3aa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity b/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity new file mode 100644 index 0000000..993ff0b --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity @@ -0,0 +1,2982 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 1 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 512 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &8446050 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8446051} + - component: {fileID: 8446054} + - component: {fileID: 8446053} + - component: {fileID: 8446052} + m_Layer: 5 + m_Name: JoinButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &8446051 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 73998978} + m_Father: {fileID: 490177806} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 80, y: -160} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &8446052 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8446053} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestJoinMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &8446053 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &8446054 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_CullTransparentMesh: 0 +--- !u!1 &18198962 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 18198963} + - component: {fileID: 18198965} + - component: {fileID: 18198964} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &18198963 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 18198962} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1613178153} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &18198964 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 18198962} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Start +--- !u!222 &18198965 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 18198962} + m_CullTransparentMesh: 0 +--- !u!1 &73998977 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 73998978} + - component: {fileID: 73998980} + - component: {fileID: 73998979} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &73998978 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 73998977} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8446051} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &73998979 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 73998977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Join +--- !u!222 &73998980 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 73998977} + m_CullTransparentMesh: 0 +--- !u!1 &239920241 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 239920242} + - component: {fileID: 239920244} + - component: {fileID: 239920243} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &239920242 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 239920241} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 716626176} + 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: 20, y: 19.999998} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &239920243 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 239920241} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &239920244 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 239920241} + m_CullTransparentMesh: 0 +--- !u!1 &346368339 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 346368340} + - component: {fileID: 346368342} + - component: {fileID: 346368341} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &346368340 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 346368339} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1108207370} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &346368341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 346368339} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Cancel +--- !u!222 &346368342 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 346368339} + m_CullTransparentMesh: 0 +--- !u!1 &490177805 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 490177806} + m_Layer: 5 + m_Name: LobbyView + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &490177806 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 490177805} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1005098734} + - {fileID: 1100846361} + - {fileID: 8446051} + m_Father: {fileID: 2050110697} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -200} + m_SizeDelta: {x: 1, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &492832111 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 492832112} + - component: {fileID: 492832114} + - component: {fileID: 492832113} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &492832112 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492832111} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1205047099} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 19.999998} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &492832113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492832111} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &492832114 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492832111} + m_CullTransparentMesh: 0 +--- !u!1 &647085297 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 647085298} + - component: {fileID: 647085300} + - component: {fileID: 647085299} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &647085298 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 647085297} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2105646339} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &647085299 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 647085297} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Leave +--- !u!222 &647085300 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 647085297} + m_CullTransparentMesh: 0 +--- !u!1 &716626175 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 716626176} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &716626176 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 716626175} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 239920242} + m_Father: {fileID: 816951368} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &777606420 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 777606421} + - component: {fileID: 777606424} + - component: {fileID: 777606423} + - component: {fileID: 777606422} + m_Layer: 5 + m_Name: TitleText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &777606421 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2050110697} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -40} + m_SizeDelta: {x: 360, y: 45} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &777606422 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!114 &777606423 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 35 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Tic-Tac-Toe +--- !u!222 &777606424 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_CullTransparentMesh: 0 +--- !u!1 &814991252 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 814991255} + - component: {fileID: 814991254} + - component: {fileID: 814991253} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &814991253 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 814991252} + m_Enabled: 1 +--- !u!20 &814991254 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 814991252} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.21698111, g: 0.21698111, b: 0.21698111, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &814991255 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 814991252} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &816951367 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 816951368} + - component: {fileID: 816951371} + - component: {fileID: 816951370} + - component: {fileID: 816951369} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &816951368 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 716626176} + m_Father: {fileID: 1005098734} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 20} + m_Pivot: {x: 1, y: 1} +--- !u!114 &816951369 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 239920243} + m_HandleRect: {fileID: 239920242} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &816951370 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &816951371 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_CullTransparentMesh: 0 +--- !u!1 &874070006 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 874070010} + - component: {fileID: 874070009} + - component: {fileID: 874070008} + - component: {fileID: 874070007} + - component: {fileID: 874070011} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &874070007 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + offsetX: 0 + offsetY: 0 +--- !u!114 &874070008 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + NonAlloc: 1 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &874070009 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0b15c78bb8ab8da42a94aa0bc3081814, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + PersistNetworkManagerToOfflineScene: 0 + runInBackground: 1 + autoStartServerBuild: 1 + serverTickRate: 30 + offlineScene: + onlineScene: + transport: {fileID: 874070008} + networkAddress: localhost + maxConnections: 200 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 3559083313143303799, guid: 11d2414f1e120a14c98cba6866e5348f, + type: 3} + autoCreatePlayer: 0 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 2923784255186993310, guid: e101d385946c91b4c81f318efc723a88, type: 3} + canvas: {fileID: 2050110693} + canvasController: {fileID: 2050110698} +--- !u!4 &874070010 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &874070011 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d09f5c8bf2f4747b7a9284ef5d9ce2a7, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1005098733 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1005098734} + - component: {fileID: 1005098737} + - component: {fileID: 1005098736} + - component: {fileID: 1005098735} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1005098734 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1348255964} + - {fileID: 816951368} + m_Father: {fileID: 490177806} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 250} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1005098735 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.19607843} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1005098736 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_CullTransparentMesh: 0 +--- !u!114 &1005098737 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1386671669} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 25 + m_Viewport: {fileID: 1348255964} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 816951369} + m_HorizontalScrollbarVisibility: 0 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: 0 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1100846360 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1100846361} + - component: {fileID: 1100846364} + - component: {fileID: 1100846362} + - component: {fileID: 1100846363} + m_Layer: 5 + m_Name: CreateButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1100846361 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1582884915} + m_Father: {fileID: 490177806} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -80, y: -160} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1100846362 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &1100846363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1100846362} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestCreateMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &1100846364 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_CullTransparentMesh: 0 +--- !u!1 &1108207369 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1108207370} + - component: {fileID: 1108207373} + - component: {fileID: 1108207372} + - component: {fileID: 1108207371} + m_Layer: 5 + m_Name: CancelButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1108207370 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 346368340} + m_Father: {fileID: 1258848447} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -120, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1108207371 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1108207372} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestCancelMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1108207372 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1108207373 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_CullTransparentMesh: 0 +--- !u!1 &1132002899 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1132002900} + - component: {fileID: 1132002903} + - component: {fileID: 1132002902} + - component: {fileID: 1132002901} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1132002900 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1205047099} + m_Father: {fileID: 1538073291} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 25} + m_SizeDelta: {x: 0, y: 70} + m_Pivot: {x: 1, y: 1} +--- !u!114 &1132002901 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 492832113} + m_HandleRect: {fileID: 492832112} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1132002902 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1132002903 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_CullTransparentMesh: 0 +--- !u!1 &1205047098 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1205047099} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1205047099 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1205047098} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 492832112} + m_Father: {fileID: 1132002900} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1258848446 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1258848447} + - component: {fileID: 1258848448} + m_Layer: 5 + m_Name: RoomView + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1258848447 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1258848446} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1538073291} + - {fileID: 2105646339} + - {fileID: 1108207370} + - {fileID: 1986814489} + - {fileID: 1613178153} + m_Father: {fileID: 2050110697} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -200} + m_SizeDelta: {x: 1, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1258848448 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1258848446} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fc0f113afba9a074b9a3e4fb56f16abb, type: 3} + m_Name: + m_EditorClassIdentifier: + playerList: {fileID: 1295888617} + playerPrefab: {fileID: 2742256683483721700, guid: 504f86497324bc040be44f6f88b6cc73, + type: 3} + cancelButton: {fileID: 1108207369} + leaveButton: {fileID: 2105646338} + startButton: {fileID: 1613178154} + owner: 0 +--- !u!1 &1295888617 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1295888618} + - component: {fileID: 1295888620} + - component: {fileID: 1295888619} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1295888618 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1295888617} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1623056866} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: -183} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1295888619 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1295888617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!114 &1295888620 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1295888617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 0 + m_Spacing: 5 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 0 + m_ChildControlWidth: 1 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &1348255963 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1348255964} + - component: {fileID: 1348255967} + - component: {fileID: 1348255966} + - component: {fileID: 1348255965} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1348255964 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1386671669} + m_Father: {fileID: 1005098734} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1348255965 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1348255966 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_CullTransparentMesh: 0 +--- !u!114 &1348255967 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &1386671668 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1386671669} + - component: {fileID: 1386671671} + - component: {fileID: 1386671670} + - component: {fileID: 1386671672} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1386671669 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1348255964} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: -250} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1386671670 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!114 &1386671671 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 0 + m_Spacing: 5 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 0 + m_ChildControlWidth: 1 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!114 &1386671672 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2fafe2cfe61f6974895a912c3755e8f1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_AllowSwitchOff: 1 +--- !u!1 &1538073290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1538073291} + - component: {fileID: 1538073294} + - component: {fileID: 1538073293} + - component: {fileID: 1538073292} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1538073291 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1623056866} + - {fileID: 1132002900} + m_Father: {fileID: 1258848447} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1538073292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.19607843} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1538073293 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_CullTransparentMesh: 0 +--- !u!114 &1538073294 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1295888618} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 25 + m_Viewport: {fileID: 1623056866} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 1132002901} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1582884914 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1582884915} + - component: {fileID: 1582884917} + - component: {fileID: 1582884916} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1582884915 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1582884914} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1100846361} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1582884916 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1582884914} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Create +--- !u!222 &1582884917 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1582884914} + m_CullTransparentMesh: 0 +--- !u!1 &1613178152 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1613178153} + - component: {fileID: 1613178156} + - component: {fileID: 1613178155} + - component: {fileID: 1613178154} + m_Layer: 5 + m_Name: StartButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1613178153 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 18198963} + m_Father: {fileID: 1258848447} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 120, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1613178154 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1613178155} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestStartMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1613178155 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1613178156 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_CullTransparentMesh: 0 +--- !u!1 &1623056865 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1623056866} + - component: {fileID: 1623056869} + - component: {fileID: 1623056868} + - component: {fileID: 1623056867} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1623056866 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1295888618} + m_Father: {fileID: 1538073291} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: -17} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1623056867 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1623056868 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_CullTransparentMesh: 0 +--- !u!114 &1623056869 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &1902615731 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1902615734} + - component: {fileID: 1902615733} + - component: {fileID: 1902615732} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1902615732 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1902615731} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1902615733 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1902615731} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1902615734 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1902615731} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1986814488 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1986814489} + - component: {fileID: 1986814492} + - component: {fileID: 1986814491} + - component: {fileID: 1986814490} + m_Layer: 5 + m_Name: ReadyButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1986814489 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2133592452} + m_Father: {fileID: 1258848447} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1986814490 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1986814491} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestReadyChange + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1986814491 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1986814492 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_CullTransparentMesh: 0 +--- !u!1 &2050110693 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2050110697} + - component: {fileID: 2050110696} + - component: {fileID: 2050110695} + - component: {fileID: 2050110694} + - component: {fileID: 2050110698} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!114 &2050110694 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &2050110695 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &2050110696 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &2050110697 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 777606421} + - {fileID: 490177806} + - {fileID: 1258848447} + m_Father: {fileID: 0} + 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_Pivot: {x: 0, y: 0} +--- !u!114 &2050110698 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c12d7cb6cdb799041927819f22a2c931, type: 3} + m_Name: + m_EditorClassIdentifier: + matchList: {fileID: 1386671668} + matchPrefab: {fileID: 3533216216399874123, guid: df3727c2222378b4ca786485a8b09981, + type: 3} + matchControllerPrefab: {fileID: 2923784255186993310, guid: e101d385946c91b4c81f318efc723a88, + type: 3} + createButton: {fileID: 1100846363} + joinButton: {fileID: 8446052} + lobbyView: {fileID: 490177805} + roomView: {fileID: 1258848446} + roomGUI: {fileID: 1258848448} + toggleGroup: {fileID: 1386671672} +--- !u!1 &2105646338 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2105646339} + - component: {fileID: 2105646342} + - component: {fileID: 2105646341} + - component: {fileID: 2105646340} + m_Layer: 5 + m_Name: LeaveButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2105646339 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 647085298} + m_Father: {fileID: 1258848447} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -120, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2105646340 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2105646341} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestLeaveMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &2105646341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2105646342 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_CullTransparentMesh: 0 +--- !u!1 &2133592451 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2133592452} + - component: {fileID: 2133592454} + - component: {fileID: 2133592453} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2133592452 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2133592451} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1986814489} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2133592453 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2133592451} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Ready +--- !u!222 &2133592454 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2133592451} + m_CullTransparentMesh: 0 diff --git a/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity.meta b/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity.meta new file mode 100644 index 0000000..15b2968 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aa1f875396fa7d348a782cebc2f75d7c +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts.meta b/Assets/Mirror/Examples/MultipleMatches/Scripts.meta new file mode 100644 index 0000000..6e44c51 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d418be768b6d32e4d9c3b8828929c3eb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs new file mode 100644 index 0000000..3eaa1ce --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs @@ -0,0 +1,671 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.MultipleMatch +{ + public class CanvasController : MonoBehaviour + { + /// + /// Match Controllers listen for this to terminate their match and clean up + /// + public event Action OnPlayerDisconnected; + + /// + /// Cross-reference of client that created the corresponding match in openMatches below + /// + internal static readonly Dictionary playerMatches = new Dictionary(); + + /// + /// Open matches that are available for joining + /// + internal static readonly Dictionary openMatches = new Dictionary(); + + /// + /// Network Connections of all players in a match + /// + internal static readonly Dictionary> matchConnections = new Dictionary>(); + + /// + /// Player informations by Network Connection + /// + internal static readonly Dictionary playerInfos = new Dictionary(); + + /// + /// Network Connections that have neither started nor joined a match yet + /// + internal static readonly List waitingConnections = new List(); + + /// + /// GUID of a match the local player has created + /// + internal Guid localPlayerMatch = Guid.Empty; + + /// + /// GUID of a match the local player has joined + /// + internal Guid localJoinedMatch = Guid.Empty; + + /// + /// GUID of a match the local player has selected in the Toggle Group match list + /// + internal Guid selectedMatch = Guid.Empty; + + // Used in UI for "Player #" + int playerIndex = 1; + + [Header("GUI References")] + public GameObject matchList; + public GameObject matchPrefab; + public GameObject matchControllerPrefab; + public Button createButton; + public Button joinButton; + public GameObject lobbyView; + public GameObject roomView; + public RoomGUI roomGUI; + public ToggleGroup toggleGroup; + + #region UI Functions + + // Called from several places to ensure a clean reset + // - MatchNetworkManager.Awake + // - OnStartServer + // - OnStartClient + // - OnClientDisconnect + // - ResetCanvas + internal void InitializeData() + { + playerMatches.Clear(); + openMatches.Clear(); + matchConnections.Clear(); + waitingConnections.Clear(); + localPlayerMatch = Guid.Empty; + localJoinedMatch = Guid.Empty; + } + + // Called from OnStopServer and OnStopClient when shutting down + void ResetCanvas() + { + InitializeData(); + lobbyView.SetActive(false); + roomView.SetActive(false); + gameObject.SetActive(false); + } + + #endregion + + #region Button Calls + + /// + /// Called from + /// + /// + public void SelectMatch(Guid matchId) + { + if (!NetworkClient.active) return; + + if (matchId == Guid.Empty) + { + selectedMatch = Guid.Empty; + joinButton.interactable = false; + } + else + { + if (!openMatches.Keys.Contains(matchId)) + { + joinButton.interactable = false; + return; + } + + selectedMatch = matchId; + MatchInfo infos = openMatches[matchId]; + joinButton.interactable = infos.players < infos.maxPlayers; + } + } + + /// + /// Assigned in inspector to Create button + /// + public void RequestCreateMatch() + { + if (!NetworkClient.active) return; + + NetworkClient.connection.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Create }); + } + + /// + /// Assigned in inspector to Join button + /// + public void RequestJoinMatch() + { + if (!NetworkClient.active || selectedMatch == Guid.Empty) return; + + NetworkClient.connection.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Join, matchId = selectedMatch }); + } + + /// + /// Assigned in inspector to Leave button + /// + public void RequestLeaveMatch() + { + if (!NetworkClient.active || localJoinedMatch == Guid.Empty) return; + + NetworkClient.connection.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Leave, matchId = localJoinedMatch }); + } + + /// + /// Assigned in inspector to Cancel button + /// + public void RequestCancelMatch() + { + if (!NetworkClient.active || localPlayerMatch == Guid.Empty) return; + + NetworkClient.connection.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Cancel }); + } + + /// + /// Assigned in inspector to Ready button + /// + public void RequestReadyChange() + { + if (!NetworkClient.active || (localPlayerMatch == Guid.Empty && localJoinedMatch == Guid.Empty)) return; + + Guid matchId = localPlayerMatch == Guid.Empty ? localJoinedMatch : localPlayerMatch; + + NetworkClient.connection.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Ready, matchId = matchId }); + } + + /// + /// Assigned in inspector to Start button + /// + public void RequestStartMatch() + { + if (!NetworkClient.active || localPlayerMatch == Guid.Empty) return; + + NetworkClient.connection.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Start }); + } + + /// + /// Called from + /// + public void OnMatchEnded() + { + if (!NetworkClient.active) return; + + localPlayerMatch = Guid.Empty; + localJoinedMatch = Guid.Empty; + ShowLobbyView(); + } + + /// + /// Sends updated match list to all waiting connections or just one if specified + /// + /// + internal void SendMatchList(NetworkConnection conn = null) + { + if (!NetworkServer.active) return; + + if (conn != null) + { + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); + } + else + { + foreach (var waiter in waitingConnections) + { + waiter.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); + } + } + } + + #endregion + + #region Server & Client Callbacks + + // Methods in this section are called from MatchNetworkManager's corresponding methods + + internal void OnStartServer() + { + if (!NetworkServer.active) return; + + InitializeData(); + NetworkServer.RegisterHandler(OnServerMatchMessage); + } + + internal void OnServerReady(NetworkConnection conn) + { + if (!NetworkServer.active) return; + + waitingConnections.Add(conn); + playerInfos.Add(conn, new PlayerInfo { playerIndex = this.playerIndex, ready = false }); + playerIndex++; + + SendMatchList(); + } + + internal void OnServerDisconnect(NetworkConnection conn) + { + if (!NetworkServer.active) return; + + // Invoke OnPlayerDisconnected on all instances of MatchController + OnPlayerDisconnected?.Invoke(conn); + + Guid matchId; + if (playerMatches.TryGetValue(conn, out matchId)) + { + playerMatches.Remove(conn); + openMatches.Remove(matchId); + + foreach (NetworkConnection playerConn in matchConnections[matchId]) + { + PlayerInfo _playerInfo = playerInfos[playerConn]; + _playerInfo.ready = false; + _playerInfo.matchId = Guid.Empty; + playerInfos[playerConn] = _playerInfo; + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); + } + } + + foreach (KeyValuePair> kvp in matchConnections) + { + kvp.Value.Remove(conn); + } + + PlayerInfo playerInfo = playerInfos[conn]; + if (playerInfo.matchId != Guid.Empty) + { + MatchInfo matchInfo; + if (openMatches.TryGetValue(playerInfo.matchId, out matchInfo)) + { + matchInfo.players--; + openMatches[playerInfo.matchId] = matchInfo; + } + + HashSet connections; + if (matchConnections.TryGetValue(playerInfo.matchId, out connections)) + { + PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); + + foreach (NetworkConnection playerConn in matchConnections[playerInfo.matchId]) + { + if (playerConn != conn) + { + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + } + } + } + } + + SendMatchList(); + } + + internal void OnStopServer() + { + ResetCanvas(); + } + + internal void OnClientConnect(NetworkConnection conn) + { + playerInfos.Add(conn, new PlayerInfo { playerIndex = this.playerIndex, ready = false }); + } + + internal void OnStartClient() + { + if (!NetworkClient.active) return; + + InitializeData(); + ShowLobbyView(); + createButton.gameObject.SetActive(true); + joinButton.gameObject.SetActive(true); + NetworkClient.RegisterHandler(OnClientMatchMessage); + } + + internal void OnClientDisconnect() + { + if (!NetworkClient.active) return; + + InitializeData(); + } + + internal void OnStopClient() + { + ResetCanvas(); + } + + #endregion + + #region Server Match Message Handlers + + void OnServerMatchMessage(NetworkConnection conn, ServerMatchMessage msg) + { + if (!NetworkServer.active) return; + + switch (msg.serverMatchOperation) + { + case ServerMatchOperation.None: + { + Debug.LogWarning("Missing ServerMatchOperation"); + break; + } + case ServerMatchOperation.Create: + { + OnServerCreateMatch(conn); + break; + } + case ServerMatchOperation.Cancel: + { + OnServerCancelMatch(conn); + break; + } + case ServerMatchOperation.Start: + { + OnServerStartMatch(conn); + break; + } + case ServerMatchOperation.Join: + { + OnServerJoinMatch(conn, msg.matchId); + break; + } + case ServerMatchOperation.Leave: + { + OnServerLeaveMatch(conn, msg.matchId); + break; + } + case ServerMatchOperation.Ready: + { + OnServerPlayerReady(conn, msg.matchId); + break; + } + } + } + + void OnServerPlayerReady(NetworkConnection conn, Guid matchId) + { + if (!NetworkServer.active) return; + + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = !playerInfo.ready; + playerInfos[conn] = playerInfo; + + HashSet connections = matchConnections[matchId]; + PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); + + foreach (NetworkConnection playerConn in matchConnections[matchId]) + { + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + } + } + + void OnServerLeaveMatch(NetworkConnection conn, Guid matchId) + { + if (!NetworkServer.active) return; + + MatchInfo matchInfo = openMatches[matchId]; + matchInfo.players--; + openMatches[matchId] = matchInfo; + + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = false; + playerInfo.matchId = Guid.Empty; + playerInfos[conn] = playerInfo; + + foreach (KeyValuePair> kvp in matchConnections) + { + kvp.Value.Remove(conn); + } + + HashSet connections = matchConnections[matchId]; + PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); + + foreach (NetworkConnection playerConn in matchConnections[matchId]) + { + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + } + + SendMatchList(); + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); + } + + void OnServerCreateMatch(NetworkConnection conn) + { + if (!NetworkServer.active || playerMatches.ContainsKey(conn)) return; + + Guid newMatchId = Guid.NewGuid(); + matchConnections.Add(newMatchId, new HashSet()); + matchConnections[newMatchId].Add(conn); + playerMatches.Add(conn, newMatchId); + openMatches.Add(newMatchId, new MatchInfo { matchId = newMatchId, maxPlayers = 2, players = 1 }); + + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = false; + playerInfo.matchId = newMatchId; + playerInfos[conn] = playerInfo; + + PlayerInfo[] infos = matchConnections[newMatchId].Select(playerConn => playerInfos[playerConn]).ToArray(); + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Created, matchId = newMatchId, playerInfos = infos }); + + SendMatchList(); + } + + void OnServerCancelMatch(NetworkConnection conn) + { + if (!NetworkServer.active || !playerMatches.ContainsKey(conn)) return; + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Cancelled }); + + Guid matchId; + if (playerMatches.TryGetValue(conn, out matchId)) + { + playerMatches.Remove(conn); + openMatches.Remove(matchId); + + foreach (NetworkConnection playerConn in matchConnections[matchId]) + { + PlayerInfo playerInfo = playerInfos[playerConn]; + playerInfo.ready = false; + playerInfo.matchId = Guid.Empty; + playerInfos[playerConn] = playerInfo; + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); + } + + SendMatchList(); + } + } + + void OnServerStartMatch(NetworkConnection conn) + { + if (!NetworkServer.active || !playerMatches.ContainsKey(conn)) return; + + Guid matchId; + if (playerMatches.TryGetValue(conn, out matchId)) + { + GameObject matchControllerObject = Instantiate(matchControllerPrefab); +#pragma warning disable 618 + matchControllerObject.GetComponent().matchId = matchId; +#pragma warning restore 618 + NetworkServer.Spawn(matchControllerObject); + + MatchController matchController = matchControllerObject.GetComponent(); + + foreach (NetworkConnection playerConn in matchConnections[matchId]) + { + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Started }); + + GameObject player = Instantiate(NetworkManager.singleton.playerPrefab); +#pragma warning disable 618 + player.GetComponent().matchId = matchId; +#pragma warning restore 618 + NetworkServer.AddPlayerForConnection(playerConn, player); + + if (matchController.player1 == null) + { + matchController.player1 = playerConn.identity; + } + else + { + matchController.player2 = playerConn.identity; + } + + /* Reset ready state for after the match. */ + PlayerInfo playerInfo = playerInfos[playerConn]; + playerInfo.ready = false; + playerInfos[playerConn] = playerInfo; + } + + matchController.startingPlayer = matchController.player1; + matchController.currentPlayer = matchController.player1; + + playerMatches.Remove(conn); + openMatches.Remove(matchId); + matchConnections.Remove(matchId); + SendMatchList(); + + OnPlayerDisconnected += matchController.OnPlayerDisconnected; + } + } + + void OnServerJoinMatch(NetworkConnection conn, Guid matchId) + { + if (!NetworkServer.active || !matchConnections.ContainsKey(matchId) || !openMatches.ContainsKey(matchId)) return; + + MatchInfo matchInfo = openMatches[matchId]; + matchInfo.players++; + openMatches[matchId] = matchInfo; + matchConnections[matchId].Add(conn); + + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = false; + playerInfo.matchId = matchId; + playerInfos[conn] = playerInfo; + + PlayerInfo[] infos = matchConnections[matchId].Select(playerConn => playerInfos[playerConn]).ToArray(); + SendMatchList(); + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Joined, matchId = matchId, playerInfos = infos }); + + foreach (NetworkConnection playerConn in matchConnections[matchId]) + { + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + } + } + + #endregion + + #region Client Match Message Handler + + void OnClientMatchMessage(ClientMatchMessage msg) + { + if (!NetworkClient.active) return; + + switch (msg.clientMatchOperation) + { + case ClientMatchOperation.None: + { + Debug.LogWarning("Missing ClientMatchOperation"); + break; + } + case ClientMatchOperation.List: + { + openMatches.Clear(); + foreach (MatchInfo matchInfo in msg.matchInfos) + { + openMatches.Add(matchInfo.matchId, matchInfo); + } + RefreshMatchList(); + break; + } + case ClientMatchOperation.Created: + { + localPlayerMatch = msg.matchId; + ShowRoomView(); + roomGUI.RefreshRoomPlayers(msg.playerInfos); + roomGUI.SetOwner(true); + break; + } + case ClientMatchOperation.Cancelled: + { + localPlayerMatch = Guid.Empty; + ShowLobbyView(); + break; + } + case ClientMatchOperation.Joined: + { + localJoinedMatch = msg.matchId; + ShowRoomView(); + roomGUI.RefreshRoomPlayers(msg.playerInfos); + roomGUI.SetOwner(false); + break; + } + case ClientMatchOperation.Departed: + { + localJoinedMatch = Guid.Empty; + ShowLobbyView(); + break; + } + case ClientMatchOperation.UpdateRoom: + { + roomGUI.RefreshRoomPlayers(msg.playerInfos); + break; + } + case ClientMatchOperation.Started: + { + lobbyView.SetActive(false); + roomView.SetActive(false); + break; + } + } + } + + void ShowLobbyView() + { + lobbyView.SetActive(true); + roomView.SetActive(false); + + foreach (Transform child in matchList.transform) + { + if (child.gameObject.GetComponent().GetMatchId() == selectedMatch) + { + Toggle toggle = child.gameObject.GetComponent(); + toggle.isOn = true; + //toggle.onValueChanged.Invoke(true); + } + } + } + + void ShowRoomView() + { + lobbyView.SetActive(false); + roomView.SetActive(true); + } + + void RefreshMatchList() + { + foreach (Transform child in matchList.transform) + { + Destroy(child.gameObject); + } + + joinButton.interactable = false; + + foreach (MatchInfo matchInfo in openMatches.Values) + { + GameObject newMatch = Instantiate(matchPrefab, Vector3.zero, Quaternion.identity); + newMatch.transform.SetParent(matchList.transform, false); + newMatch.GetComponent().SetMatchInfo(matchInfo); + newMatch.GetComponent().group = toggleGroup; + if (matchInfo.matchId == selectedMatch) + { + newMatch.GetComponent().isOn = true; + } + } + } + + #endregion + + } +} diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta new file mode 100644 index 0000000..99b4f9a --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c12d7cb6cdb799041927819f22a2c931 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs new file mode 100644 index 0000000..1df2ec3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs @@ -0,0 +1,46 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.MultipleMatch +{ + public class CellGUI : MonoBehaviour + { + public MatchController matchController; + public CellValue cellValue; + + [Header("GUI References")] + public Image image; + public Button button; + + [Header("Diagnostics - Do Not Modify")] + public NetworkIdentity playerIdentity; + + + public void Awake() + { + matchController.MatchCells.Add(cellValue, this); + } + + public void MakePlay() + { + if (matchController.currentPlayer.isLocalPlayer) + matchController.CmdMakePlay(cellValue); + } + + public void SetPlayer(NetworkIdentity playerIdentity) + { + if (playerIdentity != null) + { + this.playerIdentity = playerIdentity; + image.color = this.playerIdentity.isLocalPlayer ? Color.blue : Color.red; + button.interactable = false; + } + else + { + this.playerIdentity = null; + image.color = Color.white; + button.interactable = true; + } + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta new file mode 100644 index 0000000..6a7568a --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cda2a394a443474689a3c6d6044f7b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs b/Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs new file mode 100644 index 0000000..339e385 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs @@ -0,0 +1,313 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.MultipleMatch +{ + [RequireComponent(typeof(NetworkMatch))] + public class MatchController : NetworkBehaviour + { + internal readonly SyncDictionary matchPlayerData = new SyncDictionary(); + internal readonly Dictionary MatchCells = new Dictionary(); + + CellValue boardScore = CellValue.None; + bool playAgain = false; + + [Header("GUI References")] + public CanvasGroup canvasGroup; + public Text gameText; + public Button exitButton; + public Button playAgainButton; + public Text winCountLocal; + public Text winCountOpponent; + + [Header("Diagnostics - Do Not Modify")] + public CanvasController canvasController; + public NetworkIdentity player1; + public NetworkIdentity player2; + public NetworkIdentity startingPlayer; + + [SyncVar(hook = nameof(UpdateGameUI))] + public NetworkIdentity currentPlayer; + + void Awake() + { + canvasController = FindObjectOfType(); + } + + public override void OnStartServer() + { + StartCoroutine(AddPlayersToMatchController()); + } + + // For the SyncDictionary to properly fire the update callback, we must + // wait a frame before adding the players to the already spawned MatchController + IEnumerator AddPlayersToMatchController() + { + yield return null; + + matchPlayerData.Add(player1, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player1.connectionToClient].playerIndex }); + matchPlayerData.Add(player2, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player2.connectionToClient].playerIndex }); + } + + + public override void OnStartClient() + { + matchPlayerData.Callback += UpdateWins; + + canvasGroup.alpha = 1f; + canvasGroup.interactable = true; + canvasGroup.blocksRaycasts = true; + + exitButton.gameObject.SetActive(false); + playAgainButton.gameObject.SetActive(false); + } + + public void UpdateGameUI(NetworkIdentity _, NetworkIdentity newPlayerTurn) + { + if (!newPlayerTurn) return; + + if (newPlayerTurn.gameObject.GetComponent().isLocalPlayer) + { + gameText.text = "Your Turn"; + gameText.color = Color.blue; + } + else + { + gameText.text = "Their Turn"; + gameText.color = Color.red; + } + } + + public void UpdateWins(SyncDictionary.Operation op, NetworkIdentity key, MatchPlayerData matchPlayerData) + { + if (key.gameObject.GetComponent().isLocalPlayer) + { + winCountLocal.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}"; + } + else + { + winCountOpponent.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}"; + } + } + + [Command(requiresAuthority = false)] + public void CmdMakePlay(CellValue cellValue, NetworkConnectionToClient sender = null) + { + // If wrong player or cell already taken, ignore + if (sender.identity != currentPlayer || MatchCells[cellValue].playerIdentity != null) + return; + + MatchCells[cellValue].playerIdentity = currentPlayer; + RpcUpdateCell(cellValue, currentPlayer); + + MatchPlayerData mpd = matchPlayerData[currentPlayer]; + mpd.currentScore = mpd.currentScore | cellValue; + matchPlayerData[currentPlayer] = mpd; + + boardScore = boardScore | cellValue; + + if (CheckWinner(mpd.currentScore)) + { + mpd.wins += 1; + matchPlayerData[currentPlayer] = mpd; + RpcShowWinner(currentPlayer); + currentPlayer = null; + } + else if (boardScore == CellValue.Full) + { + RpcShowWinner(null); + currentPlayer = null; + } + else + { + // Set currentPlayer SyncVar so clients know whose turn it is + currentPlayer = currentPlayer == player1 ? player2 : player1; + } + + } + + bool CheckWinner(CellValue currentScore) + { + if ((currentScore & CellValue.TopRow) == CellValue.TopRow) + return true; + if ((currentScore & CellValue.MidRow) == CellValue.MidRow) + return true; + if ((currentScore & CellValue.BotRow) == CellValue.BotRow) + return true; + if ((currentScore & CellValue.LeftCol) == CellValue.LeftCol) + return true; + if ((currentScore & CellValue.MidCol) == CellValue.MidCol) + return true; + if ((currentScore & CellValue.RightCol) == CellValue.RightCol) + return true; + if ((currentScore & CellValue.Diag1) == CellValue.Diag1) + return true; + if ((currentScore & CellValue.Diag2) == CellValue.Diag2) + return true; + + return false; + } + + [ClientRpc] + public void RpcUpdateCell(CellValue cellValue, NetworkIdentity player) + { + MatchCells[cellValue].SetPlayer(player); + } + + [ClientRpc] + public void RpcShowWinner(NetworkIdentity winner) + { + + foreach (CellGUI cellGUI in MatchCells.Values) + cellGUI.GetComponent