From f3cee6510133a3c7240624bb2f3e629bfabe7402 Mon Sep 17 00:00:00 2001 From: fuqunaga Date: Wed, 11 Sep 2024 18:20:10 +0900 Subject: [PATCH 01/32] Upgrade Unity2021.3.20f1 > 2022.3.45f1 --- .../Editor/PrefsGUISyncEditorRosettaUI.cs | 2 +- Packages/manifest.json | 6 +- Packages/packages-lock.json | 71 ++++++------------- .../Settings.json | 2 - ProjectSettings/ProjectVersion.txt | 4 +- ProjectSettings/boot.config | 0 6 files changed, 25 insertions(+), 60 deletions(-) delete mode 100644 ProjectSettings/boot.config diff --git a/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs b/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs index 7b26180..67c9f82 100644 --- a/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs +++ b/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs @@ -13,7 +13,7 @@ public class PrefsGUISyncEditorRosettaUI { static PrefsGUISyncEditorRosettaUI() { - PrefsGUIEditorRosettaUI.RegisterObjCheckExtension(new PrefsGUIEditorRosettaUIObjCheckExtension()); + PrefsGUIEditorWindowRosettaUI.RegisterObjCheckExtension(new PrefsGUIEditorRosettaUIObjCheckExtension()); } private class PrefsGUIEditorRosettaUIObjCheckExtension : IPrefsGUIEditorRosettaUIObjCheckExtension diff --git a/Packages/manifest.json b/Packages/manifest.json index 5444ec1..b3782e5 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,12 +1,10 @@ { "dependencies": { "com.unity.feature.development": "1.0.1", - "com.unity.ide.rider": "3.0.21", - "com.unity.ide.visualstudio": "2.0.18", + "com.unity.ide.rider": "3.0.31", + "com.unity.ide.visualstudio": "2.0.22", "com.unity.ide.vscode": "1.2.5", - "com.unity.textmeshpro": "3.0.6", "com.unity.ugui": "1.0.0", - "com.unity.visualscripting": "1.8.0", "com.veriorpies.parrelsync": "https://github.com/VeriorPies/ParrelSync.git?path=/ParrelSync", "ga.fuquna.prefsgui.rapidgui": "0.0.2", "ga.fuquna.prefsgui.rosettaui": "1.0.2", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 95f9e88..d43e775 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -19,17 +19,17 @@ "depth": 0, "source": "builtin", "dependencies": { - "com.unity.ide.visualstudio": "2.0.17", - "com.unity.ide.rider": "3.0.18", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.rider": "3.0.31", "com.unity.ide.vscode": "1.2.5", "com.unity.editorcoroutines": "1.0.0", "com.unity.performance.profile-analyzer": "1.2.2", - "com.unity.test-framework": "1.1.31", - "com.unity.testtools.codecoverage": "1.2.2" + "com.unity.test-framework": "1.1.33", + "com.unity.testtools.codecoverage": "1.2.6" } }, "com.unity.ide.rider": { - "version": "3.0.21", + "version": "3.0.31", "depth": 0, "source": "registry", "dependencies": { @@ -38,7 +38,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.18", + "version": "2.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -61,14 +61,14 @@ "url": "https://packages.unity.com" }, "com.unity.settings-manager": { - "version": "1.0.3", + "version": "2.0.1", "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.test-framework": { - "version": "1.1.31", + "version": "1.1.33", "depth": 1, "source": "registry", "dependencies": { @@ -79,7 +79,7 @@ "url": "https://packages.unity.com" }, "com.unity.testtools.codecoverage": { - "version": "1.2.2", + "version": "1.2.6", "depth": 1, "source": "registry", "dependencies": { @@ -88,15 +88,6 @@ }, "url": "https://packages.unity.com" }, - "com.unity.textmeshpro": { - "version": "3.0.6", - "depth": 0, - "source": "registry", - "dependencies": { - "com.unity.ugui": "1.0.0" - }, - "url": "https://packages.unity.com" - }, "com.unity.ugui": { "version": "1.0.0", "depth": 0, @@ -106,16 +97,6 @@ "com.unity.modules.imgui": "1.0.0" } }, - "com.unity.visualscripting": { - "version": "1.8.0", - "depth": 0, - "source": "registry", - "dependencies": { - "com.unity.ugui": "1.0.0", - "com.unity.modules.jsonserialize": "1.0.0" - }, - "url": "https://packages.unity.com" - }, "com.veriorpies.parrelsync": { "version": "https://github.com/VeriorPies/ParrelSync.git?path=/ParrelSync", "depth": 0, @@ -141,15 +122,14 @@ "url": "https://registry.npmjs.com" }, "ga.fuquna.prefsgui.rosettaui": { - "version": "1.0.2", + "version": "file:C:/unity/PrefsGUI/Packages/ga.fuquna.prefsgui.rosettaui", "depth": 0, - "source": "registry", + "source": "local", "dependencies": { - "ga.fuquna.prefsgui": "3.2.4", - "ga.fuquna.rosettaui": "1.1.3", - "ga.fuquna.rosettaui.uitoolkit": "1.1.1" - }, - "url": "https://registry.npmjs.com" + "ga.fuquna.prefsgui": "3.4.3", + "ga.fuquna.rosettaui": "1.8.0", + "ga.fuquna.rosettaui.uitoolkit": "1.7.0" + } }, "ga.fuquna.prefsguisyncformirror": { "version": "file:ga.fuquna.prefsguisyncformirror", @@ -167,18 +147,18 @@ "url": "https://registry.npmjs.com" }, "ga.fuquna.rosettaui": { - "version": "1.2.0", - "depth": 0, + "version": "1.8.0", + "depth": 1, "source": "registry", "dependencies": {}, "url": "https://registry.npmjs.com" }, "ga.fuquna.rosettaui.uitoolkit": { - "version": "1.2.2", - "depth": 0, + "version": "1.7.0", + "depth": 1, "source": "registry", "dependencies": { - "ga.fuquna.rosettaui": "1.2.0" + "ga.fuquna.rosettaui": "1.7.0" }, "url": "https://registry.npmjs.com" }, @@ -314,17 +294,6 @@ "version": "1.0.0", "depth": 0, "source": "builtin", - "dependencies": { - "com.unity.modules.ui": "1.0.0", - "com.unity.modules.imgui": "1.0.0", - "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.modules.uielementsnative": "1.0.0" - } - }, - "com.unity.modules.uielementsnative": { - "version": "1.0.0", - "depth": 1, - "source": "builtin", "dependencies": { "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0", diff --git a/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json b/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json index ad11087..3c7b4c1 100644 --- a/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json +++ b/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json @@ -1,6 +1,4 @@ { - "m_Name": "Settings", - "m_Path": "ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json", "m_Dictionary": { "m_DictionaryValues": [] } diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index ed449d8..29c4eee 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2021.3.20f1 -m_EditorVersionWithRevision: 2021.3.20f1 (577897200b8b) +m_EditorVersion: 2022.3.45f1 +m_EditorVersionWithRevision: 2022.3.45f1 (a13dfa44d684) diff --git a/ProjectSettings/boot.config b/ProjectSettings/boot.config deleted file mode 100644 index e69de29..0000000 From 2bcf39c04fe981e2f63ae36676a995cf5b16d83b Mon Sep 17 00:00:00 2001 From: fuqunaga Date: Wed, 11 Sep 2024 18:44:05 +0900 Subject: [PATCH 02/32] fix: PrefsGUISyncEditorRosettaUI support new RosettaUI style --- .../Editor/PrefsGUISyncEditorRosettaUI.cs | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs b/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs index 67c9f82..6adba4b 100644 --- a/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs +++ b/Packages/ga.fuquna.prefsguisyncformirror/Editor/PrefsGUISyncEditorRosettaUI.cs @@ -22,19 +22,31 @@ private class PrefsGUIEditorRosettaUIObjCheckExtension : IPrefsGUIEditorRosettaU public Element PrefsLeft(PrefsParam prefs) { - return UI.Toggle(null, - () => PrefsGUISyncEditorUtility.GetSyncFlag(prefs.key), - flag => PrefsGUISyncEditorUtility.SetSyncFlag(prefs.key, flag) - ).SetHeight(28f); + return BringToTop( + UI.Toggle(null, + () => PrefsGUISyncEditorUtility.GetSyncFlag(prefs.key), + flag => PrefsGUISyncEditorUtility.SetSyncFlag(prefs.key, flag) + ) + ); } public Element PrefsSetLeft(IEnumerable prefsList) { - return UI.Toggle(null, - () => prefsList.Any(prefs => PrefsGUISyncEditorUtility.GetSyncFlag(prefs.key)), - flag => PrefsGUISyncEditorUtility.SetSyncFlags(prefsList.Select(prefs => prefs.key), flag) + return BringToTop( + UI.Toggle(null, + () => prefsList.Any(prefs => PrefsGUISyncEditorUtility.GetSyncFlag(prefs.key)), + flag => PrefsGUISyncEditorUtility.SetSyncFlags(prefsList.Select(prefs => prefs.key), flag) + ) ); } + + private static Element BringToTop(Element element) + { + return UI.Column( + element, + UI.Space() + ).SetFlexGrow(0); // UI.Row()だと横に広がってしまうのを抑制 + } } } } From ca2416d32cccdb89f3db134e41c2b149c0fcc4fa Mon Sep 17 00:00:00 2001 From: fuqunaga Date: Thu, 12 Sep 2024 14:21:59 +0900 Subject: [PATCH 03/32] build(deps): update prefsgui to 3.5.0 --- .idea/.idea.PrefsGUISyncForMirror/.idea/vcs.xml | 2 +- .../package.json | 6 +++--- Packages/manifest.json | 6 +++--- Packages/packages-lock.json | 17 +++++++++-------- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.idea/.idea.PrefsGUISyncForMirror/.idea/vcs.xml b/.idea/.idea.PrefsGUISyncForMirror/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/.idea.PrefsGUISyncForMirror/.idea/vcs.xml +++ b/.idea/.idea.PrefsGUISyncForMirror/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/Packages/ga.fuquna.prefsguisyncformirror/package.json b/Packages/ga.fuquna.prefsguisyncformirror/package.json index 0d245b6..94aad5f 100644 --- a/Packages/ga.fuquna.prefsguisyncformirror/package.json +++ b/Packages/ga.fuquna.prefsguisyncformirror/package.json @@ -2,7 +2,7 @@ "name": "ga.fuquna.prefsguisyncformirror", "displayName": "PrefsGUISync for Mirror", "version": "1.0.4", - "unity": "2021.3", + "unity": "2022.3", "description": "PrefsGUI subset for synchronization over Mirror", "keywords": [ "unity", @@ -12,7 +12,7 @@ ], "category": "Tool", "dependencies": { - "ga.fuquna.prefsgui": "3.2.4" + "ga.fuquna.prefsgui": "3.5.0" }, "author": { "name": "fuqunaga", @@ -23,4 +23,4 @@ "changelogUrl": "https://github.com/fuqunaga/PrefsGUISyncForMirror/blob/main/Packages/ga.fuquna.prefsguisyncformirror/CHANGELOG.md", "repository": "github:fuqunaga/PrefsGUISyncForMirror", "license": "MIT" -} +} \ No newline at end of file diff --git a/Packages/manifest.json b/Packages/manifest.json index b3782e5..bb05bd5 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -7,9 +7,9 @@ "com.unity.ugui": "1.0.0", "com.veriorpies.parrelsync": "https://github.com/VeriorPies/ParrelSync.git?path=/ParrelSync", "ga.fuquna.prefsgui.rapidgui": "0.0.2", - "ga.fuquna.prefsgui.rosettaui": "1.0.2", - "ga.fuquna.rosettaui": "1.2.0", - "ga.fuquna.rosettaui.uitoolkit": "1.2.2", + "ga.fuquna.prefsgui.rosettaui": "1.3.0", + "ga.fuquna.rosettaui": "1.8.0", + "ga.fuquna.rosettaui.uitoolkit": "1.7.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index d43e775..e595f66 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -105,7 +105,7 @@ "hash": "f45424822189ebd875d864a17d7f03b72eafbff7" }, "ga.fuquna.prefsgui": { - "version": "3.2.4", + "version": "3.5.0", "depth": 1, "source": "registry", "dependencies": {}, @@ -122,21 +122,22 @@ "url": "https://registry.npmjs.com" }, "ga.fuquna.prefsgui.rosettaui": { - "version": "file:C:/unity/PrefsGUI/Packages/ga.fuquna.prefsgui.rosettaui", + "version": "1.3.0", "depth": 0, - "source": "local", + "source": "registry", "dependencies": { - "ga.fuquna.prefsgui": "3.4.3", + "ga.fuquna.prefsgui": "3.5.0", "ga.fuquna.rosettaui": "1.8.0", "ga.fuquna.rosettaui.uitoolkit": "1.7.0" - } + }, + "url": "https://registry.npmjs.com" }, "ga.fuquna.prefsguisyncformirror": { "version": "file:ga.fuquna.prefsguisyncformirror", "depth": 0, "source": "embedded", "dependencies": { - "ga.fuquna.prefsgui": "3.2.4" + "ga.fuquna.prefsgui": "3.5.0" } }, "ga.fuquna.rapidgui": { @@ -148,14 +149,14 @@ }, "ga.fuquna.rosettaui": { "version": "1.8.0", - "depth": 1, + "depth": 0, "source": "registry", "dependencies": {}, "url": "https://registry.npmjs.com" }, "ga.fuquna.rosettaui.uitoolkit": { "version": "1.7.0", - "depth": 1, + "depth": 0, "source": "registry", "dependencies": { "ga.fuquna.rosettaui": "1.7.0" From a6f8a021b26378d5210bf33ddc0793afc88b176f Mon Sep 17 00:00:00 2001 From: fuqunaga Date: Thu, 12 Sep 2024 14:23:11 +0900 Subject: [PATCH 04/32] update PrefsGUIExample --- .../PrefsGUIExample/PrefsGUI - RapidGUI.meta | 8 - .../PrefsGUI - RapidGUI.prefab | 47 ---- .../PrefsGUI - RapidGUI.prefab.meta | 7 - .../PrefsGUIRapidGUIExample.cs | 40 --- .../PrefsGUIRapidGUIExample.cs.meta | 12 - .../PrefsGUIRapidGUIExampleBase.cs | 36 --- .../PrefsGUIRapidGUIExampleBase.cs.meta | 12 - .../PrefsGUI - RosettaUI.prefab | 113 +++++++++ .../PrefsGUIRosettaUIExample.cs | 20 +- .../PrefsGUIRosettaUIExample_MinMaxSlider.cs | 24 ++ ...fsGUIRosettaUIExample_MinMaxSlider.cs.meta | 3 + .../PrefsGUIRosettaUIExample_Slider.cs | 34 +++ .../PrefsGUIRosettaUIExample_Slider.cs.meta | 3 + .../PrefsGUI/PrefsGUIExample_Dictionary.cs | 14 ++ .../PrefsGUIExample_Dictionary.cs.meta | 3 + .../PrefsGUI/PrefsGUIExample_MinMax.cs | 15 ++ ...cs.meta => PrefsGUIExample_MinMax.cs.meta} | 0 .../PrefsGUI/PrefsGUIExample_Part1.cs | 154 ------------ .../PrefsGUI/PrefsGUIExample_Part2.cs | 83 ------ .../PrefsGUI/PrefsGUIExample_Part2.cs.meta | 12 - .../PrefsGUI/PrefsGUIExample_Part3.cs | 59 ----- .../PrefsGUI/PrefsGUIExample_Primitive.cs | 26 ++ ...meta => PrefsGUIExample_Primitive.cs.meta} | 0 .../PrefsGUI/PrefsGUIExample_Types.cs | 28 +++ .../PrefsGUI/PrefsGUIExample_Types.cs.meta | 3 + .../PrefsGUI/PrefsGUIExamples.prefab | 236 +++++++++++++----- .../PrefsGUIExample/PrefsGUIExample.prefab | 196 +++++++-------- .../PrefsMaterialPropertyRapidGUIExample.cs | 36 --- ...efsMaterialPropertyRapidGUIExample.cs.meta | 12 - Assets/Scenes/PrefsGUISyncForMirror.unity | 119 ++++++++- 30 files changed, 653 insertions(+), 702 deletions(-) delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI.meta delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab.meta delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs.meta delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs.meta create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs.meta create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs.meta create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs.meta create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_MinMax.cs rename Assets/Examples/PrefsGUIExample/PrefsGUI/{PrefsGUIExample_Part3.cs.meta => PrefsGUIExample_MinMax.cs.meta} (100%) delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part1.cs delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs.meta delete mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part3.cs create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Primitive.cs rename Assets/Examples/PrefsGUIExample/PrefsGUI/{PrefsGUIExample_Part1.cs.meta => PrefsGUIExample_Primitive.cs.meta} (100%) create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs create mode 100644 Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs.meta delete mode 100644 Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs delete mode 100644 Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs.meta diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI.meta deleted file mode 100644 index 2825756..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eb89c08f7831e4143acfd754daa2e352 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab b/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab deleted file mode 100644 index ef3d3bc..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab +++ /dev/null @@ -1,47 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &4411645983101423750 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4411645983101423748} - - component: {fileID: 4411645983101423749} - m_Layer: 0 - m_Name: PrefsGUI - RapidGUI - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &4411645983101423748 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4411645983101423750} - 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!114 &4411645983101423749 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4411645983101423750} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7614bb62828319d4aacb15b5251cde29, type: 3} - m_Name: - m_EditorClassIdentifier: - position: {x: 0, y: 500} diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab.meta deleted file mode 100644 index 0f3fc14..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUI - RapidGUI.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 346bc598f20a6ff42822c7a09d057ae8 -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs deleted file mode 100644 index ebbd6f0..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs +++ /dev/null @@ -1,40 +0,0 @@ -using UnityEngine; - -#if PrefsGUI_RapidGUI -using RapidGUI; -using PrefsGUI.RapidGUI; -#endif - -namespace PrefsGUI.Example -{ -#if PrefsGUI_RapidGUI - public class PrefsGUIRapidGUIExample : PrefsGUIRapidGUIExampleBase - { - public Vector2 position; - private WindowLaunchers windowLaunchers; - - private void Start() - { - windowLaunchers = new WindowLaunchers - { - isWindow = false - }; - windowLaunchers.Add("Part1", typeof(PrefsGUIExample_Part1)); - windowLaunchers.Add("Part2", typeof(PrefsGUIExample_Part2)); - windowLaunchers.Add("Part3", typeof(PrefsGUIExample_Part3)); - windowLaunchers.Add("PrefsSearch", PrefsSearch.DoGUI).SetWidth(600f).SetHeight(800f); - - windowRect.position = position; - } - - protected override void DoGUI() - { - windowLaunchers.DoGUI(); - base.DoGUI(); - } - } -#else - public class PrefsGUIRapidGUIExample : MonoBehaviour - {} -#endif -} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs.meta deleted file mode 100644 index 7929219..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExample.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 7614bb62828319d4aacb15b5251cde29 -timeCreated: 1473738440 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs deleted file mode 100644 index e340f4e..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs +++ /dev/null @@ -1,36 +0,0 @@ -using UnityEngine; - -#if PrefsGUI_RapidGUI -using RapidGUI; - -namespace PrefsGUI.Example -{ - public abstract class PrefsGUIRapidGUIExampleBase : MonoBehaviour - { - protected Rect windowRect = new() - { - width = 500f - }; - - public void OnGUI() - { - windowRect = RGUI.ResizableWindow(GetHashCode(), windowRect, (id) => - { - DoGUI(); - GUI.DragWindow(); - }, - "PrefsGUI - RapidGUI"); - } - - - protected virtual void DoGUI() - { - GUILayout.Space(50f); - GUILayout.Label($"file path: {Kvs.PrefsKvsPathSelector.path}"); - - if (GUILayout.Button("Save")) Prefs.Save(); - if (GUILayout.Button("DeleteAll")) Prefs.DeleteAll(); - } - } -} -#endif \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs.meta deleted file mode 100644 index 6565036..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RapidGUI/PrefsGUIRapidGUIExampleBase.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 4dc0666f26e64404bbddda481d3efc8e -timeCreated: 1473744492 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUI - RosettaUI.prefab b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUI - RosettaUI.prefab index 9a1f205..faa432a 100644 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUI - RosettaUI.prefab +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUI - RosettaUI.prefab @@ -1,10 +1,101 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &2331325693719292506 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3617350369278438900} + - component: {fileID: 1158614953931690290} + m_Layer: 0 + m_Name: Slider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3617350369278438900 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2331325693719292506} + serializedVersion: 2 + 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: 8747254707611192352} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1158614953931690290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2331325693719292506} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b8ca722537374d8dbae702af89ec960f, type: 3} + m_Name: + m_EditorClassIdentifier: + primitive: {fileID: 0} +--- !u!1 &4755230528773982185 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4512470761560304642} + - component: {fileID: 3003689320578001802} + m_Layer: 0 + m_Name: MinMaxSlider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4512470761560304642 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4755230528773982185} + serializedVersion: 2 + 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: 8747254707611192352} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3003689320578001802 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4755230528773982185} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2d093026f77141df9104af271e6ad8c6, type: 3} + m_Name: + m_EditorClassIdentifier: + minmax: {fileID: 0} --- !u!1001 &7411232724451739856 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: - target: {fileID: 606649722984901848, guid: 4ed1865184a851c448a44589b9f302b9, @@ -68,6 +159,21 @@ PrefabInstance: value: 0 objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: + - targetCorrespondingSourceObject: {fileID: 2287126204365735152, guid: 4ed1865184a851c448a44589b9f302b9, + type: 3} + insertIndex: -1 + addedObject: {fileID: 3617350369278438900} + - targetCorrespondingSourceObject: {fileID: 2287126204365735152, guid: 4ed1865184a851c448a44589b9f302b9, + type: 3} + insertIndex: -1 + addedObject: {fileID: 4512470761560304642} + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 606649722984901848, guid: 4ed1865184a851c448a44589b9f302b9, + type: 3} + insertIndex: -1 + addedObject: {fileID: 1262933857} m_SourcePrefab: {fileID: 100100000, guid: 4ed1865184a851c448a44589b9f302b9, type: 3} --- !u!1 &7976644945990181896 stripped GameObject: @@ -87,3 +193,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6c505e31293c9064a9ce25e10dd6c5e0, type: 3} m_Name: m_EditorClassIdentifier: + position: {x: 0, y: 0} +--- !u!4 &8747254707611192352 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2287126204365735152, guid: 4ed1865184a851c448a44589b9f302b9, + type: 3} + m_PrefabInstance: {fileID: 7411232724451739856} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample.cs index 68d02db..bda24ab 100644 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample.cs +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample.cs @@ -1,12 +1,9 @@ using PrefsGUI.Example; -using UnityEngine; -#if PrefsGUI_RosettaUI using RosettaUI; -#endif +using UnityEngine; namespace PrefsGUI.RosettaUI.Example { -#if PrefsGUI_RosettaUI [RequireComponent(typeof(RosettaUIRoot))] public class PrefsGUIRosettaUIExample : MonoBehaviour { @@ -18,23 +15,20 @@ private void Start() root.Build(CreateElement()); } - Element CreateElement() + private Element CreateElement() { return UI.Window( "PrefsGUI - RosettaUI", - UI.WindowLauncher("Part1"), - UI.WindowLauncher("Part2"), - UI.WindowLauncher("Part3"), + UI.WindowLauncher("Primitive"), + UI.WindowLauncher("Slider"), + UI.WindowLauncher("MinMaxSlider"), + UI.WindowLauncher("Dictionary"), UI.WindowLauncher(UI.Window(nameof(PrefsSearch), PrefsSearch.CreateElement())), UI.Space().SetHeight(15f), - UI.Label(() => $"file path: {Kvs.PrefsKvsPathSelector.path}"), + UI.Label(() => $"file path: {Kvs.PrefsKvsPathSelector.Path}"), UI.Button(nameof(Prefs.Save), Prefs.Save), UI.Button(nameof(Prefs.DeleteAll), Prefs.DeleteAll) ).SetPosition(position); } } -#else - public class PrefsGUIRosettaUIExample : MonoBehaviour - {} -#endif } \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs new file mode 100644 index 0000000..bbe4f6e --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs @@ -0,0 +1,24 @@ +using PrefsGUI.Example; +using RosettaUI; +using UnityEngine; + +namespace PrefsGUI.RosettaUI.Example +{ + public class PrefsGUIRosettaUIExample_MinMaxSlider : MonoBehaviour, IElementCreator + { + public PrefsGUIExample_MinMax minMax; + + public Element CreateElement(LabelElement label) + { + return UI.Column( + minMax.prefsMinMaxInt.CreateMinMaxSlider(), + minMax.prefsMinMaxFloat.CreateMinMaxSlider(), + minMax.prefsMinMaxVector2.CreateMinMaxSlider(), + minMax.prefsMinMaxVector3.CreateMinMaxSlider(), + minMax.prefsMinMaxVector4.CreateMinMaxSlider(), + minMax.prefsMinMaxVector2Int.CreateMinMaxSlider(), + minMax.prefsMinMaxVector3Int.CreateMinMaxSlider() + ); + } + } +} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs.meta new file mode 100644 index 0000000..9d4a908 --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_MinMaxSlider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2d093026f77141df9104af271e6ad8c6 +timeCreated: 1724128989 \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs new file mode 100644 index 0000000..173a24a --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs @@ -0,0 +1,34 @@ +using PrefsGUI.Example; +using RosettaUI; +using UnityEngine; + +namespace PrefsGUI.RosettaUI.Example +{ + public class PrefsGUIRosettaUIExample_Slider : MonoBehaviour, IElementCreator + { + public PrefsGUIExample_Primitive primitive; + + public Element CreateElement(LabelElement label) + { + return UI.Column( + // example.prefsBool.CreateSlider(), + primitive.prefsInt.CreateSlider(), + primitive.prefsFloat.CreateSlider(), + // example.prefsString.CreateSlider(), + // example.prefsEnum.CreateSlider(), + // example.prefsColor.CreateSlider(), + // example.prefsGradient.CreateSlider(), + primitive.prefsVector2.CreateSlider(), + primitive.prefsVector3.CreateSlider(), + primitive.prefsVector4.CreateSlider(), + primitive.prefsVector2Int.CreateSlider(), + primitive.prefsVector3Int.CreateSlider(), + primitive.prefsRect.CreateSlider(), + primitive.prefsBounds.CreateSlider(), + primitive.prefsBoundsInt.CreateSlider()//, + // example.prefsClass.CreateSlider(), + // example.prefsList.CreateSlider() + ); + } + } +} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs.meta new file mode 100644 index 0000000..a18591c --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI - RosettaUI/PrefsGUIRosettaUIExample_Slider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b8ca722537374d8dbae702af89ec960f +timeCreated: 1724061476 \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs new file mode 100644 index 0000000..e8b5d63 --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace PrefsGUI.Example +{ + public class PrefsGUIExample_Dictionary : MonoBehaviour + { + public PrefsDictionary prefsStringIntDictionary = new("StringIntDictionary"); + public PrefsDictionary> prefsStringListDictionary = new("StringListDictionary"); + public PrefsDictionary prefsIntClassDictionary = new("IntClassDictionary"); + public PrefsDictionary prefsEnumClassDictionary = new("EnumClassDictionary"); + public PrefsDictionary prefsVector3RectDictionary = new("Vector3RectDictionary"); + } +} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs.meta new file mode 100644 index 0000000..012d1b9 --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Dictionary.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 05adcfa2b67e481b905f2cc7c6f285c4 +timeCreated: 1724129586 \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_MinMax.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_MinMax.cs new file mode 100644 index 0000000..0b91bf4 --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_MinMax.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace PrefsGUI.Example +{ + public class PrefsGUIExample_MinMax : MonoBehaviour + { + public PrefsMinMaxInt prefsMinMaxInt = new("PrefsMinMaxInt"); + public PrefsMinMaxFloat prefsMinMaxFloat = new("PrefsMinMaxFloat"); + public PrefsMinMaxVector2 prefsMinMaxVector2 = new("PrefsMinMaxVector2"); + public PrefsMinMaxVector3 prefsMinMaxVector3 = new("PrefsMinMaxVector3"); + public PrefsMinMaxVector4 prefsMinMaxVector4 = new("PrefsMinMaxVector4"); + public PrefsMinMaxVector2Int prefsMinMaxVector2Int = new("PrefsMinMaxVector2Int"); + public PrefsMinMaxVector3Int prefsMinMaxVector3Int = new("PrefsMinMaxVector3Int"); + } +} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part3.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_MinMax.cs.meta similarity index 100% rename from Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part3.cs.meta rename to Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_MinMax.cs.meta diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part1.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part1.cs deleted file mode 100644 index c142b31..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part1.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using UnityEngine; -using Debug = UnityEngine.Debug; - -#if PrefsGUI_RapidGUI -using RapidGUI; -using PrefsGUI.RapidGUI; -#endif - -#if PrefsGUI_RosettaUI -using RosettaUI; -using PrefsGUI.RosettaUI; -#endif - -namespace PrefsGUI.Example -{ - public class PrefsGUIExample_Part1 : MonoBehaviour -#if PrefsGUI_RapidGUI - ,IDoGUI -#endif -#if PrefsGUI_RosettaUI - ,IElementCreator -#endif - { - #region Type Define - - public enum EnumSample - { - One, - Two, - Three - } - - [Serializable] - public class CustomClass - { - public string name; - public int intValue; - - public CustomClass() - { - } - - public CustomClass(CustomClass other) - { - name = other.name; - intValue = other.intValue; - } - } - - #endregion - - // define PrefsParams with key. - public PrefsBool prefsBool = new PrefsBool("PrefsBool"); - public PrefsInt prefsInt = new PrefsInt("PrefsInt"); - public PrefsFloat prefsFloat = new PrefsFloat("PrefsFloat"); - public PrefsString prefsString = new PrefsString("PrefsString"); - public PrefsParam prefsEnum = new PrefsParam("PrefsEnum"); - public PrefsColor prefsColor = new PrefsColor("PrefsColor"); - public PrefsVector2 prefsVector2 = new PrefsVector2("PrefsVector2"); - public PrefsVector3 prefsVector3 = new PrefsVector3("PrefsVector3"); - public PrefsVector4 prefsVector4 = new PrefsVector4("PrefsVector4"); - public PrefsAny prefsClass = new PrefsAny("PrefsClass"); - public PrefsList prefsList = new PrefsList("PrefsList"); - - - void Update() - { - TestImplicitCast(); - } - - protected void TestImplicitCast() - { - bool b = prefsBool; - int i = prefsInt; - float f = prefsFloat; - string s = prefsString; - EnumSample e = prefsEnum; - Color c = prefsColor; - Vector2 v2 = prefsVector2; - Vector3 v3 = prefsVector2; - Vector4 v4 = prefsVector2; - v2 = prefsVector3; - v3 = prefsVector3; - v4 = prefsVector3; - v2 = prefsVector4; - v3 = prefsVector4; - v4 = prefsVector4; - - CustomClass customClass = prefsClass; - List list = prefsList; - } - -#if PrefsGUI_RapidGUI - public void DoGUI() - { - prefsBool.DoGUI(); - - // Return true if value was changed - var changed = prefsInt.DoGUI(); - if (changed) - { - // Implicitly convert - int intValue = prefsInt; - Debug.Log("DoGUI: Changed. " + intValue); - } - - prefsFloat.DoGUI(); - prefsFloat.DoGUISlider(); - prefsString.DoGUI(); - prefsEnum.DoGUI(); - prefsColor.DoGUI(); - prefsVector2.DoGUI(); - prefsVector2.DoGUISlider(); - prefsVector3.DoGUI(); - prefsVector3.DoGUISlider(); - prefsVector4.DoGUI(); - prefsVector4.DoGUISlider(); - prefsClass.DoGUI(); - prefsList.DoGUI(); - - if (prefsList.Count > 0) - { - prefsList.DoGUIAt(0, "PrefsList element at 0"); - } - } -#endif - -#if PrefsGUI_RosettaUI - public Element CreateElement(LabelElement _) - { - return UI.Column( - prefsBool.CreateElement(), - prefsInt.CreateElement().RegisterValueChangeCallback(() => Debug.Log("CreateElement: Changed. " + prefsInt.Get())), - prefsFloat.CreateElement(), - prefsFloat.CreateSlider(), - prefsString.CreateElement(), - prefsEnum.CreateElement(), - prefsColor.CreateElement(), - prefsVector2.CreateElement(), - prefsVector2.CreateSlider(), - prefsVector3.CreateElement(), - prefsVector3.CreateSlider(), - prefsVector4.CreateElement(), - prefsVector4.CreateSlider(), - prefsClass.CreateElement(), - prefsList.CreateElement() - ); - } -#endif - } -} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs deleted file mode 100644 index bc8dfc8..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System.Net; -using UnityEngine; - -#if PrefsGUI_RapidGUI -using RapidGUI; -using PrefsGUI.RapidGUI; -#endif - -#if PrefsGUI_RosettaUI -using RosettaUI; -using PrefsGUI.RosettaUI; -#endif - -namespace PrefsGUI.Example -{ - public class PrefsGUIExample_Part2 : MonoBehaviour -#if PrefsGUI_RapidGUI - ,IDoGUI -#endif -#if PrefsGUI_RosettaUI - ,IElementCreator -#endif - { - // define PrefsParams with key. - public PrefsVector2Int prefsVector2Int = new PrefsVector2Int("PrefsVector2Int"); - public PrefsVector3Int prefsVector3Int = new PrefsVector3Int("PrefsVector3Int"); - public PrefsRect prefsRect = new PrefsRect("PrefsRect"); - public PrefsBounds prefsBounds = new PrefsBounds("PrefsBounds"); - public PrefsBoundsInt prefsBoundsInt = new PrefsBoundsInt("PrefsBoundsInt"); - public PrefsIPEndPoint prefsIPEndPoint = new PrefsIPEndPoint("PrefsIPEndPoint"); - - void Update() - { - TestImplicitCast(); - } - - protected void TestImplicitCast() - { - Vector2Int v2Int = prefsVector2Int; - Vector3Int v3Int = prefsVector3Int; - Rect rect = prefsRect; - Bounds bounds = prefsBounds; - BoundsInt boundsInt = prefsBoundsInt; - - IPEndPoint ip = prefsIPEndPoint; - } - -#if PrefsGUI_RapidGUI - public void DoGUI() - { - prefsVector2Int.DoGUI(); - prefsVector2Int.DoGUISlider(); - prefsVector3Int.DoGUI(); - prefsVector3Int.DoGUISlider(); - prefsRect.DoGUI(); - prefsRect.DoGUISlider(); - prefsBounds.DoGUI(); - prefsBounds.DoGUISlider(); - prefsBoundsInt.DoGUI(); - prefsBoundsInt.DoGUISlider(); - prefsIPEndPoint.DoGUI(); - } -#endif - -#if PrefsGUI_RosettaUI - public Element CreateElement(LabelElement _) - { - return UI.Column( - prefsVector2Int.CreateElement(), - prefsVector2Int.CreateSlider(), - prefsVector3Int.CreateElement(), - prefsVector3Int.CreateSlider(), - prefsRect.CreateElement(), - prefsRect.CreateSlider(), - prefsBounds.CreateElement(), - prefsBounds.CreateSlider(), - prefsBoundsInt.CreateElement(), - prefsIPEndPoint.CreateElement() - ); - } -#endif - } -} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs.meta deleted file mode 100644 index 2c1b88c..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part2.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 84e9b87159a01f64da8cb763532f1382 -timeCreated: 1473738440 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part3.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part3.cs deleted file mode 100644 index 2cf089d..0000000 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part3.cs +++ /dev/null @@ -1,59 +0,0 @@ -using UnityEngine; -#if PrefsGUI_RapidGUI -using RapidGUI; -using PrefsGUI.RapidGUI; -#endif - -#if PrefsGUI_RosettaUI -using RosettaUI; -using PrefsGUI.RosettaUI; -#endif - -namespace PrefsGUI.Example -{ - public class PrefsGUIExample_Part3 : MonoBehaviour -#if PrefsGUI_RapidGUI - ,IDoGUI -#endif -#if PrefsGUI_RosettaUI - ,IElementCreator -#endif - { - // define PrefsParams with key. - public PrefsMinMaxInt prefsMinMaxInt = new("PrefsMinMaxInt"); - public PrefsMinMaxFloat prefsMinMaxFloat = new("PrefsMinMaxFloat"); - public PrefsMinMaxVector2 prefsMinMaxVector2 = new("PrefsMinMaxVector2"); - public PrefsMinMaxVector3 prefsMinMaxVector3 = new("PrefsMinMaxVector3"); - public PrefsMinMaxVector4 prefsMinMaxVector4 = new("PrefsMinMaxVector4"); - public PrefsMinMaxVector2Int prefsMinMaxVector2Int = new("PrefsMinMaxVector2Int"); - public PrefsMinMaxVector3Int prefsMinMaxVector3Int = new("PrefsMinMaxVector3Int"); - -#if PrefsGUI_RapidGUI - public void DoGUI() - { - prefsMinMaxInt.DoGUISlider(); - prefsMinMaxFloat.DoGUISlider(); - prefsMinMaxVector2.DoGUISlider(); - prefsMinMaxVector3.DoGUISlider(); - prefsMinMaxVector4.DoGUISlider(); - prefsMinMaxVector2Int.DoGUISlider(); - prefsMinMaxVector3Int.DoGUISlider(); - } -#endif - -#if PrefsGUI_RosettaUI - public Element CreateElement(LabelElement _) - { - return UI.Column( - prefsMinMaxInt.CreateMinMaxSlider(), - prefsMinMaxFloat.CreateMinMaxSlider(), - prefsMinMaxVector2.CreateMinMaxSlider(), - prefsMinMaxVector3.CreateMinMaxSlider(), - prefsMinMaxVector4.CreateMinMaxSlider(), - prefsMinMaxVector2Int.CreateMinMaxSlider(), - prefsMinMaxVector3Int.CreateMinMaxSlider() - ); - } -#endif - } -} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Primitive.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Primitive.cs new file mode 100644 index 0000000..65249aa --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Primitive.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +namespace PrefsGUI.Example +{ + public class PrefsGUIExample_Primitive : MonoBehaviour + { + public PrefsBool prefsBool = new("PrefsBool"); + public PrefsInt prefsInt = new("PrefsInt"); + public PrefsFloat prefsFloat = new("PrefsFloat"); + public PrefsString prefsString = new("PrefsString"); + public PrefsParam prefsEnum = new("PrefsEnum"); + public PrefsColor prefsColor = new("PrefsColor"); + public PrefsGradient prefsGradient = new("PrefsGradient"); + public PrefsVector2 prefsVector2 = new("PrefsVector2"); + public PrefsVector3 prefsVector3 = new("PrefsVector3"); + public PrefsVector4 prefsVector4 = new("PrefsVector4"); + public PrefsVector2Int prefsVector2Int = new("PrefsVector2Int"); + public PrefsVector3Int prefsVector3Int = new("PrefsVector3Int"); + public PrefsRect prefsRect = new("PrefsRect"); + public PrefsBounds prefsBounds = new("PrefsBounds"); + public PrefsBoundsInt prefsBoundsInt = new("PrefsBoundsInt"); + public PrefsAny prefsClass = new("PrefsClass"); + public PrefsList prefsList = new("PrefsList"); + public PrefsIPAddressAndPort prefsIPEndPoint = new("PrefsIPAddressAndPort"); + } +} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part1.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Primitive.cs.meta similarity index 100% rename from Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Part1.cs.meta rename to Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Primitive.cs.meta diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs new file mode 100644 index 0000000..55aaa2b --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs @@ -0,0 +1,28 @@ +using System; + +namespace PrefsGUI.Example +{ + public enum EnumSample + { + One, + Two, + Three + } + + [Serializable] + public class CustomClass + { + public string name; + public int intValue; + + public CustomClass() + { + } + + public CustomClass(CustomClass other) + { + name = other.name; + intValue = other.intValue; + } + } +} \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs.meta b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs.meta new file mode 100644 index 0000000..278401a --- /dev/null +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExample_Types.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 47cef5d3ad30428b8a0b71445f9b567e +timeCreated: 1724129986 \ No newline at end of file diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExamples.prefab b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExamples.prefab index 6897a17..75b7c76 100644 --- a/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExamples.prefab +++ b/Assets/Examples/PrefsGUIExample/PrefsGUI/PrefsGUIExamples.prefab @@ -11,7 +11,7 @@ GameObject: - component: {fileID: 5910173124826832050} - component: {fileID: 5910173124826832049} m_Layer: 0 - m_Name: Part1 + m_Name: Primitive m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -24,13 +24,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5910173124826832051} + serializedVersion: 2 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: 5910173124934788266} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &5910173124826832049 MonoBehaviour: @@ -61,7 +61,39 @@ MonoBehaviour: defaultValue: 0 prefsColor: _key: PrefsColor - defaultValue: {r: 0, g: 0, b: 0, a: 0} + defaultValue: {r: 1, g: 0, b: 0, a: 1} + prefsGradient: + _key: PrefsGradient + defaultValue: + serializedVersion: 2 + key0: {r: 1, g: 0, b: 0, a: 1} + key1: {r: 0, g: 1, b: 0.07015848, a: 1} + key2: {r: 0.002779007, g: 0, b: 1, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 35209 + ctime2: 65535 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 2 + m_ColorSpace: -1 + m_NumColorKeys: 3 + m_NumAlphaKeys: 2 prefsVector2: _key: PrefsVector2 defaultValue: {x: 0, y: 0} @@ -71,6 +103,30 @@ MonoBehaviour: prefsVector4: _key: PrefsVector4 defaultValue: {x: 0, y: 0, z: 0, w: 0} + prefsVector2Int: + _key: PrefsVector2Int + defaultValue: {x: 0, y: 0} + prefsVector3Int: + _key: PrefsVector3Int + defaultValue: {x: 0, y: 0, z: 0} + prefsRect: + _key: PrefsRect + defaultValue: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + prefsBounds: + _key: PrefsBounds + defaultValue: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + prefsBoundsInt: + _key: PrefsBoundsInt + defaultValue: + m_Position: {x: 0, y: 0, z: 0} + m_Size: {x: 0, y: 0, z: 0} prefsClass: _key: PrefsClass defaultValue: @@ -81,6 +137,13 @@ MonoBehaviour: defaultValue: - name: first intValue: 0 + prefsIPEndPoint: + prefs0: + _key: PrefsIPEndPoint_address + defaultValue: localhost + prefs1: + _key: PrefsIPEndPoint_port + defaultValue: 10000 --- !u!1 &5910173124934788267 GameObject: m_ObjectHideFlags: 0 @@ -105,16 +168,16 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5910173124934788267} + serializedVersion: 2 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: - {fileID: 5910173124826832050} - - {fileID: 5910173125313911334} - {fileID: 5910173125652080342} + - {fileID: 2122528793330596787} m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &5910173124934788265 MonoBehaviour: @@ -128,9 +191,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f45fdd78baa00824fa0bd95ff0bf37bd, type: 3} m_Name: m_EditorClassIdentifier: - platformMask: 132 + platform: 12 _path: '%dataPath%/../../%productName%Prefs' ---- !u!1 &5910173125313911335 +--- !u!1 &5910173125652080343 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -138,67 +201,78 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 5910173125313911334} - - component: {fileID: 5910173125313911333} + - component: {fileID: 5910173125652080342} + - component: {fileID: 5910173125652080341} m_Layer: 0 - m_Name: Part2 + m_Name: MinMax m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &5910173125313911334 +--- !u!4 &5910173125652080342 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5910173125313911335} + m_GameObject: {fileID: 5910173125652080343} + serializedVersion: 2 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: 5910173124934788266} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &5910173125313911333 +--- !u!114 &5910173125652080341 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5910173125313911335} + m_GameObject: {fileID: 5910173125652080343} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 84e9b87159a01f64da8cb763532f1382, type: 3} + m_Script: {fileID: 11500000, guid: 99088179b88fc1d46adc2fc60ac2fbee, type: 3} m_Name: m_EditorClassIdentifier: - prefsVector2Int: - _key: PrefsVector2Int - defaultValue: {x: 0, y: 0} - prefsVector3Int: - _key: PrefsVector3Int - defaultValue: {x: 0, y: 0, z: 0} - prefsRect: - _key: PrefsRect + prefsMinMaxInt: + _key: PrefsMinMaxInt defaultValue: - serializedVersion: 2 - x: 0 - y: 0 - width: 0 - height: 0 - prefsBounds: - _key: PrefsBounds + min: 0 + max: 0 + prefsMinMaxFloat: + _key: PrefsMinMaxFloat defaultValue: - m_Center: {x: 0, y: 0, z: 0} - m_Extent: {x: 0, y: 0, z: 0} - prefsBoundsInt: - _key: PrefsBoundsInt + min: 0 + max: 0 + prefsMinMaxVector2: + _key: PrefsMinMaxVector2 defaultValue: - m_Position: {x: 0, y: 0, z: 0} - m_Size: {x: 0, y: 0, z: 0} ---- !u!1 &5910173125652080343 + min: {x: 0, y: 0} + max: {x: 0, y: 0} + prefsMinMaxVector3: + _key: PrefsMinMaxVector3 + defaultValue: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + prefsMinMaxVector4: + _key: PrefsMinMaxVector4 + defaultValue: + min: {x: 0, y: 0, z: 0, w: 0} + max: {x: 0, y: 0, z: 0, w: 0} + prefsMinMaxVector2Int: + _key: PrefsMinMaxVector2Int + defaultValue: + min: {x: 0, y: 0} + max: {x: 0, y: 0} + prefsMinMaxVector3Int: + _key: PrefsMinMaxVector3Int + defaultValue: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} +--- !u!1 &7910112138199482675 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -206,53 +280,93 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 5910173125652080342} - - component: {fileID: 5910173125652080341} + - component: {fileID: 2122528793330596787} + - component: {fileID: 2435621400607673198} m_Layer: 0 - m_Name: Part3 + m_Name: Dictionary m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &5910173125652080342 +--- !u!4 &2122528793330596787 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5910173125652080343} + m_GameObject: {fileID: 7910112138199482675} + serializedVersion: 2 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: 5910173124934788266} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &5910173125652080341 +--- !u!114 &2435621400607673198 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5910173125652080343} + m_GameObject: {fileID: 7910112138199482675} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 99088179b88fc1d46adc2fc60ac2fbee, type: 3} + m_Script: {fileID: 11500000, guid: 05adcfa2b67e481b905f2cc7c6f285c4, type: 3} m_Name: m_EditorClassIdentifier: - prefsMinMaxInt: - _key: PrefsMinMaxInt - prefsMinMaxFloat: - _key: PrefsMinMaxFloat - prefsMinMaxVector2: - _key: PrefsMinMaxVector2 - prefsMinMaxVector3: - _key: PrefsMinMaxVector3 - prefsMinMaxVector4: - _key: PrefsMinMaxVector4 - prefsMinMaxVector2Int: - _key: PrefsMinMaxVector2Int - prefsMinMaxVector3Int: - _key: PrefsMinMaxVector3Int + prefsStringIntDictionary: + _key: StringIntDictionary + defaultValue: + _list: + - key: first key + value: 1 + prefsStringListDictionary: + _key: StringListDictionary + defaultValue: + _list: + - key: + value: 0000000001000000 + prefsIntClassDictionary: + _key: IntClassDictionary + defaultValue: + _list: + - key: 0 + value: + name: first element + intValue: 0 + - key: 1 + value: + name: secound element + intValue: 1 + prefsEnumClassDictionary: + _key: EnumClassDictionary + defaultValue: + _list: + - key: 0 + value: + name: first element + intValue: 0 + - key: 1 + value: + name: secound element + intValue: 1 + prefsVector3RectDictionary: + _key: Vector3RectDictionary + defaultValue: + _list: + - key: {x: 0, y: 0, z: 0} + value: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + - key: {x: 0, y: 1, z: 0} + value: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 diff --git a/Assets/Examples/PrefsGUIExample/PrefsGUIExample.prefab b/Assets/Examples/PrefsGUIExample/PrefsGUIExample.prefab index 0384f32..d471c61 100644 --- a/Assets/Examples/PrefsGUIExample/PrefsGUIExample.prefab +++ b/Assets/Examples/PrefsGUIExample/PrefsGUIExample.prefab @@ -23,6 +23,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7830099223094831405} + serializedVersion: 2 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} @@ -32,68 +33,84 @@ Transform: - {fileID: 8293265376701648384} - {fileID: 7830099223039217024} m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1001 &753197507116155424 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 7830099223094831404} m_Modifications: - - target: {fileID: 7976644945990181896, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 7976644945990181896, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_Name value: PrefsGUI - RosettaUI objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_RootOrder value: 1 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalPosition.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalPosition.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalPosition.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalRotation.w value: 1 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalRotation.x value: -0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalRotation.y value: -0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalRotation.z value: -0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalEulerAnglesHint.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalEulerAnglesHint.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + - target: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} --- !u!4 &8293265376701648384 stripped Transform: - m_CorrespondingSourceObject: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, type: 3} + m_CorrespondingSourceObject: {fileID: 8747254707611192352, guid: 98479ffecdc1cc946ae433c204c2d776, + type: 3} m_PrefabInstance: {fileID: 753197507116155424} m_PrefabAsset: {fileID: 0} --- !u!1001 &4516898106111953952 @@ -101,125 +118,79 @@ PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 7830099223094831404} m_Modifications: - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsInt._key - value: PrefsInt - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsBool._key - value: PrefsBool - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsEnum._key - value: PrefsEnum - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsList._key - value: PrefsList - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsClass._key - value: PrefsClass - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsColor._key - value: PrefsColor - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsFloat._key - value: PrefsFloat - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsString._key - value: PrefsString - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsVector2._key - value: PrefsVector2 - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsVector3._key - value: PrefsVector3 - objectReference: {fileID: 0} - - target: {fileID: 5910173124826832049, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsVector4._key - value: PrefsVector4 - objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_RootOrder value: 0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalPosition.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalPosition.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalPosition.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalRotation.w value: 1 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalRotation.x value: -0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalRotation.y value: -0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalRotation.z value: -0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalEulerAnglesHint.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalEulerAnglesHint.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 5910173124934788267, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + - target: {fileID: 5910173124934788267, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} propertyPath: m_Name value: PrefsGUI objectReference: {fileID: 0} - - target: {fileID: 5910173125313911333, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsRect._key - value: PrefsRect - objectReference: {fileID: 0} - - target: {fileID: 5910173125313911333, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsBounds._key - value: PrefsBounds - objectReference: {fileID: 0} - - target: {fileID: 5910173125313911333, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsBoundsInt._key - value: PrefsBoundsInt - objectReference: {fileID: 0} - - target: {fileID: 5910173125313911333, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsVector2Int._key - value: PrefsVector2Int - objectReference: {fileID: 0} - - target: {fileID: 5910173125313911333, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} - propertyPath: prefsVector3Int._key - value: PrefsVector3Int - objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: + - {fileID: 5910173125313911335, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} --- !u!4 &7830099221368563850 stripped Transform: - m_CorrespondingSourceObject: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, type: 3} + m_CorrespondingSourceObject: {fileID: 5910173124934788266, guid: f4cadb92b2d3b5a4dad3110b82cd1d5d, + type: 3} m_PrefabInstance: {fileID: 4516898106111953952} m_PrefabAsset: {fileID: 0} --- !u!1001 &5878122633179602180 @@ -227,60 +198,77 @@ PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 7830099223094831404} m_Modifications: - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_RootOrder value: 2 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalPosition.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalPosition.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalPosition.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalRotation.w value: 1 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalRotation.x value: -0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalRotation.y value: -0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalRotation.z value: -0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalEulerAnglesHint.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalEulerAnglesHint.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 4411645983101423750, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + - target: {fileID: 4411645983101423750, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} propertyPath: m_Name value: PrefsGUI - RapidGUI objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} --- !u!4 &7830099223039217024 stripped Transform: - m_CorrespondingSourceObject: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, type: 3} + m_CorrespondingSourceObject: {fileID: 4411645983101423748, guid: 346bc598f20a6ff42822c7a09d057ae8, + type: 3} m_PrefabInstance: {fileID: 5878122633179602180} m_PrefabAsset: {fileID: 0} diff --git a/Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs b/Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs deleted file mode 100644 index 9dea68b..0000000 --- a/Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs +++ /dev/null @@ -1,36 +0,0 @@ -using UnityEngine; -#if PrefsGUI_RapidGUI -using PrefsGUI.RapidGUI; -using UnityEngine.Serialization; -#endif - -namespace PrefsGUI.Example -{ -#if PrefsGUI_RapidGUI - public class PrefsMaterialPropertyRapidGUIExample : PrefsGUIRapidGUIExampleBase - { - [FormerlySerializedAs("debugMenu")] public PrefsMaterialProperty prefsMaterialProperty; - - public void Start() - { - if (prefsMaterialProperty == null) - { - prefsMaterialProperty = GetComponent(); - } - } - - protected override void DoGUI() - { - if (prefsMaterialProperty != null) - { - prefsMaterialProperty.DoGUI(); - } - - base.DoGUI(); - } - } -#else - public class PrefsMaterialPropertyRapidGUIExample : MonoBehaviour - {} -#endif -} \ No newline at end of file diff --git a/Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs.meta b/Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs.meta deleted file mode 100644 index d3e1b5e..0000000 --- a/Assets/Examples/PrefsMaterialPropertyExample/PrefsMaterialPropertyRapidGUIExample.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: ea2e4ffaf96fe60428b7e63abbe8dde5 -timeCreated: 1474017055 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scenes/PrefsGUISyncForMirror.unity b/Assets/Scenes/PrefsGUISyncForMirror.unity index afa37eb..3a34e8a 100644 --- a/Assets/Scenes/PrefsGUISyncForMirror.unity +++ b/Assets/Scenes/PrefsGUISyncForMirror.unity @@ -38,7 +38,6 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -104,7 +103,7 @@ NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: - serializedVersion: 2 + serializedVersion: 3 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 @@ -117,7 +116,7 @@ NavMeshSettings: cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 - accuratePlacement: 0 + buildHeightMesh: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: @@ -209,13 +208,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 67078573} + serializedVersion: 2 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_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} --- !u!1 &352369114 GameObject: @@ -257,9 +256,17 @@ Camera: m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} - m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 x: 0 @@ -293,25 +300,56 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 352369114} + serializedVersion: 2 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_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &845866595 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 7830099221792254709, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} + m_PrefabInstance: {fileID: 1260040620} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 99088179b88fc1d46adc2fc60ac2fbee, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &914878926 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 7830099221526941841, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} + m_PrefabInstance: {fileID: 1260040620} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 61933781acb3fb14faf7443efab03b2c, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1001 &1260040620 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: - target: {fileID: 753197506188842305, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} propertyPath: position.y value: 150 objectReference: {fileID: 0} + - target: {fileID: 1902734614948188946, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} + propertyPath: primitive + value: + objectReference: {fileID: 914878926} + - target: {fileID: 2584180674348050858, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} + propertyPath: minMax + value: + objectReference: {fileID: 845866595} - target: {fileID: 7830099223039217026, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} propertyPath: m_IsActive value: 0 @@ -365,14 +403,67 @@ PrefabInstance: value: PrefsGUIExample objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: + - {fileID: 8646983505340250362, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 1a70f7cb24c86ff4cb00da13fcc4f9b9, type: 3} --- !u!1001 &4002032991337432683 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.size + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[0] + value: PrefsBool + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[1] + value: PrefsInt + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[2] + value: PrefsFloat + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[3] + value: PrefsString + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[4] + value: PrefsEnum + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[5] + value: PrefsColor + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[6] + value: PrefsVector2 + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[7] + value: PrefsVector3 + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[8] + value: PrefsVector4 + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[9] + value: PrefsClass + objectReference: {fileID: 0} + - target: {fileID: 4002032992138290985, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} + propertyPath: ignoreKeyList.Array.data[10] + value: PrefsList + objectReference: {fileID: 0} - target: {fileID: 4002032992138290986, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} propertyPath: m_Name value: PrefsGUISync @@ -426,12 +517,16 @@ PrefabInstance: value: 0 objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: b505519b5e6839c448e69ec00ddb3f93, type: 3} --- !u!1001 &7849735202726305980 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: - target: {fileID: 7849735203262328166, guid: 22d0f1c0bb64c6941ae1d584d298c577, type: 3} @@ -483,4 +578,16 @@ PrefabInstance: value: 0 objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 22d0f1c0bb64c6941ae1d584d298c577, type: 3} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 352369119} + - {fileID: 67078575} + - {fileID: 7849735202726305980} + - {fileID: 4002032991337432683} + - {fileID: 1260040620} From c92ea9f906a75d873ef4bcd46dd64dc0cd11e923 Mon Sep 17 00:00:00 2001 From: fuqunaga Date: Thu, 12 Sep 2024 14:31:57 +0900 Subject: [PATCH 05/32] build(deps): update ParrelSync version to 1.5.2 --- Packages/packages-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index e595f66..53d3381 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -102,7 +102,7 @@ "depth": 0, "source": "git", "dependencies": {}, - "hash": "f45424822189ebd875d864a17d7f03b72eafbff7" + "hash": "d1ef610e9fe3ad0b490cce91594449fc0af809a6" }, "ga.fuquna.prefsgui": { "version": "3.5.0", From c4f547590c7b4d09f81907dc425827d0fcef52fb Mon Sep 17 00:00:00 2001 From: fuqunaga Date: Thu, 12 Sep 2024 14:38:12 +0900 Subject: [PATCH 06/32] refactor(test): PreformanceTest --- .../Runtime/Performance/PerformanceTest.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Assets/Tests/Runtime/Performance/PerformanceTest.cs b/Assets/Tests/Runtime/Performance/PerformanceTest.cs index 4da0fea..9968d3b 100644 --- a/Assets/Tests/Runtime/Performance/PerformanceTest.cs +++ b/Assets/Tests/Runtime/Performance/PerformanceTest.cs @@ -30,22 +30,20 @@ public void Start() private void Update() { - if (updatePrefsValues) + if (!updatePrefsValues) return; + + foreach (var prefs in prefsFloats) { - foreach (var prefs in prefsFloats) - { - prefs.Set(Random.value); - } + prefs.Set(Random.value); + } - foreach (var prefs in prefsStrings) - { - prefs.Set(_stringValues[Random.Range(0,count)]); - } - + foreach (var prefs in prefsStrings) + { + prefs.Set(_stringValues[Random.Range(0,count)]); } } - void ResetPrefs() + private void ResetPrefs() { prefsFloats = Enumerable.Range(0, count) .Select(i => new PrefsFloat(nameof(PrefsFloat) + i)) @@ -61,7 +59,7 @@ void ResetPrefs() } } - public Element CreateElement() + private Element CreateElement() { return UI.Window(nameof(PerformanceTest), UI.Field(() => count).RegisterValueChangeCallback(ResetPrefs), From 54e384314514df16fd4e34f274d30206273374b4 Mon Sep 17 00:00:00 2001 From: fuqunaga Date: Thu, 12 Sep 2024 14:59:23 +0900 Subject: [PATCH 07/32] build(deps): update Mirror version to 89.8.0 from 73.0.0 --- .../CompilerSymbols/PreprocessorDefine.cs | 31 +- .../Components/Discovery/NetworkDiscovery.cs | 26 +- .../Discovery/NetworkDiscoveryBase.cs | 85 +- .../Discovery/NetworkDiscoveryBase.cs.meta | 2 +- .../Discovery/ServerRequest.cs.meta | 2 +- .../Discovery/ServerResponse.cs.meta | 2 +- .../Experimental/NetworkLerpRigidbody.cs | 14 +- .../Experimental/NetworkRigidbody.cs | 14 +- .../Experimental/NetworkRigidbody2D.cs | 14 +- Assets/Mirror/Components/GUIConsole.cs | 32 +- .../Distance/DistanceInterestManagement.cs | 2 +- .../Match/MatchInterestManagement.cs | 173 +- .../InterestManagement/Match/NetworkMatch.cs | 29 +- .../Scene/SceneInterestManagement.cs | 6 +- .../SpatialHashing/Grid3D.cs | 106 + .../SpatialHashing/Grid3D.cs.meta | 3 + .../SpatialHashing3DInterestManagement.cs | 146 + ...SpatialHashing3DInterestManagement.cs.meta | 3 + .../SpatialHashingInterestManagement.cs | 6 +- .../InterestManagement/Team/NetworkTeam.cs | 28 +- .../Team/TeamInterestManagement.cs | 171 +- .../LagCompensation.meta} | 2 +- .../LagCompensation/HistoryCollider.cs | 109 + .../LagCompensation/HistoryCollider.cs.meta} | 2 +- .../LagCompensation/LagCompensator.cs | 197 + .../LagCompensation/LagCompensator.cs.meta} | 2 +- Assets/Mirror/Components/NetworkAnimator.cs | 113 +- .../Components/NetworkDiagnosticsDebugger.cs | 31 + .../NetworkDiagnosticsDebugger.cs.meta} | 2 +- .../Mirror/Components/NetworkPingDisplay.cs | 10 +- .../Mirror/Components/NetworkRigidbody.meta | 3 + .../NetworkRigidbodyReliable.cs | 112 + .../NetworkRigidbodyReliable.cs.meta} | 2 +- .../NetworkRigidbodyReliable2D.cs | 112 + .../NetworkRigidbodyReliable2D.cs.meta | 11 + .../NetworkRigidbodyUnreliable.cs | 112 + .../NetworkRigidbodyUnreliable.cs.meta | 11 + .../NetworkRigidbodyUnreliable2D.cs | 112 + .../NetworkRigidbodyUnreliable2D.cs.meta | 11 + .../Mirror/Components/NetworkRoomManager.cs | 157 +- Assets/Mirror/Components/NetworkRoomPlayer.cs | 6 +- Assets/Mirror/Components/NetworkStatistics.cs | 4 +- ...ormReliable.meta => NetworkTransform.meta} | 0 .../NetworkTransform/NetworkTransform.cs | 10 + .../NetworkTransform.cs.meta | 0 .../NetworkTransformBase.cs | 246 +- .../NetworkTransformBase.cs.meta | 2 +- .../NetworkTransformChild.cs | 0 .../NetworkTransformChild.cs.meta | 0 .../NetworkTransformReliable.cs | 193 +- .../NetworkTransformReliable.cs.meta | 0 .../NetworkTransformUnreliable.cs | 679 +++ .../NetworkTransformUnreliable.cs.meta | 11 + .../TransformSnapshot.cs | 7 +- .../TransformSnapshot.cs.meta | 0 .../NetworkTransform/TransformSyncData.cs | 156 + .../TransformSyncData.cs.meta | 11 + .../NetworkTransform.cs | 359 -- .../Mirror/Components/PredictedRigidbody.meta | 3 + .../LocalGhostMaterial.mat} | 21 +- .../LocalGhostMaterial.mat.meta} | 2 +- .../PredictedRigidbody/PredictedRigidbody.cs | 997 +++++ .../PredictedRigidbody.cs.meta | 15 + .../PredictedRigidbodyPhysicsGhost.cs | 15 + .../PredictedRigidbodyPhysicsGhost.cs.meta | 11 + .../PredictedRigidbodyRemoteGhost.cs | 1 + .../PredictedRigidbodyRemoteGhost.cs.meta | 11 + .../PredictedRigidbody/PredictedSyncData.cs | 54 + .../PredictedSyncData.cs.meta | 3 + .../PredictedRigidbody/PredictionUtils.cs | 419 ++ .../PredictionUtils.cs.meta | 11 + .../RemoteGhostMaterial.mat} | 21 +- .../RemoteGhostMaterial.mat.meta} | 2 +- .../PredictedRigidbody/RigidbodyState.cs | 60 + .../PredictedRigidbody/RigidbodyState.cs.meta | 11 + Assets/Mirror/Components/RemoteStatistics.cs | 6 +- Assets/Mirror/Core/AssemblyInfo.cs | 1 + Assets/Mirror/Core/Attributes.cs | 14 +- Assets/Mirror/Core/Batching/Batcher.cs | 48 +- Assets/Mirror/Core/Batching/Unbatcher.cs | 57 +- Assets/Mirror/Core/ConnectionQuality.cs | 74 + Assets/Mirror/Core/ConnectionQuality.cs.meta | 11 + Assets/Mirror/Core/Empty.meta | 3 - Assets/Mirror/Core/Empty/ClientScene.cs | 1 - .../Mirror/Core/Empty/Cloud/ApiConnector.cs | 1 - Assets/Mirror/Core/Empty/Cloud/ApiUpdater.cs | 1 - Assets/Mirror/Core/Empty/Cloud/Ball.cs | 1 - Assets/Mirror/Core/Empty/Cloud/BallManager.cs | 1 - .../Core/Empty/Cloud/BallManager.cs.meta | 11 - Assets/Mirror/Core/Empty/Cloud/BaseApi.cs | 1 - .../Mirror/Core/Empty/Cloud/BaseApi.cs.meta | 11 - Assets/Mirror/Core/Empty/Cloud/Events.cs | 1 - Assets/Mirror/Core/Empty/Cloud/Events.cs.meta | 11 - Assets/Mirror/Core/Empty/Cloud/Extensions.cs | 1 - .../Core/Empty/Cloud/Extensions.cs.meta | 11 - .../Core/Empty/Cloud/ICoroutineRunner.cs | 1 - .../Core/Empty/Cloud/ICoroutineRunner.cs.meta | 11 - .../Core/Empty/Cloud/IRequestCreator.cs | 1 - .../Core/Empty/Cloud/IRequestCreator.cs.meta | 11 - .../Core/Empty/Cloud/IUnityEqualCheck.cs | 1 - .../Core/Empty/Cloud/IUnityEqualCheck.cs.meta | 11 - .../Empty/Cloud/InstantiateNetworkManager.cs | 1 - .../Cloud/InstantiateNetworkManager.cs.meta | 11 - Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs | 1 - .../Core/Empty/Cloud/JsonStructs.cs.meta | 11 - Assets/Mirror/Core/Empty/Cloud/ListServer.cs | 1 - .../Core/Empty/Cloud/ListServer.cs.meta | 11 - .../Core/Empty/Cloud/ListServerBaseApi.cs | 1 - .../Empty/Cloud/ListServerBaseApi.cs.meta | 11 - .../Core/Empty/Cloud/ListServerClientApi.cs | 1 - .../Empty/Cloud/ListServerClientApi.cs.meta | 11 - .../Mirror/Core/Empty/Cloud/ListServerJson.cs | 1 - .../Core/Empty/Cloud/ListServerJson.cs.meta | 11 - .../Core/Empty/Cloud/ListServerServerApi.cs | 1 - .../Empty/Cloud/ListServerServerApi.cs.meta | 11 - Assets/Mirror/Core/Empty/Cloud/Logger.cs | 1 - Assets/Mirror/Core/Empty/Cloud/Logger.cs.meta | 11 - .../Empty/Cloud/NetworkManagerListServer.cs | 1 - .../Cloud/NetworkManagerListServer.cs.meta | 11 - .../Cloud/NetworkManagerListServerPong.cs | 1 - .../NetworkManagerListServerPong.cs.meta | 11 - Assets/Mirror/Core/Empty/Cloud/Player.cs | 1 - Assets/Mirror/Core/Empty/Cloud/Player.cs.meta | 11 - .../Core/Empty/Cloud/QuickListServerDebug.cs | 1 - .../Empty/Cloud/QuickListServerDebug.cs.meta | 11 - .../Mirror/Core/Empty/Cloud/QuitButtonHUD.cs | 1 - .../Core/Empty/Cloud/QuitButtonHUD.cs.meta | 11 - .../Mirror/Core/Empty/Cloud/RequestCreator.cs | 1 - .../Core/Empty/Cloud/RequestCreator.cs.meta | 11 - .../Core/Empty/Cloud/ServerListManager.cs | 1 - .../Empty/Cloud/ServerListManager.cs.meta | 11 - .../Mirror/Core/Empty/Cloud/ServerListUI.cs | 1 - .../Core/Empty/Cloud/ServerListUI.cs.meta | 11 - .../Core/Empty/Cloud/ServerListUIItem.cs | 1 - .../Core/Empty/Cloud/ServerListUIItem.cs.meta | 11 - .../Mirror/Core/Empty/DotNetCompatibility.cs | 1 - .../Core/Empty/DotNetCompatibility.cs.meta | 11 - Assets/Mirror/Core/Empty/FallbackTransport.cs | 1 - Assets/Mirror/Core/Empty/LogFactory.cs | 1 - Assets/Mirror/Core/Empty/LogFactory.cs.meta | 11 - Assets/Mirror/Core/Empty/LogFilter.cs | 1 - .../Empty/Logging/ConsoleColorLogHandler.cs | 1 - .../Logging/ConsoleColorLogHandler.cs.meta | 11 - .../Empty/Logging/EditorLogSettingsLoader.cs | 1 - .../Logging/EditorLogSettingsLoader.cs.meta | 11 - .../Mirror/Core/Empty/Logging/LogFactory.cs | 1 - .../Core/Empty/Logging/LogFactory.cs.meta | 11 - .../Mirror/Core/Empty/Logging/LogSettings.cs | 2 - .../Core/Empty/Logging/LogSettings.cs.meta | 11 - .../Empty/Logging/NetworkHeadlessLogger.cs | 1 - .../Core/Empty/Logging/NetworkLogSettings.cs | 1 - .../Empty/Logging/NetworkLogSettings.cs.meta | 11 - .../Mirror/Core/Empty/NetworkMatchChecker.cs | 1 - .../Core/Empty/NetworkMatchChecker.cs.meta | 11 - .../Mirror/Core/Empty/NetworkOwnerChecker.cs | 1 - .../Core/Empty/NetworkOwnerChecker.cs.meta | 11 - .../Core/Empty/NetworkProximityChecker.cs | 1 - .../Empty/NetworkProximityChecker.cs.meta | 11 - .../Mirror/Core/Empty/NetworkSceneChecker.cs | 1 - .../Core/Empty/NetworkSceneChecker.cs.meta | 11 - .../Mirror/Core/Empty/NetworkTransformBase.cs | 1 - Assets/Mirror/Core/Empty/NetworkVisibility.cs | 1 - .../Core/Empty/NetworkVisibility.cs.meta | 11 - Assets/Mirror/Core/Empty/StringHash.cs | 1 - Assets/Mirror/Core/Empty/StringHash.cs.meta | 11 - Assets/Mirror/Core/Empty/SyncVar.cs | 1 - Assets/Mirror/Core/Empty/SyncVar.cs.meta | 11 - Assets/Mirror/Core/Empty/SyncVarGameObject.cs | 1 - .../Core/Empty/SyncVarGameObject.cs.meta | 11 - .../Core/Empty/SyncVarNetworkBehaviour.cs | 1 - .../Empty/SyncVarNetworkBehaviour.cs.meta | 11 - .../Core/Empty/SyncVarNetworkIdentity.cs | 1 - .../Core/Empty/SyncVarNetworkIdentity.cs.meta | 11 - Assets/Mirror/Core/HostMode.cs | 4 - Assets/Mirror/Core/InterestManagement.cs | 146 +- Assets/Mirror/Core/InterestManagementBase.cs | 77 + .../Core/InterestManagementBase.cs.meta | 11 + Assets/Mirror/Core/LagCompensation.meta | 3 + Assets/Mirror/Core/LagCompensation/Capture.cs | 13 + .../Core/LagCompensation/Capture.cs.meta | 11 + .../Core/LagCompensation/HistoryBounds.cs | 139 + .../LagCompensation/HistoryBounds.cs.meta | 11 + .../Core/LagCompensation/LagCompensation.cs | 144 + .../LagCompensation/LagCompensation.cs.meta | 11 + .../LagCompensationSettings.cs | 19 + .../LagCompensationSettings.cs.meta | 11 + .../Core/LagCompensation/MinMaxBounds.cs | 73 + .../Core/LagCompensation/MinMaxBounds.cs.meta | 11 + Assets/Mirror/Core/LocalConnectionToClient.cs | 47 +- Assets/Mirror/Core/LocalConnectionToServer.cs | 25 +- Assets/Mirror/Core/Messages.cs | 43 +- Assets/Mirror/Core/Mirror.asmdef | 4 +- Assets/Mirror/Core/NetworkBehaviour.cs | 163 +- Assets/Mirror/Core/NetworkClient.cs | 309 +- .../Core/NetworkClient_TimeInterpolation.cs | 65 +- Assets/Mirror/Core/NetworkConnection.cs | 82 +- .../Mirror/Core/NetworkConnectionToClient.cs | 108 +- .../Mirror/Core/NetworkConnectionToServer.cs | 2 - Assets/Mirror/Core/NetworkIdentity.cs | 136 +- Assets/Mirror/Core/NetworkLoop.cs | 18 + Assets/Mirror/Core/NetworkManager.cs | 289 +- Assets/Mirror/Core/NetworkManagerHUD.cs | 95 +- Assets/Mirror/Core/NetworkMessages.cs | 104 +- Assets/Mirror/Core/NetworkReader.cs | 14 +- Assets/Mirror/Core/NetworkReaderExtensions.cs | 118 +- Assets/Mirror/Core/NetworkReaderPool.cs | 5 +- Assets/Mirror/Core/NetworkServer.cs | 578 ++- Assets/Mirror/Core/NetworkTime.cs | 169 +- Assets/Mirror/Core/NetworkWriter.cs | 9 +- Assets/Mirror/Core/NetworkWriterExtensions.cs | 147 +- Assets/Mirror/Core/NetworkWriterPool.cs | 4 +- Assets/Mirror/Core/PortTransport.cs | 13 + Assets/Mirror/Core/PortTransport.cs.meta | 11 + Assets/Mirror/Core/Prediction.meta | 3 + Assets/Mirror/Core/Prediction/Prediction.cs | 195 + .../Mirror/Core/Prediction/Prediction.cs.meta | 11 + Assets/Mirror/Core/RemoteCalls.cs | 13 + .../SnapshotInterpolation.cs | 63 +- .../SnapshotInterpolationSettings.cs | 70 + .../SnapshotInterpolationSettings.cs.meta | 3 + .../TimeSnapshot.cs.meta | 10 +- Assets/Mirror/Core/SyncDictionary.cs | 220 +- Assets/Mirror/Core/SyncList.cs | 97 +- Assets/Mirror/Core/SyncSet.cs | 158 +- .../Empty.meta => Core/Threading.meta} | 2 +- .../Threading/ConcurrentNetworkWriterPool.cs | 45 + .../ConcurrentNetworkWriterPool.cs.meta | 11 + .../ConcurrentNetworkWriterPooled.cs | 11 + .../ConcurrentNetworkWriterPooled.cs.meta | 3 + .../Mirror/Core/Threading/ConcurrentPool.cs | 44 + .../Core/Threading/ConcurrentPool.cs.meta | 11 + Assets/Mirror/Core/Threading/ThreadLog.cs | 112 + .../Mirror/Core/Threading/ThreadLog.cs.meta | 11 + Assets/Mirror/Core/Threading/WorkerThread.cs | 165 + .../Core/Threading/WorkerThread.cs.meta | 11 + Assets/Mirror/Core/Tools/AccurateInterval.cs | 86 +- Assets/Mirror/Core/Tools/Compression.cs | 128 +- .../Core/Tools/ExponentialMovingAverage.cs | 12 +- Assets/Mirror/Core/Tools/Extensions.cs | 81 +- Assets/Mirror/Core/Tools/Mathd.cs | 13 +- Assets/Mirror/Core/Tools/Pool.cs | 10 +- Assets/Mirror/Core/Tools/Utils.cs | 35 +- Assets/Mirror/Core/Transport.cs | 13 + Assets/Mirror/Core/WeaverFuse.cs | 22 + Assets/Mirror/Core/WeaverFuse.cs.meta | 11 + Assets/Mirror/Editor/EditorHelper.cs | 10 + .../Empty/EnterPlayModeSettingsCheck.cs | 1 - .../Empty/EnterPlayModeSettingsCheck.cs.meta | 11 - Assets/Mirror/Editor/Empty/LogLevelWindow.cs | 1 - .../Editor/Empty/LogLevelWindow.cs.meta | 11 - Assets/Mirror/Editor/Empty/Logging.meta | 8 - .../Editor/Empty/Logging/LogLevelWindow.cs | 1 - .../Empty/Logging/LogLevelWindow.cs.meta | 11 - .../Editor/Empty/Logging/LogLevelsGUI.cs | 1 - .../Editor/Empty/Logging/LogLevelsGUI.cs.meta | 11 - .../Editor/Empty/Logging/LogSettingsEditor.cs | 1 - .../Empty/Logging/LogSettingsEditor.cs.meta | 11 - .../Empty/Logging/NetworkLogSettingsEditor.cs | 1 - .../Logging/NetworkLogSettingsEditor.cs.meta | 11 - .../Editor/Empty/ScriptableObjectUtility.cs | 1 - .../Empty/ScriptableObjectUtility.cs.meta | 11 - Assets/Mirror/Editor/Empty/SyncVarDrawer.cs | 1 - .../Mirror/Editor/Empty/SyncVarDrawer.cs.meta | 3 - .../Mirror/Editor/LagCompensatorInspector.cs | 14 + .../LagCompensatorInspector.cs.meta} | 2 +- Assets/Mirror/Editor/Mirror.Editor.asmdef | 1 + .../Editor/NetworkBehaviourInspector.cs | 3 +- .../Editor/NetworkInformationPreview.cs | 4 +- Assets/Mirror/Editor/NetworkManagerEditor.cs | 73 + .../Mirror/Editor/NetworkScenePostProcess.cs | 12 - Assets/Mirror/Editor/ReadOnlyDrawer.cs | 19 + .../ReadOnlyDrawer.cs.meta} | 2 +- .../Editor/SyncObjectCollectionsDrawer.cs | 8 +- Assets/Mirror/Editor/Weaver/Empty.meta | 8 - .../Weaver/Empty/GenericArgumentResolver.cs | 1 - .../Empty/GenericArgumentResolver.cs.meta | 11 - .../Weaver/Empty/MessageClassProcessor.cs | 1 - .../Empty/MessageClassProcessor.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Empty/Program.cs | 1 - .../Editor/Weaver/Empty/Program.cs.meta | 11 - .../Weaver/Empty/SyncDictionaryProcessor.cs | 1 - .../Empty/SyncDictionaryProcessor.cs.meta | 11 - .../Editor/Weaver/Empty/SyncEventProcessor.cs | 1 - .../Weaver/Empty/SyncEventProcessor.cs.meta | 11 - .../Editor/Weaver/Empty/SyncListProcessor.cs | 1 - .../Weaver/Empty/SyncListProcessor.cs.meta | 11 - .../EntryPoint/CompilationFinishedHook.cs | 13 +- .../ILPostProcessorAssemblyResolver.cs | 120 +- .../ILPostProcessorLogger.cs | 1 + Assets/Mirror/Editor/Weaver/Extensions.cs | 16 +- .../Weaver/Processors/CommandProcessor.cs | 16 +- .../Processors/NetworkBehaviourProcessor.cs | 86 +- .../Processors/ReaderWriterProcessor.cs | 16 + .../Editor/Weaver/Processors/RpcProcessor.cs | 7 +- .../ServerClientAttributeProcessor.cs | 13 +- .../SyncVarAttributeAccessReplacer.cs | 68 +- .../Processors/SyncVarAttributeProcessor.cs | 86 +- .../Weaver/Processors/TargetRpcProcessor.cs | 34 +- Assets/Mirror/Editor/Weaver/Readers.cs | 4 +- Assets/Mirror/Editor/Weaver/Resolvers.cs | 32 + Assets/Mirror/Editor/Weaver/Weaver.cs | 34 +- Assets/Mirror/Editor/Weaver/WeaverTypes.cs | 51 +- Assets/Mirror/Editor/Weaver/Writers.cs | 4 +- Assets/Mirror/Examples.meta | 8 - Assets/Mirror/Examples/AdditiveLevels.meta | 8 - .../Examples/AdditiveLevels/Materials.meta | 8 - .../AdditiveLevels/Materials/CubeSphere.mat | 77 - .../AdditiveLevels/Materials/Ground.mat | 77 - .../AdditiveLevels/Materials/Player.mat | 77 - .../AdditiveLevels/Materials/Portal.mat | 78 - .../AdditiveLevels/Materials/Skybox.mat | 104 - .../AdditiveLevels/Materials/Skybox.mat.meta | 9 - .../Materials/StartPoint.mat.meta | 8 - .../Examples/AdditiveLevels/Prefabs.meta | 8 - .../AdditiveLevels/Prefabs/Cube.prefab | 136 - .../AdditiveLevels/Prefabs/Cube.prefab.meta | 7 - .../AdditiveLevels/Prefabs/Plane.prefab | 156 - .../AdditiveLevels/Prefabs/Plane.prefab.meta | 7 - .../AdditiveLevels/Prefabs/Player.prefab | 367 -- .../AdditiveLevels/Prefabs/Player.prefab.meta | 7 - .../AdditiveLevels/Prefabs/Portal.prefab | 254 -- .../AdditiveLevels/Prefabs/Portal.prefab.meta | 7 - .../AdditiveLevels/Prefabs/Sphere.prefab | 136 - .../AdditiveLevels/Prefabs/Sphere.prefab.meta | 7 - .../AdditiveLevels/Prefabs/StartPoint.prefab | 85 - .../Prefabs/StartPoint.prefab.meta | 7 - .../Mirror/Examples/AdditiveLevels/ReadMe.txt | 1 - .../Examples/AdditiveLevels/Scenes.meta | 8 - .../AdditiveLevels/Scenes/Offline.unity | 505 --- .../AdditiveLevels/Scenes/Offline.unity.meta | 7 - .../AdditiveLevels/Scenes/Online.meta | 8 - .../AdditiveLevels/Scenes/Online.unity | 653 --- .../AdditiveLevels/Scenes/Online.unity.meta | 7 - .../Scenes/Online/LightingData.asset | Bin 19648 -> 0 bytes .../Scenes/Online/LightingData.asset.meta | 8 - .../Scenes/Online/ReflectionProbe-0.exr | Bin 115342 -> 0 bytes .../Scenes/Online/ReflectionProbe-0.exr.meta | 92 - .../Scenes/OnlineSettings.lighting | 63 - .../Scenes/OnlineSettings.lighting.meta | 8 - .../AdditiveLevels/Scenes/SubLevel1.unity | 1021 ----- .../Scenes/SubLevel1.unity.meta | 7 - .../AdditiveLevels/Scenes/SubLevel2.unity | 820 ---- .../Scenes/SubLevel2.unity.meta | 7 - .../Examples/AdditiveLevels/Scripts.meta | 8 - .../Scripts/AdditiveLevelsNetworkManager.cs | 197 - .../AdditiveLevelsNetworkManager.cs.meta | 11 - .../AdditiveLevels/Scripts/FadeInOut.cs | 52 - .../AdditiveLevels/Scripts/FadeInOut.cs.meta | 11 - .../Scripts/LookAtMainCamera.cs | 21 - .../Scripts/LookAtMainCamera.cs.meta | 11 - .../Scripts/PhysicsSimulator.cs | 40 - .../Scripts/PhysicsSimulator.cs.meta | 11 - .../AdditiveLevels/Scripts/PlayerCamera.cs | 44 - .../Scripts/PlayerCamera.cs.meta | 11 - .../Scripts/PlayerController.cs | 184 - .../Scripts/PlayerController.cs.meta | 11 - .../Examples/AdditiveLevels/Scripts/Portal.cs | 93 - .../AdditiveLevels/Scripts/Portal.cs.meta | 11 - .../AdditiveLevels/Scripts/RandomColor.cs | 36 - .../Scripts/RandomColor.cs.meta | 11 - .../Examples/AdditiveLevels/Textures.meta | 9 - .../AdditiveLevels/Textures/Back_Tex.jpeg | Bin 68766 -> 0 bytes .../AdditiveLevels/Textures/Down_Tex.jpeg | Bin 75605 -> 0 bytes .../Textures/Down_Tex.jpeg.meta | 92 - .../AdditiveLevels/Textures/Front_Tex.jpeg | Bin 72964 -> 0 bytes .../Textures/Front_Tex.jpeg.meta | 92 - .../AdditiveLevels/Textures/Left_Tex.jpeg | Bin 68026 -> 0 bytes .../Textures/Left_Tex.jpeg.meta | 92 - .../AdditiveLevels/Textures/Right_Tex.jpeg | Bin 70199 -> 0 bytes .../Textures/Right_Tex.jpeg.meta | 92 - .../AdditiveLevels/Textures/Up_Tex.jpeg | Bin 69705 -> 0 bytes .../AdditiveLevels/Textures/Up_Tex.jpeg.meta | 92 - Assets/Mirror/Examples/AdditiveScenes.meta | 8 - .../AdditiveScenes/AnimationControllers.meta | 8 - .../AnimationControllers/Tank.controller | 156 - .../AnimationControllers/Tank.controller.meta | 8 - .../Examples/AdditiveScenes/Materials.meta | 8 - .../AdditiveScenes/Materials/Capsule.mat | 77 - .../AdditiveScenes/Materials/Capsule.mat.meta | 8 - .../AdditiveScenes/Materials/Cube.mat | 77 - .../AdditiveScenes/Materials/Cube.mat.meta | 8 - .../AdditiveScenes/Materials/Cylinder.mat | 77 - .../Materials/Cylinder.mat.meta | 8 - .../AdditiveScenes/Materials/Player.mat | 77 - .../AdditiveScenes/Materials/Player.mat.meta | 8 - .../AdditiveScenes/Materials/Quad.mat | 77 - .../AdditiveScenes/Materials/Quad.mat.meta | 8 - .../AdditiveScenes/Materials/Shelter.mat | 77 - .../AdditiveScenes/Materials/Shelter.mat.meta | 8 - .../AdditiveScenes/Materials/Sphere.mat | 77 - .../AdditiveScenes/Materials/Sphere.mat.meta | 8 - .../AdditiveScenes/Materials/Zone.mat.meta | 8 - .../Examples/AdditiveScenes/Prefabs.meta | 8 - .../AdditiveScenes/Prefabs/Capsule.prefab | 150 - .../Prefabs/Capsule.prefab.meta | 7 - .../AdditiveScenes/Prefabs/Cube.prefab | 149 - .../AdditiveScenes/Prefabs/Cube.prefab.meta | 7 - .../AdditiveScenes/Prefabs/Cylinder.prefab | 150 - .../Prefabs/Cylinder.prefab.meta | 7 - .../AdditiveScenes/Prefabs/Player.prefab | 384 -- .../AdditiveScenes/Prefabs/Player.prefab.meta | 7 - .../AdditiveScenes/Prefabs/Sphere.prefab | 149 - .../AdditiveScenes/Prefabs/Sphere.prefab.meta | 7 - .../AdditiveScenes/Prefabs/Tank.prefab | 600 --- .../AdditiveScenes/Prefabs/Tank.prefab.meta | 7 - .../AdditiveScenes/Prefabs/Zone.prefab | 61 - .../AdditiveScenes/Prefabs/Zone.prefab.meta | 7 - .../Mirror/Examples/AdditiveScenes/README.md | 24 - .../Examples/AdditiveScenes/README.md.meta | 7 - .../Examples/AdditiveScenes/Scenes.meta | 8 - .../AdditiveScenes/Scenes/MainScene.unity | 2238 ---------- .../Scenes/MainScene.unity.meta | 7 - .../AdditiveScenes/Scenes/SubScene.unity | 937 ---- .../AdditiveScenes/Scenes/SubScene.unity.meta | 7 - .../Examples/AdditiveScenes/Scripts.meta | 8 - .../Scripts/AdditiveNetworkManager.cs | 70 - .../Scripts/AdditiveNetworkManager.cs.meta | 11 - .../AdditiveScenes/Scripts/PlayerCamera.cs | 44 - .../Scripts/PlayerCamera.cs.meta | 11 - .../Scripts/PlayerController.cs | 185 - .../Scripts/PlayerController.cs.meta | 11 - .../AdditiveScenes/Scripts/RandomColor.cs | 31 - .../Scripts/RandomColor.cs.meta | 11 - .../Scripts/ShootingTankBehaviour.cs | 59 - .../Scripts/ShootingTankBehaviour.cs.meta | 11 - .../AdditiveScenes/Scripts/ZoneHandler.cs | 42 - .../Scripts/ZoneHandler.cs.meta | 11 - Assets/Mirror/Examples/Basic.meta | 8 - Assets/Mirror/Examples/Basic/Prefabs.meta | 8 - .../Examples/Basic/Prefabs/Player.prefab | 73 - .../Examples/Basic/Prefabs/Player.prefab.meta | 7 - .../Examples/Basic/Prefabs/PlayerUI.prefab | 256 -- .../Basic/Prefabs/PlayerUI.prefab.meta | 7 - Assets/Mirror/Examples/Basic/README.md | 16 - Assets/Mirror/Examples/Basic/README.md.meta | 7 - Assets/Mirror/Examples/Basic/Scenes.meta | 8 - .../Examples/Basic/Scenes/Example.unity | 819 ---- .../Examples/Basic/Scenes/Example.unity.meta | 7 - Assets/Mirror/Examples/Basic/Scripts.meta | 8 - .../Examples/Basic/Scripts/BasicNetManager.cs | 43 - .../Basic/Scripts/BasicNetManager.cs.meta | 11 - .../Mirror/Examples/Basic/Scripts/CanvasUI.cs | 28 - .../Examples/Basic/Scripts/CanvasUI.cs.meta | 11 - .../Mirror/Examples/Basic/Scripts/Player.cs | 180 - .../Examples/Basic/Scripts/Player.cs.meta | 11 - .../Mirror/Examples/Basic/Scripts/PlayerUI.cs | 41 - .../Examples/Basic/Scripts/PlayerUI.cs.meta | 11 - Assets/Mirror/Examples/Benchmark.meta | 8 - .../Mirror/Examples/Benchmark/Materials.meta | 8 - .../Examples/Benchmark/Materials/Red.mat | 77 - .../Examples/Benchmark/Materials/Red.mat.meta | 8 - .../Examples/Benchmark/Materials/White.mat | 77 - .../Benchmark/Materials/White.mat.meta | 8 - Assets/Mirror/Examples/Benchmark/Prefabs.meta | 8 - .../Examples/Benchmark/Prefabs/Monster.prefab | 151 - .../Benchmark/Prefabs/Monster.prefab.meta | 7 - .../Examples/Benchmark/Prefabs/Player.prefab | 149 - .../Benchmark/Prefabs/Player.prefab.meta | 7 - Assets/Mirror/Examples/Benchmark/Scenes.meta | 8 - .../Examples/Benchmark/Scenes/Scene.unity | 487 --- .../Benchmark/Scenes/Scene.unity.meta | 7 - Assets/Mirror/Examples/Benchmark/Scripts.meta | 8 - .../Scripts/BenchmarkNetworkManager.cs | 52 - .../Scripts/BenchmarkNetworkManager.cs.meta | 11 - .../Benchmark/Scripts/MonsterMovement.cs | 50 - .../Benchmark/Scripts/MonsterMovement.cs.meta | 11 - .../Benchmark/Scripts/PlayerMovement.cs | 20 - .../Benchmark/Scripts/PlayerMovement.cs.meta | 11 - Assets/Mirror/Examples/CCU.meta | 8 - Assets/Mirror/Examples/CCU/CCU.unity | 527 --- Assets/Mirror/Examples/CCU/CCU.unity.meta | 7 - .../Mirror/Examples/CCU/CCUNetworkManager.cs | 93 - .../Examples/CCU/CCUNetworkManager.cs.meta | 11 - Assets/Mirror/Examples/CCU/Monster.cs | 55 - Assets/Mirror/Examples/CCU/Monster.cs.meta | 11 - Assets/Mirror/Examples/CCU/Monster.prefab | 151 - .../Mirror/Examples/CCU/Monster.prefab.meta | 7 - Assets/Mirror/Examples/CCU/Player.cs | 99 - Assets/Mirror/Examples/CCU/Player.cs.meta | 11 - Assets/Mirror/Examples/CCU/Player.prefab | 174 - Assets/Mirror/Examples/CCU/Player.prefab.meta | 7 - Assets/Mirror/Examples/CCU/Red.mat | 77 - Assets/Mirror/Examples/CCU/Red.mat.meta | 8 - Assets/Mirror/Examples/CCU/White.mat | 77 - Assets/Mirror/Examples/CCU/White.mat.meta | 8 - Assets/Mirror/Examples/Chat.meta | 8 - Assets/Mirror/Examples/Chat/Prefabs.meta | 8 - .../Examples/Chat/Prefabs/Player.prefab | 68 - .../Examples/Chat/Prefabs/Player.prefab.meta | 7 - Assets/Mirror/Examples/Chat/Scenes.meta | 8 - Assets/Mirror/Examples/Chat/Scenes/Main.unity | 3799 ----------------- .../Examples/Chat/Scenes/Main.unity.meta | 7 - Assets/Mirror/Examples/Chat/Scripts.meta | 8 - .../Chat/Scripts/ChatAuthenticator.cs | 210 - .../Chat/Scripts/ChatAuthenticator.cs.meta | 11 - .../Chat/Scripts/ChatNetworkManager.cs | 46 - .../Chat/Scripts/ChatNetworkManager.cs.meta | 11 - Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs | 100 - .../Examples/Chat/Scripts/ChatUI.cs.meta | 11 - .../Mirror/Examples/Chat/Scripts/LoginUI.cs | 28 - .../Examples/Chat/Scripts/LoginUI.cs.meta | 11 - Assets/Mirror/Examples/Chat/Scripts/Player.cs | 30 - .../Examples/Chat/Scripts/Player.cs.meta | 11 - Assets/Mirror/Examples/Common.meta | 8 - Assets/Mirror/Examples/Common/FPS.cs | 37 - Assets/Mirror/Examples/Common/FPS.cs.meta | 11 - Assets/Mirror/Examples/Discovery.meta | 8 - Assets/Mirror/Examples/Discovery/Prefabs.meta | 8 - .../Examples/Discovery/Prefabs/Player.prefab | 118 - .../Discovery/Prefabs/Player.prefab.meta | 7 - Assets/Mirror/Examples/Discovery/Scenes.meta | 8 - .../Examples/Discovery/Scenes/Scene.unity | 731 ---- .../Discovery/Scenes/Scene.unity.meta | 7 - Assets/Mirror/Examples/Mirror.Examples.asmdef | 18 - .../Examples/MultipleAdditiveScenes.meta | 8 - .../MultipleAdditiveScenes/Materials.meta | 8 - .../Materials/Physics.meta | 8 - .../Physics/Icosphere.physicMaterial | 14 - .../Physics/Icosphere.physicMaterial.meta | 8 - .../Materials/Physics/Player.physicMaterial | 14 - .../Physics/Player.physicMaterial.meta | 8 - .../Physics/RoomBounce.physicMaterial | 14 - .../Physics/RoomBounce.physicMaterial.meta | 8 - .../Materials/Render.meta | 8 - .../Materials/Render/PlayArea.mat | 77 - .../Materials/Render/PlayArea.mat.meta | 8 - .../Materials/Render/Player.mat | 77 - .../Materials/Render/Player.mat.meta | 8 - .../Materials/Render/Prize.mat | 77 - .../Materials/Render/Prize.mat.meta | 8 - .../MultipleAdditiveScenes/Models.meta | 8 - .../Models/Icosphere.meta | 8 - .../Models/Icosphere/Icosphere.obj | 119 - .../Models/Icosphere/Icosphere.obj.meta | 104 - .../Models/Icosphere/Materials.meta | 8 - .../Models/Icosphere/Materials/Icosphere.mat | 77 - .../Icosphere/Materials/Icosphere.mat.meta | 8 - .../MultipleAdditiveScenes/Prefabs.meta | 8 - .../Prefabs/Icosphere.prefab | 233 - .../Prefabs/Icosphere.prefab.meta | 7 - .../Prefabs/Player.prefab | 388 -- .../Prefabs/Player.prefab.meta | 8 - .../Prefabs/Prize.prefab | 203 - .../Prefabs/Prize.prefab.meta | 8 - .../Examples/MultipleAdditiveScenes/README.md | 34 - .../MultipleAdditiveScenes/README.md.meta | 7 - .../MultipleAdditiveScenes/Scenes.meta | 8 - .../MultipleAdditiveScenes/Scenes/Game.unity | 753 ---- .../Scenes/Game.unity.meta | 7 - .../MultipleAdditiveScenes/Scenes/Main.unity | 944 ---- .../Scenes/Main.unity.meta | 7 - .../MultipleAdditiveScenes/Scripts.meta | 8 - .../Scripts/MultiSceneNetManager.cs | 157 - .../Scripts/MultiSceneNetManager.cs.meta | 11 - .../Scripts/PhysicsCollision.cs | 44 - .../Scripts/PhysicsCollision.cs.meta | 11 - .../Scripts/PhysicsSimulator.cs | 39 - .../Scripts/PhysicsSimulator.cs.meta | 11 - .../Scripts/PlayerCamera.cs | 44 - .../Scripts/PlayerCamera.cs.meta | 11 - .../Scripts/PlayerController.cs | 184 - .../Scripts/PlayerController.cs.meta | 11 - .../Scripts/PlayerScore.cs | 30 - .../Scripts/PlayerScore.cs.meta | 11 - .../Scripts/RandomColor.cs | 31 - .../Scripts/RandomColor.cs.meta | 11 - .../MultipleAdditiveScenes/Scripts/Reward.cs | 52 - .../Scripts/Reward.cs.meta | 11 - .../MultipleAdditiveScenes/Scripts/Spawner.cs | 24 - .../Scripts/Spawner.cs.meta | 11 - Assets/Mirror/Examples/MultipleMatches.meta | 8 - .../Examples/MultipleMatches/Prefabs.meta | 8 - .../MultipleMatches/Prefabs/CellGUI.prefab | 153 - .../Prefabs/CellGUI.prefab.meta | 7 - .../Prefabs/MatchController.prefab | 1967 --------- .../Prefabs/MatchController.prefab.meta | 7 - .../MultipleMatches/Prefabs/MatchGUI.prefab | 307 -- .../Prefabs/MatchGUI.prefab.meta | 7 - .../Prefabs/MatchPlayer.prefab | 67 - .../Prefabs/MatchPlayer.prefab.meta | 7 - .../MultipleMatches/Prefabs/PlayerGUI.prefab | 189 - .../Prefabs/PlayerGUI.prefab.meta | 7 - .../Mirror/Examples/MultipleMatches/README.md | 9 - .../Examples/MultipleMatches/Scenes.meta | 8 - .../MultipleMatches/Scenes/Main.unity | 2982 ------------- .../MultipleMatches/Scenes/Main.unity.meta | 7 - .../Examples/MultipleMatches/Scripts.meta | 8 - .../Scripts/CanvasController.cs | 652 --- .../Scripts/CanvasController.cs.meta | 11 - .../MultipleMatches/Scripts/CellGUI.cs | 47 - .../MultipleMatches/Scripts/CellGUI.cs.meta | 11 - .../Scripts/MatchController.cs | 310 -- .../Scripts/MatchController.cs.meta | 11 - .../MultipleMatches/Scripts/MatchGUI.cs | 44 - .../MultipleMatches/Scripts/MatchGUI.cs.meta | 11 - .../MultipleMatches/Scripts/MatchMessages.cs | 117 - .../Scripts/MatchMessages.cs.meta | 11 - .../Scripts/MatchNetworkManager.cs | 123 - .../Scripts/MatchNetworkManager.cs.meta | 11 - .../MultipleMatches/Scripts/PlayerGUI.cs | 17 - .../MultipleMatches/Scripts/PlayerGUI.cs.meta | 11 - .../MultipleMatches/Scripts/RoomGUI.cs | 45 - .../MultipleMatches/Scripts/RoomGUI.cs.meta | 11 - Assets/Mirror/Examples/Pong.meta | 8 - .../Examples/Pong/PhysicsMaterials.meta | 8 - .../BallMaterial.physicsMaterial2D | 10 - .../BallMaterial.physicsMaterial2D.meta | 8 - Assets/Mirror/Examples/Pong/Prefabs.meta | 8 - .../Mirror/Examples/Pong/Prefabs/Ball.prefab | 200 - .../Examples/Pong/Prefabs/Ball.prefab.meta | 8 - .../Examples/Pong/Prefabs/Racket.prefab | 200 - .../Examples/Pong/Prefabs/Racket.prefab.meta | 8 - Assets/Mirror/Examples/Pong/Scenes.meta | 8 - .../Mirror/Examples/Pong/Scenes/Scene.unity | 906 ---- .../Examples/Pong/Scenes/Scene.unity.meta | 8 - Assets/Mirror/Examples/Pong/Scripts.meta | 8 - Assets/Mirror/Examples/Pong/Scripts/Ball.cs | 61 - .../Mirror/Examples/Pong/Scripts/Ball.cs.meta | 12 - .../Pong/Scripts/NetworkManagerPong.cs | 45 - .../Pong/Scripts/NetworkManagerPong.cs.meta | 11 - Assets/Mirror/Examples/Pong/Scripts/Player.cs | 19 - .../Examples/Pong/Scripts/Player.cs.meta | 12 - Assets/Mirror/Examples/Pong/Sprites.meta | 8 - Assets/Mirror/Examples/Pong/Sprites/Ball.png | Bin 2791 -> 0 bytes .../Examples/Pong/Sprites/Ball.png.meta | 88 - .../Examples/Pong/Sprites/DottedLine.png | Bin 2799 -> 0 bytes .../Examples/Pong/Sprites/DottedLine.png.meta | 88 - .../Mirror/Examples/Pong/Sprites/Racket.png | Bin 2800 -> 0 bytes .../Examples/Pong/Sprites/Racket.png.meta | 88 - .../Examples/Pong/Sprites/WallHorizontal.png | Bin 2796 -> 0 bytes .../Pong/Sprites/WallHorizontal.png.meta | 88 - .../Examples/Pong/Sprites/WallVertical.png | Bin 2800 -> 0 bytes .../Pong/Sprites/WallVertical.png.meta | 88 - Assets/Mirror/Examples/RigidbodyPhysics.meta | 8 - .../Examples/RigidbodyPhysics/Materials.meta | 8 - .../RigidbodyPhysics/Materials/Blue.mat | 77 - .../RigidbodyPhysics/Materials/Blue.mat.meta | 8 - .../RigidbodyPhysics/Materials/Floor.mat | 77 - .../RigidbodyPhysics/Materials/Floor.mat.meta | 8 - .../RigidbodyPhysics/Materials/Green.mat | 77 - .../RigidbodyPhysics/Materials/Green.mat.meta | 8 - .../RigidbodyPhysics/Materials/Orange.mat | 78 - .../Materials/Orange.mat.meta | 8 - .../RigidbodyPhysics/Materials/Red.mat | 77 - .../RigidbodyPhysics/Materials/Red.mat.meta | 8 - .../RigidbodyPhysics/PhysicMaterials.meta | 8 - .../PhysicMaterials/Ball.physicMaterial | 14 - .../PhysicMaterials/Ball.physicMaterial.meta | 8 - .../PhysicMaterials/Floor.physicMaterial | 14 - .../PhysicMaterials/Floor.physicMaterial.meta | 8 - .../Examples/RigidbodyPhysics/Prefabs.meta | 8 - .../Prefabs/Empty Player.prefab | 51 - .../Prefabs/Empty Player.prefab.meta | 7 - .../Examples/RigidbodyPhysics/Scenes.meta | 8 - .../RigidbodyPhysics/Scenes/BounceScene.unity | 2163 ---------- .../Scenes/BounceScene.unity.meta | 7 - .../Examples/RigidbodyPhysics/Scripts.meta | 8 - .../RigidbodyPhysics/Scripts/AddForce.cs | 29 - .../RigidbodyPhysics/Scripts/AddForce.cs.meta | 11 - Assets/Mirror/Examples/Room.meta | 8 - Assets/Mirror/Examples/Room/Materials.meta | 8 - .../Examples/Room/Materials/PlayArea.mat | 77 - .../Examples/Room/Materials/PlayArea.mat.meta | 8 - .../Mirror/Examples/Room/Materials/Player.mat | 77 - .../Examples/Room/Materials/Player.mat.meta | 8 - .../Mirror/Examples/Room/Materials/Prize.mat | 77 - .../Examples/Room/Materials/Prize.mat.meta | 8 - .../Examples/Room/Materials/Textures.meta | 8 - .../Room/Materials/Textures/Wall01.tga | Bin 1048620 -> 0 bytes .../Room/Materials/Textures/Wall01.tga.meta | 88 - .../Room/Materials/Textures/Wall01_n.tga | Bin 1048620 -> 0 bytes .../Room/Materials/Textures/Wall01_n.tga.meta | 88 - Assets/Mirror/Examples/Room/Prefabs.meta | 8 - .../Examples/Room/Prefabs/GamePlayer.prefab | 385 -- .../Room/Prefabs/GamePlayer.prefab.meta | 8 - .../Mirror/Examples/Room/Prefabs/Prize.prefab | 203 - .../Examples/Room/Prefabs/Prize.prefab.meta | 8 - .../Examples/Room/Prefabs/RoomPlayer.prefab | 70 - .../Room/Prefabs/RoomPlayer.prefab.meta | 8 - Assets/Mirror/Examples/Room/README.md | 28 - Assets/Mirror/Examples/Room/README.md.meta | 7 - Assets/Mirror/Examples/Room/Scenes.meta | 8 - .../Examples/Room/Scenes/OfflineScene.unity | 312 -- .../Room/Scenes/OfflineScene.unity.meta | 7 - .../Examples/Room/Scenes/OnlineScene.unity | 907 ---- .../Room/Scenes/OnlineScene.unity.meta | 7 - .../Room/Scenes/OnlineSceneSettings.lighting | 64 - .../Scenes/OnlineSceneSettings.lighting.meta | 8 - .../Examples/Room/Scenes/RoomScene.unity | 187 - .../Examples/Room/Scenes/RoomScene.unity.meta | 7 - Assets/Mirror/Examples/Room/Scripts.meta | 8 - .../Room/Scripts/NetworkRoomManagerExt.cs | 99 - .../Scripts/NetworkRoomManagerExt.cs.meta | 11 - .../Room/Scripts/NetworkRoomPlayerExt.cs | 38 - .../Room/Scripts/NetworkRoomPlayerExt.cs.meta | 11 - .../Examples/Room/Scripts/PlayerCamera.cs | 44 - .../Room/Scripts/PlayerCamera.cs.meta | 11 - .../Examples/Room/Scripts/PlayerController.cs | 184 - .../Room/Scripts/PlayerController.cs.meta | 11 - .../Examples/Room/Scripts/PlayerScore.cs | 18 - .../Examples/Room/Scripts/PlayerScore.cs.meta | 11 - .../Examples/Room/Scripts/RandomColor.cs | 31 - .../Examples/Room/Scripts/RandomColor.cs.meta | 11 - Assets/Mirror/Examples/Room/Scripts/Reward.cs | 53 - .../Examples/Room/Scripts/Reward.cs.meta | 11 - .../Mirror/Examples/Room/Scripts/Spawner.cs | 21 - .../Examples/Room/Scripts/Spawner.cs.meta | 11 - .../Examples/Snapshot Interpolation.meta | 8 - .../Snapshot Interpolation/ClientCube.cs | 205 - .../Snapshot Interpolation/ClientCube.cs.meta | 3 - .../Snapshot Interpolation/ClientMaterial.mat | 80 - .../ClientMaterial.mat.meta | 8 - .../Snapshot Interpolation/ServerCube.cs | 117 - .../Snapshot Interpolation/ServerCube.cs.meta | 11 - .../Snapshot Interpolation/ServerMaterial.mat | 80 - .../ServerMaterial.mat.meta | 8 - .../Snapshot Interpolation/Snapshot3D.cs | 26 - .../Snapshot Interpolation/Snapshot3D.cs.meta | 11 - .../SnapshotInterpolation.unity | 455 -- .../SnapshotInterpolation.unity.meta | 7 - .../Snapshot Interpolation/_DISABLE VSYNC_ | 2 - .../_DISABLE VSYNC_.meta | 7 - Assets/Mirror/Examples/SyncDirection.meta | 8 - .../Mirror/Examples/SyncDirection/Player.cs | 58 - .../Examples/SyncDirection/Player.cs.meta | 11 - .../Examples/SyncDirection/Player.prefab | 220 - .../Examples/SyncDirection/Player.prefab.meta | 7 - .../Mirror/Examples/SyncDirection/Scene.unity | 605 --- .../Examples/SyncDirection/Scene.unity.meta | 7 - .../Mirror/Examples/SyncDirection/White.mat | 77 - .../Examples/SyncDirection/White.mat.meta | 8 - Assets/Mirror/Examples/Tanks.meta | 8 - Assets/Mirror/Examples/Tanks/Models.meta | 8 - .../Models/(Public Domain) Recon_Tank.meta | 8 - .../(Public Domain) Recon_Tank/BaseColor.png | Bin 939498 -> 0 bytes .../BaseColor.png.meta | 88 - .../Controller.controller | 272 -- .../Controller.controller.meta | 8 - .../(Public Domain) Recon_Tank/Emissive.png | Bin 80294 -> 0 bytes .../Emissive.png.meta | 88 - .../(Public Domain) Recon_Tank/Metallic.png | Bin 62860 -> 0 bytes .../Metallic.png.meta | 88 - .../(Public Domain) Recon_Tank/Normal.png | Bin 666342 -> 0 bytes .../Normal.png.meta | 88 - .../Recon_Tank - License.txt | 7 - .../Recon_Tank - License.txt.meta | 7 - .../TankMaterial.mat | 82 - .../TankMaterial.mat.meta | 8 - .../(Public Domain) Recon_Tank/reconTank.fbx | Bin 224204 -> 0 bytes .../reconTank.fbx.meta | 239 -- Assets/Mirror/Examples/Tanks/Prefabs.meta | 8 - .../Examples/Tanks/Prefabs/Projectile.prefab | 186 - .../Tanks/Prefabs/Projectile.prefab.meta | 7 - .../Mirror/Examples/Tanks/Prefabs/Tank.prefab | 407 -- .../Examples/Tanks/Prefabs/Tank.prefab.meta | 8 - Assets/Mirror/Examples/Tanks/Scenes.meta | 8 - .../Mirror/Examples/Tanks/Scenes/Scene.meta | 8 - .../Mirror/Examples/Tanks/Scenes/Scene.unity | 709 --- .../Examples/Tanks/Scenes/Scene.unity.meta | 7 - .../Examples/Tanks/Scenes/Scene/NavMesh.asset | Bin 5444 -> 0 bytes .../Tanks/Scenes/Scene/NavMesh.asset.meta | 8 - .../Tanks/Scenes/SceneSettings.lighting | 64 - .../Tanks/Scenes/SceneSettings.lighting.meta | 8 - Assets/Mirror/Examples/Tanks/Scripts.meta | 8 - .../Examples/Tanks/Scripts/FaceCamera.cs | 14 - .../Examples/Tanks/Scripts/FaceCamera.cs.meta | 3 - .../Examples/Tanks/Scripts/Projectile.cs | 35 - .../Examples/Tanks/Scripts/Projectile.cs.meta | 11 - Assets/Mirror/Examples/Tanks/Scripts/Tank.cs | 95 - .../Examples/Tanks/Scripts/Tank.cs.meta | 11 - Assets/Mirror/Examples/Tanks/Textures.meta | 8 - ...lic Domain) Dirt Hand Painted Texture.meta | 8 - .../Dirt Hand Painted Texture - License.txt | 5 - ...rt Hand Painted Texture - License.txt.meta | 7 - .../Dirt.mat | 82 - .../Dirt.mat.meta | 8 - .../dirt.png | Bin 105829 -> 0 bytes .../dirt.png.meta | 88 - .../Tanks/Textures/ProjectileMaterial.mat | 77 - .../Textures/ProjectileMaterial.mat.meta | 8 - .../Cloud.meta => Plugins/BouncyCastle.meta} | 2 +- .../BouncyCastle.Cryptography.dll | Bin 0 -> 6954264 bytes .../BouncyCastle.Cryptography.dll.meta | 33 + Assets/Mirror/Plugins/BouncyCastle/LICENSE.md | 13 + .../BouncyCastle/LICENSE.md.meta} | 2 +- ...kTransformUnreliable.meta => Presets.meta} | 2 +- Assets/Mirror/Presets/NetworkTransform.meta | 8 + .../ClientAuth-Balanced.preset | 124 + .../ClientAuth-Balanced.preset.meta} | 4 +- .../ClientAuth-FastPaced.preset | 124 + .../ClientAuth-FastPaced.preset.meta} | 4 +- .../ClientAuth-VeryCasual.preset | 124 + .../ClientAuth-VeryCasual.preset.meta | 8 + Assets/Mirror/Transports/Edgegap.meta | 8 + .../Transports/Edgegap/EdgegapLobby.meta | 8 + .../EdgegapLobby/EdgegapLobbyKcpTransport.cs | 342 ++ .../EdgegapLobbyKcpTransport.cs.meta | 11 + .../Edgegap/EdgegapLobby/LobbyApi.cs | 295 ++ .../Edgegap/EdgegapLobby/LobbyApi.cs.meta | 11 + .../LobbyServiceCreateDialogue.cs | 138 + .../LobbyServiceCreateDialogue.cs.meta | 11 + .../EdgegapLobby/LobbyTransportInspector.cs | 64 + .../LobbyTransportInspector.cs.meta | 11 + .../Edgegap/EdgegapLobby/Models.meta | 3 + .../Models/ListLobbiesResponse.cs | 12 + .../Models/ListLobbiesResponse.cs.meta | 11 + .../Edgegap/EdgegapLobby/Models/Lobby.cs | 45 + .../Edgegap/EdgegapLobby/Models/Lobby.cs.meta | 11 + .../Edgegap/EdgegapLobby/Models/LobbyBrief.cs | 17 + .../EdgegapLobby/Models/LobbyBrief.cs.meta | 11 + .../EdgegapLobby/Models/LobbyCreateRequest.cs | 27 + .../Models/LobbyCreateRequest.cs.meta | 11 + .../EdgegapLobby/Models/LobbyIdRequest.cs | 14 + .../Models/LobbyIdRequest.cs.meta | 11 + .../Models/LobbyJoinOrLeaveRequest.cs | 17 + .../Models/LobbyJoinOrLeaveRequest.cs.meta | 11 + .../EdgegapLobby/Models/LobbyUpdateRequest.cs | 12 + .../Models/LobbyUpdateRequest.cs.meta | 11 + .../Transports/Edgegap/EdgegapRelay.meta | 8 + .../Edgegap/EdgegapRelay/EdgegapKcpClient.cs | 141 + .../EdgegapRelay/EdgegapKcpClient.cs.meta | 11 + .../Edgegap/EdgegapRelay/EdgegapKcpServer.cs | 203 + .../EdgegapRelay/EdgegapKcpServer.cs.meta | 11 + .../EdgegapRelay/EdgegapKcpTransport.cs | 162 + .../EdgegapRelay/EdgegapKcpTransport.cs.meta | 11 + .../Edgegap/EdgegapRelay/Protocol.cs | 29 + .../Edgegap/EdgegapRelay/Protocol.cs.meta | 11 + .../Transports/Edgegap/EdgegapRelay/README.md | 20 + .../Edgegap/EdgegapRelay}/README.md.meta | 2 +- .../EdgegapRelay/RelayCredentialsFromArgs.cs | 25 + .../RelayCredentialsFromArgs.cs.meta | 11 + Assets/Mirror/Transports/Edgegap/edgegap.png | Bin 0 -> 4347 bytes .../Edgegap/edgegap.png.meta} | 55 +- Assets/Mirror/Transports/Encryption.meta | 3 + .../Mirror/Transports/Encryption/Editor.meta | 3 + .../Editor/EncryptionTransportEditor.asmdef} | 8 +- .../EncryptionTransportEditor.asmdef.meta} | 2 +- .../Editor/EncryptionTransportInspector.cs | 81 + .../EncryptionTransportInspector.cs.meta | 3 + .../Encryption/EncryptedConnection.cs | 595 +++ .../Encryption/EncryptedConnection.cs.meta | 3 + .../Encryption/EncryptionCredentials.cs | 125 + .../Encryption/EncryptionCredentials.cs.meta | 3 + .../Encryption/EncryptionTransport.cs | 270 ++ .../Encryption/EncryptionTransport.cs.meta | 11 + .../Transports/Encryption/PubKeyInfo.cs | 9 + .../Transports/Encryption/PubKeyInfo.cs.meta | 3 + .../KCP/{MirrorTransport => }/KcpTransport.cs | 133 +- .../KcpTransport.cs.meta | 0 .../Transports/KCP/MirrorTransport.meta | 8 - .../Transports/KCP/ThreadedKcpTransport.cs | 327 ++ .../KCP/ThreadedKcpTransport.cs.meta | 11 + Assets/Mirror/Transports/KCP/kcp2k/KCP.asmdef | 4 +- .../Mirror/Transports/KCP/kcp2k/VERSION.txt | 71 + .../KCP/kcp2k/empty/KcpClientConnection.cs | 1 - .../kcp2k/empty/KcpClientConnection.cs.meta | 3 - .../empty/KcpClientConnectionNonAlloc.cs | 1 - .../empty/KcpClientConnectionNonAlloc.cs.meta | 3 - .../KCP/kcp2k/empty/KcpClientNonAlloc.cs | 1 - .../KCP/kcp2k/empty/KcpClientNonAlloc.cs.meta | 3 - .../empty/KcpServerConnectionNonAlloc.cs | 1 - .../empty/KcpServerConnectionNonAlloc.cs.meta | 3 - .../Transports/KCP/kcp2k/highlevel/Common.cs | 45 +- .../KCP/kcp2k/highlevel/Extensions.cs | 165 +- .../KCP/kcp2k/highlevel/KcpClient.cs | 256 +- .../KCP/kcp2k/highlevel/KcpConfig.cs | 43 +- .../KCP/kcp2k/highlevel/KcpHeader.cs | 46 +- .../Transports/KCP/kcp2k/highlevel/KcpPeer.cs | 444 +- .../KCP/kcp2k/highlevel/KcpServer.cs | 207 +- .../kcp2k/highlevel/KcpServerConnection.cs | 120 +- .../KCP/kcp2k/highlevel/KcpState.cs | 4 + .../KCP/kcp2k/highlevel/KcpState.cs.meta} | 2 +- .../Transports/KCP/kcp2k/kcp/AckItem.cs | 8 + .../KCP/kcp2k/kcp/AckItem.cs.meta} | 2 +- Assets/Mirror/Transports/KCP/kcp2k/kcp/Kcp.cs | 200 +- .../Transports/KCP/kcp2k/kcp/Segment.cs | 25 +- .../Mirror/Transports/KCP/kcp2k/kcp/Utils.cs | 32 +- .../Transports/Latency/LatencySimulation.cs | 203 +- .../MiddlewareTransport.asmdef.meta | 7 - .../Middleware/MiddlewareTransport.cs | 2 + .../Multiplex/MultiplexTransport.asmdef | 16 - .../Multiplex/MultiplexTransport.asmdef.meta | 7 - .../Multiplex/MultiplexTransport.cs | 146 +- .../Mirror/Transports/SimpleWeb/Common/Log.cs | 124 - .../Mirror/Transports/SimpleWeb/Editor.meta | 8 + .../Editor/ClientWebsocketSettingsDrawer.cs | 71 + .../ClientWebsocketSettingsDrawer.cs.meta | 3 + .../Transports/SimpleWeb/SimpleWeb.meta | 8 + .../SimpleWeb/{ => SimpleWeb}/AssemblyInfo.cs | 2 +- .../{ => SimpleWeb}/AssemblyInfo.cs.meta | 0 .../SimpleWeb/{ => SimpleWeb}/CHANGELOG.md | 0 .../{ => SimpleWeb}/CHANGELOG.md.meta | 0 .../SimpleWeb/{ => SimpleWeb}/Client.meta | 0 .../Client/ClientWebsocketSettings.cs | 17 + .../Client/ClientWebsocketSettings.cs.meta | 3 + .../{ => SimpleWeb}/Client/SimpleWebClient.cs | 40 +- .../Client/SimpleWebClient.cs.meta | 0 .../{ => SimpleWeb}/Client/StandAlone.meta | 0 .../Client/StandAlone/ClientHandshake.cs | 22 +- .../Client/StandAlone/ClientHandshake.cs.meta | 0 .../Client/StandAlone/ClientSslHelper.cs | 2 +- .../Client/StandAlone/ClientSslHelper.cs.meta | 0 .../StandAlone/WebSocketClientStandAlone.cs | 13 +- .../WebSocketClientStandAlone.cs.meta | 0 .../{ => SimpleWeb}/Client/Webgl.meta | 0 .../Client/Webgl/SimpleWebJSLib.cs | 0 .../Client/Webgl/SimpleWebJSLib.cs.meta | 0 .../Client/Webgl/WebSocketClientWebGl.cs | 39 +- .../Client/Webgl/WebSocketClientWebGl.cs.meta | 0 .../{ => SimpleWeb}/Client/Webgl/plugin.meta | 0 .../Client/Webgl/plugin/SimpleWeb.jslib | 65 +- .../Client/Webgl/plugin/SimpleWeb.jslib.meta | 0 .../SimpleWeb/{ => SimpleWeb}/Common.meta | 0 .../{ => SimpleWeb}/Common/BufferPool.cs | 54 +- .../{ => SimpleWeb}/Common/BufferPool.cs.meta | 0 .../{ => SimpleWeb}/Common/Connection.cs | 66 +- .../{ => SimpleWeb}/Common/Connection.cs.meta | 0 .../{ => SimpleWeb}/Common/Constants.cs | 1 - .../{ => SimpleWeb}/Common/Constants.cs.meta | 0 .../{ => SimpleWeb}/Common/EventType.cs | 0 .../{ => SimpleWeb}/Common/EventType.cs.meta | 0 .../SimpleWeb/SimpleWeb/Common/Log.cs | 224 + .../{ => SimpleWeb}/Common/Log.cs.meta | 0 .../{ => SimpleWeb}/Common/Message.cs | 0 .../{ => SimpleWeb}/Common/Message.cs.meta | 0 .../Common/MessageProcessor.cs | 28 +- .../Common/MessageProcessor.cs.meta | 0 .../{ => SimpleWeb}/Common/ReadHelper.cs | 15 +- .../{ => SimpleWeb}/Common/ReadHelper.cs.meta | 0 .../{ => SimpleWeb}/Common/ReceiveLoop.cs | 43 +- .../Common/ReceiveLoop.cs.meta | 0 .../SimpleWeb/SimpleWeb/Common/Request.cs | 26 + .../SimpleWeb/Common/Request.cs.meta | 11 + .../{ => SimpleWeb}/Common/SendLoop.cs | 13 +- .../{ => SimpleWeb}/Common/SendLoop.cs.meta | 0 .../{ => SimpleWeb}/Common/TcpConfig.cs | 0 .../{ => SimpleWeb}/Common/TcpConfig.cs.meta | 0 .../SimpleWeb/{ => SimpleWeb}/Common/Utils.cs | 0 .../{ => SimpleWeb}/Common/Utils.cs.meta | 0 .../SimpleWeb/{ => SimpleWeb}/LICENSE | 0 .../SimpleWeb/{ => SimpleWeb}/LICENSE.meta | 0 .../SimpleWeb/{ => SimpleWeb}/README.txt | 0 .../SimpleWeb/{ => SimpleWeb}/README.txt.meta | 0 .../SimpleWeb/{ => SimpleWeb}/Server.meta | 0 .../{ => SimpleWeb}/Server/ServerHandshake.cs | 23 +- .../Server/ServerHandshake.cs.meta | 0 .../{ => SimpleWeb}/Server/ServerSslHelper.cs | 12 +- .../Server/ServerSslHelper.cs.meta | 0 .../{ => SimpleWeb}/Server/SimpleWebServer.cs | 36 +- .../Server/SimpleWebServer.cs.meta | 0 .../{ => SimpleWeb}/Server/WebSocketServer.cs | 61 +- .../Server/WebSocketServer.cs.meta | 0 .../{ => SimpleWeb}/SimpleWebTransport.asmdef | 4 +- .../SimpleWebTransport.asmdef.meta | 0 .../{ => SimpleWeb}/SslConfigLoader.cs | 7 +- .../{ => SimpleWeb}/SslConfigLoader.cs.meta | 0 .../SimpleWeb/SimpleWebTransport.cs | 276 +- .../Transports/Telepathy/Telepathy/Client.cs | 12 +- .../Transports/Telepathy/Telepathy/Empty.meta | 8 - .../Telepathy/Telepathy/Empty/Logger.cs | 1 - .../Telepathy/Telepathy/Empty/Logger.cs.meta | 11 - .../Telepathy/Telepathy/Empty/Message.cs | 1 - .../Telepathy/Telepathy/Empty/Message.cs.meta | 11 - .../Telepathy/Telepathy/Empty/SafeQueue.cs | 1 - .../Telepathy/Empty/SafeQueue.cs.meta | 11 - .../Telepathy/Empty/ThreadExtensions.cs | 1 - .../Telepathy/Empty/ThreadExtensions.cs.meta | 11 - .../Transports/Telepathy/Telepathy/Server.cs | 52 +- .../Telepathy/Telepathy/ThreadFunctions.cs | 12 +- .../Transports/Telepathy/Telepathy/VERSION | 3 + .../Telepathy/TelepathyTransport.cs | 68 +- Assets/Mirror/Transports/Threaded.meta | 8 + .../Transports/Threaded/ThreadedTransport.cs | 655 +++ .../Threaded/ThreadedTransport.cs.meta | 11 + Assets/Mirror/Version.txt | 2 +- Packages/manifest.json | 1 + Packages/packages-lock.json | 7 + ProjectSettings/ProjectSettings.asset | 69 +- 978 files changed, 15675 insertions(+), 50343 deletions(-) create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs.meta rename Assets/Mirror/{Core/Empty/Logging.meta => Components/LagCompensation.meta} (77%) create mode 100644 Assets/Mirror/Components/LagCompensation/HistoryCollider.cs rename Assets/Mirror/{Core/Empty/ClientScene.cs.meta => Components/LagCompensation/HistoryCollider.cs.meta} (86%) create mode 100644 Assets/Mirror/Components/LagCompensation/LagCompensator.cs rename Assets/Mirror/{Core/Empty/FallbackTransport.cs.meta => Components/LagCompensation/LagCompensator.cs.meta} (86%) create mode 100644 Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs rename Assets/Mirror/{Core/Empty/LogFilter.cs.meta => Components/NetworkDiagnosticsDebugger.cs.meta} (86%) create mode 100644 Assets/Mirror/Components/NetworkRigidbody.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs rename Assets/Mirror/{Core/Empty/Logging/NetworkHeadlessLogger.cs.meta => Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta} (86%) create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta rename Assets/Mirror/Components/{NetworkTransformReliable.meta => NetworkTransform.meta} (100%) create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransform.cs rename Assets/Mirror/Components/{NetworkTransformUnreliable => NetworkTransform}/NetworkTransform.cs.meta (100%) rename Assets/Mirror/Components/{ => NetworkTransform}/NetworkTransformBase.cs (60%) rename Assets/Mirror/{Core/Empty => Components/NetworkTransform}/NetworkTransformBase.cs.meta (86%) rename Assets/Mirror/Components/{NetworkTransformUnreliable => NetworkTransform}/NetworkTransformChild.cs (100%) rename Assets/Mirror/Components/{NetworkTransformUnreliable => NetworkTransform}/NetworkTransformChild.cs.meta (100%) rename Assets/Mirror/Components/{NetworkTransformReliable => NetworkTransform}/NetworkTransformReliable.cs (71%) rename Assets/Mirror/Components/{NetworkTransformReliable => NetworkTransform}/NetworkTransformReliable.cs.meta (100%) create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta rename Assets/Mirror/Components/{NetworkTransformUnreliable => NetworkTransform}/TransformSnapshot.cs (92%) rename Assets/Mirror/Components/{NetworkTransformUnreliable => NetworkTransform}/TransformSnapshot.cs.meta (100%) create mode 100644 Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody.meta rename Assets/Mirror/{Examples/AdditiveLevels/Materials/StartPoint.mat => Components/PredictedRigidbody/LocalGhostMaterial.mat} (83%) rename Assets/Mirror/{Examples/AdditiveLevels/Materials/CubeSphere.mat.meta => Components/PredictedRigidbody/LocalGhostMaterial.mat.meta} (79%) create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta rename Assets/Mirror/{Examples/AdditiveScenes/Materials/Zone.mat => Components/PredictedRigidbody/RemoteGhostMaterial.mat} (83%) rename Assets/Mirror/{Examples/AdditiveLevels/Materials/Ground.mat.meta => Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta} (79%) create mode 100644 Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta create mode 100644 Assets/Mirror/Core/ConnectionQuality.cs create mode 100644 Assets/Mirror/Core/ConnectionQuality.cs.meta delete mode 100644 Assets/Mirror/Core/Empty.meta delete mode 100644 Assets/Mirror/Core/Empty/ClientScene.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ApiConnector.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ApiUpdater.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Ball.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/BallManager.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/BallManager.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/BaseApi.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/BaseApi.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Events.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Events.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Extensions.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Extensions.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServer.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServer.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Logger.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Logger.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Player.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/Player.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs delete mode 100644 Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/DotNetCompatibility.cs delete mode 100644 Assets/Mirror/Core/Empty/DotNetCompatibility.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/FallbackTransport.cs delete mode 100644 Assets/Mirror/Core/Empty/LogFactory.cs delete mode 100644 Assets/Mirror/Core/Empty/LogFactory.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/LogFilter.cs delete mode 100644 Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs delete mode 100644 Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs delete mode 100644 Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Logging/LogFactory.cs delete mode 100644 Assets/Mirror/Core/Empty/Logging/LogFactory.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Logging/LogSettings.cs delete mode 100644 Assets/Mirror/Core/Empty/Logging/LogSettings.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/Logging/NetworkHeadlessLogger.cs delete mode 100644 Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs delete mode 100644 Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/NetworkMatchChecker.cs delete mode 100644 Assets/Mirror/Core/Empty/NetworkMatchChecker.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/NetworkOwnerChecker.cs delete mode 100644 Assets/Mirror/Core/Empty/NetworkOwnerChecker.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/NetworkProximityChecker.cs delete mode 100644 Assets/Mirror/Core/Empty/NetworkProximityChecker.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/NetworkSceneChecker.cs delete mode 100644 Assets/Mirror/Core/Empty/NetworkSceneChecker.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/NetworkTransformBase.cs delete mode 100644 Assets/Mirror/Core/Empty/NetworkVisibility.cs delete mode 100644 Assets/Mirror/Core/Empty/NetworkVisibility.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/StringHash.cs delete mode 100644 Assets/Mirror/Core/Empty/StringHash.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/SyncVar.cs delete mode 100644 Assets/Mirror/Core/Empty/SyncVar.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/SyncVarGameObject.cs delete mode 100644 Assets/Mirror/Core/Empty/SyncVarGameObject.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs delete mode 100644 Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs.meta delete mode 100644 Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs delete mode 100644 Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs.meta create mode 100644 Assets/Mirror/Core/InterestManagementBase.cs create mode 100644 Assets/Mirror/Core/InterestManagementBase.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation.meta create mode 100644 Assets/Mirror/Core/LagCompensation/Capture.cs create mode 100644 Assets/Mirror/Core/LagCompensation/Capture.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/HistoryBounds.cs create mode 100644 Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensation.cs create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs create mode 100644 Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta create mode 100644 Assets/Mirror/Core/PortTransport.cs create mode 100644 Assets/Mirror/Core/PortTransport.cs.meta create mode 100644 Assets/Mirror/Core/Prediction.meta create mode 100644 Assets/Mirror/Core/Prediction/Prediction.cs create mode 100644 Assets/Mirror/Core/Prediction/Prediction.cs.meta create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta rename Assets/Mirror/{Editor/Empty.meta => Core/Threading.meta} (77%) create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta create mode 100644 Assets/Mirror/Core/Threading/ConcurrentPool.cs create mode 100644 Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta create mode 100644 Assets/Mirror/Core/Threading/ThreadLog.cs create mode 100644 Assets/Mirror/Core/Threading/ThreadLog.cs.meta create mode 100644 Assets/Mirror/Core/Threading/WorkerThread.cs create mode 100644 Assets/Mirror/Core/Threading/WorkerThread.cs.meta create mode 100644 Assets/Mirror/Core/WeaverFuse.cs create mode 100644 Assets/Mirror/Core/WeaverFuse.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs delete mode 100644 Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/LogLevelWindow.cs delete mode 100644 Assets/Mirror/Editor/Empty/LogLevelWindow.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/Logging.meta delete mode 100644 Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs delete mode 100644 Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs delete mode 100644 Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs delete mode 100644 Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs delete mode 100644 Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs delete mode 100644 Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs.meta delete mode 100644 Assets/Mirror/Editor/Empty/SyncVarDrawer.cs delete mode 100644 Assets/Mirror/Editor/Empty/SyncVarDrawer.cs.meta create mode 100644 Assets/Mirror/Editor/LagCompensatorInspector.cs rename Assets/Mirror/{Core/Empty/Cloud/Ball.cs.meta => Editor/LagCompensatorInspector.cs.meta} (83%) create mode 100644 Assets/Mirror/Editor/ReadOnlyDrawer.cs rename Assets/Mirror/{Components/NetworkTransformBase.cs.meta => Editor/ReadOnlyDrawer.cs.meta} (83%) delete mode 100644 Assets/Mirror/Editor/Weaver/Empty.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/Program.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/Program.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs.meta delete mode 100644 Assets/Mirror/Examples.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/LightingData.asset delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/LightingData.asset.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/ReflectionProbe-0.exr delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/ReflectionProbe-0.exr.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/PhysicsSimulator.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/PhysicsSimulator.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Back_Tex.jpeg delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Right_Tex.jpeg delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Right_Tex.jpeg.meta delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Up_Tex.jpeg delete mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Up_Tex.jpeg.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/AnimationControllers.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/AnimationControllers/Tank.controller.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/README.md delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/README.md.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerCamera.cs delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerCamera.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs delete mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta delete mode 100644 Assets/Mirror/Examples/Basic.meta delete mode 100644 Assets/Mirror/Examples/Basic/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/Basic/Prefabs/Player.prefab delete mode 100644 Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab delete mode 100644 Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta delete mode 100644 Assets/Mirror/Examples/Basic/README.md delete mode 100644 Assets/Mirror/Examples/Basic/README.md.meta delete mode 100644 Assets/Mirror/Examples/Basic/Scenes.meta delete mode 100644 Assets/Mirror/Examples/Basic/Scenes/Example.unity delete mode 100644 Assets/Mirror/Examples/Basic/Scenes/Example.unity.meta delete mode 100644 Assets/Mirror/Examples/Basic/Scripts.meta delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/Player.cs delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs delete mode 100644 Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta delete mode 100644 Assets/Mirror/Examples/Benchmark.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Materials.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Materials/Red.mat delete mode 100644 Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Materials/White.mat delete mode 100644 Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab delete mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab delete mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Scenes.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity delete mode 100644 Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Scripts.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs delete mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs delete mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta delete mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs delete mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta delete mode 100644 Assets/Mirror/Examples/CCU.meta delete mode 100644 Assets/Mirror/Examples/CCU/CCU.unity delete mode 100644 Assets/Mirror/Examples/CCU/CCU.unity.meta delete mode 100644 Assets/Mirror/Examples/CCU/CCUNetworkManager.cs delete mode 100644 Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta delete mode 100644 Assets/Mirror/Examples/CCU/Monster.cs delete mode 100644 Assets/Mirror/Examples/CCU/Monster.cs.meta delete mode 100644 Assets/Mirror/Examples/CCU/Monster.prefab delete mode 100644 Assets/Mirror/Examples/CCU/Monster.prefab.meta delete mode 100644 Assets/Mirror/Examples/CCU/Player.cs delete mode 100644 Assets/Mirror/Examples/CCU/Player.cs.meta delete mode 100644 Assets/Mirror/Examples/CCU/Player.prefab delete mode 100644 Assets/Mirror/Examples/CCU/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/CCU/Red.mat delete mode 100644 Assets/Mirror/Examples/CCU/Red.mat.meta delete mode 100644 Assets/Mirror/Examples/CCU/White.mat delete mode 100644 Assets/Mirror/Examples/CCU/White.mat.meta delete mode 100644 Assets/Mirror/Examples/Chat.meta delete mode 100644 Assets/Mirror/Examples/Chat/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/Chat/Prefabs/Player.prefab delete mode 100644 Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scenes.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scenes/Main.unity delete mode 100644 Assets/Mirror/Examples/Chat/Scenes/Main.unity.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scripts.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/Player.cs delete mode 100644 Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta delete mode 100644 Assets/Mirror/Examples/Common.meta delete mode 100644 Assets/Mirror/Examples/Common/FPS.cs delete mode 100644 Assets/Mirror/Examples/Common/FPS.cs.meta delete mode 100644 Assets/Mirror/Examples/Discovery.meta delete mode 100644 Assets/Mirror/Examples/Discovery/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab delete mode 100644 Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/Discovery/Scenes.meta delete mode 100644 Assets/Mirror/Examples/Discovery/Scenes/Scene.unity delete mode 100644 Assets/Mirror/Examples/Discovery/Scenes/Scene.unity.meta delete mode 100644 Assets/Mirror/Examples/Mirror.Examples.asmdef delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/README.md delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerCamera.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerCamera.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs delete mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/README.md delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scenes.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchGUI.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchGUI.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchMessages.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchMessages.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchNetworkManager.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchNetworkManager.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/PlayerGUI.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/PlayerGUI.cs.meta delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/RoomGUI.cs delete mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/RoomGUI.cs.meta delete mode 100644 Assets/Mirror/Examples/Pong.meta delete mode 100644 Assets/Mirror/Examples/Pong/PhysicsMaterials.meta delete mode 100644 Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D delete mode 100644 Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D.meta delete mode 100644 Assets/Mirror/Examples/Pong/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Ball.prefab delete mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Ball.prefab.meta delete mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Racket.prefab delete mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Racket.prefab.meta delete mode 100644 Assets/Mirror/Examples/Pong/Scenes.meta delete mode 100644 Assets/Mirror/Examples/Pong/Scenes/Scene.unity delete mode 100644 Assets/Mirror/Examples/Pong/Scenes/Scene.unity.meta delete mode 100644 Assets/Mirror/Examples/Pong/Scripts.meta delete mode 100644 Assets/Mirror/Examples/Pong/Scripts/Ball.cs delete mode 100644 Assets/Mirror/Examples/Pong/Scripts/Ball.cs.meta delete mode 100644 Assets/Mirror/Examples/Pong/Scripts/NetworkManagerPong.cs delete mode 100644 Assets/Mirror/Examples/Pong/Scripts/NetworkManagerPong.cs.meta delete mode 100644 Assets/Mirror/Examples/Pong/Scripts/Player.cs delete mode 100644 Assets/Mirror/Examples/Pong/Scripts/Player.cs.meta delete mode 100644 Assets/Mirror/Examples/Pong/Sprites.meta delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/Ball.png delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/Ball.png.meta delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/DottedLine.png delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/DottedLine.png.meta delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/Racket.png delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/Racket.png.meta delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallHorizontal.png delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallHorizontal.png.meta delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallVertical.png delete mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallVertical.png.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Blue.mat delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Blue.mat.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Floor.mat delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Floor.mat.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Green.mat delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Green.mat.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Orange.mat delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Orange.mat.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Red.mat delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Red.mat.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Ball.physicMaterial delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Ball.physicMaterial.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Floor.physicMaterial delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Floor.physicMaterial.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Prefabs/Empty Player.prefab delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Prefabs/Empty Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scenes.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scenes/BounceScene.unity delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scenes/BounceScene.unity.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scripts.meta delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scripts/AddForce.cs delete mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scripts/AddForce.cs.meta delete mode 100644 Assets/Mirror/Examples/Room.meta delete mode 100644 Assets/Mirror/Examples/Room/Materials.meta delete mode 100644 Assets/Mirror/Examples/Room/Materials/PlayArea.mat delete mode 100644 Assets/Mirror/Examples/Room/Materials/PlayArea.mat.meta delete mode 100644 Assets/Mirror/Examples/Room/Materials/Player.mat delete mode 100644 Assets/Mirror/Examples/Room/Materials/Player.mat.meta delete mode 100644 Assets/Mirror/Examples/Room/Materials/Prize.mat delete mode 100644 Assets/Mirror/Examples/Room/Materials/Prize.mat.meta delete mode 100644 Assets/Mirror/Examples/Room/Materials/Textures.meta delete mode 100644 Assets/Mirror/Examples/Room/Materials/Textures/Wall01.tga delete mode 100644 Assets/Mirror/Examples/Room/Materials/Textures/Wall01.tga.meta delete mode 100644 Assets/Mirror/Examples/Room/Materials/Textures/Wall01_n.tga delete mode 100644 Assets/Mirror/Examples/Room/Materials/Textures/Wall01_n.tga.meta delete mode 100644 Assets/Mirror/Examples/Room/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/Room/Prefabs/GamePlayer.prefab delete mode 100644 Assets/Mirror/Examples/Room/Prefabs/GamePlayer.prefab.meta delete mode 100644 Assets/Mirror/Examples/Room/Prefabs/Prize.prefab delete mode 100644 Assets/Mirror/Examples/Room/Prefabs/Prize.prefab.meta delete mode 100644 Assets/Mirror/Examples/Room/Prefabs/RoomPlayer.prefab delete mode 100644 Assets/Mirror/Examples/Room/Prefabs/RoomPlayer.prefab.meta delete mode 100644 Assets/Mirror/Examples/Room/README.md delete mode 100644 Assets/Mirror/Examples/Room/README.md.meta delete mode 100644 Assets/Mirror/Examples/Room/Scenes.meta delete mode 100644 Assets/Mirror/Examples/Room/Scenes/OfflineScene.unity delete mode 100644 Assets/Mirror/Examples/Room/Scenes/OfflineScene.unity.meta delete mode 100644 Assets/Mirror/Examples/Room/Scenes/OnlineScene.unity delete mode 100644 Assets/Mirror/Examples/Room/Scenes/OnlineScene.unity.meta delete mode 100644 Assets/Mirror/Examples/Room/Scenes/OnlineSceneSettings.lighting delete mode 100644 Assets/Mirror/Examples/Room/Scenes/OnlineSceneSettings.lighting.meta delete mode 100644 Assets/Mirror/Examples/Room/Scenes/RoomScene.unity delete mode 100644 Assets/Mirror/Examples/Room/Scenes/RoomScene.unity.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomPlayerExt.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomPlayerExt.cs.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerCamera.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerCamera.cs.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerController.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerController.cs.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerScore.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerScore.cs.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/RandomColor.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/RandomColor.cs.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/Reward.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/Reward.cs.meta delete mode 100644 Assets/Mirror/Examples/Room/Scripts/Spawner.cs delete mode 100644 Assets/Mirror/Examples/Room/Scripts/Spawner.cs.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientCube.cs delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientCube.cs.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientMaterial.mat delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientMaterial.mat.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerCube.cs delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerCube.cs.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerMaterial.mat delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerMaterial.mat.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/Snapshot3D.cs delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/Snapshot3D.cs.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/SnapshotInterpolation.unity delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/SnapshotInterpolation.unity.meta delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/_DISABLE VSYNC_ delete mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/_DISABLE VSYNC_.meta delete mode 100644 Assets/Mirror/Examples/SyncDirection.meta delete mode 100644 Assets/Mirror/Examples/SyncDirection/Player.cs delete mode 100644 Assets/Mirror/Examples/SyncDirection/Player.cs.meta delete mode 100644 Assets/Mirror/Examples/SyncDirection/Player.prefab delete mode 100644 Assets/Mirror/Examples/SyncDirection/Player.prefab.meta delete mode 100644 Assets/Mirror/Examples/SyncDirection/Scene.unity delete mode 100644 Assets/Mirror/Examples/SyncDirection/Scene.unity.meta delete mode 100644 Assets/Mirror/Examples/SyncDirection/White.mat delete mode 100644 Assets/Mirror/Examples/SyncDirection/White.mat.meta delete mode 100644 Assets/Mirror/Examples/Tanks.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Metallic.png delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Metallic.png.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Normal.png delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Normal.png.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx delete mode 100644 Assets/Mirror/Examples/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Prefabs.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Projectile.prefab delete mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Projectile.prefab.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Tank.prefab delete mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Tank.prefab.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes/Scene.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes/Scene.unity delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes/Scene.unity.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes/Scene/NavMesh.asset delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes/Scene/NavMesh.asset.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes/SceneSettings.lighting delete mode 100644 Assets/Mirror/Examples/Tanks/Scenes/SceneSettings.lighting.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scripts.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scripts/FaceCamera.cs delete mode 100644 Assets/Mirror/Examples/Tanks/Scripts/FaceCamera.cs.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Projectile.cs delete mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Projectile.cs.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Tank.cs delete mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Tank.cs.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Textures.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt Hand Painted Texture - License.txt delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt Hand Painted Texture - License.txt.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt.mat delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt.mat.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png.meta delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/ProjectileMaterial.mat delete mode 100644 Assets/Mirror/Examples/Tanks/Textures/ProjectileMaterial.mat.meta rename Assets/Mirror/{Core/Empty/Cloud.meta => Plugins/BouncyCastle.meta} (77%) create mode 100644 Assets/Mirror/Plugins/BouncyCastle/BouncyCastle.Cryptography.dll create mode 100644 Assets/Mirror/Plugins/BouncyCastle/BouncyCastle.Cryptography.dll.meta create mode 100644 Assets/Mirror/Plugins/BouncyCastle/LICENSE.md rename Assets/Mirror/{Examples/AdditiveLevels/ReadMe.txt.meta => Plugins/BouncyCastle/LICENSE.md.meta} (75%) rename Assets/Mirror/{Components/NetworkTransformUnreliable.meta => Presets.meta} (77%) create mode 100644 Assets/Mirror/Presets/NetworkTransform.meta create mode 100644 Assets/Mirror/Presets/NetworkTransform/ClientAuth-Balanced.preset rename Assets/Mirror/{Examples/AdditiveLevels/Materials/Player.mat.meta => Presets/NetworkTransform/ClientAuth-Balanced.preset.meta} (60%) create mode 100644 Assets/Mirror/Presets/NetworkTransform/ClientAuth-FastPaced.preset rename Assets/Mirror/{Examples/AdditiveLevels/Materials/Portal.mat.meta => Presets/NetworkTransform/ClientAuth-FastPaced.preset.meta} (60%) create mode 100644 Assets/Mirror/Presets/NetworkTransform/ClientAuth-VeryCasual.preset create mode 100644 Assets/Mirror/Presets/NetworkTransform/ClientAuth-VeryCasual.preset.meta create mode 100644 Assets/Mirror/Transports/Edgegap.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/EdgegapLobbyKcpTransport.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/EdgegapLobbyKcpTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyApi.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyApi.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyServiceCreateDialogue.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyServiceCreateDialogue.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyTransportInspector.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyTransportInspector.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/ListLobbiesResponse.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/ListLobbiesResponse.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/Lobby.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/Lobby.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyBrief.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyBrief.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyCreateRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyCreateRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyIdRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyIdRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyJoinOrLeaveRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyJoinOrLeaveRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyUpdateRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyUpdateRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpClient.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpClient.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpServer.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpServer.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpTransport.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/Protocol.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/Protocol.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/README.md rename Assets/Mirror/{Examples/MultipleMatches => Transports/Edgegap/EdgegapRelay}/README.md.meta (75%) create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/RelayCredentialsFromArgs.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/RelayCredentialsFromArgs.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/edgegap.png rename Assets/Mirror/{Examples/AdditiveLevels/Textures/Back_Tex.jpeg.meta => Transports/Edgegap/edgegap.png.meta} (63%) create mode 100644 Assets/Mirror/Transports/Encryption.meta create mode 100644 Assets/Mirror/Transports/Encryption/Editor.meta rename Assets/Mirror/Transports/{Middleware/MiddlewareTransport.asmdef => Encryption/Editor/EncryptionTransportEditor.asmdef} (67%) rename Assets/Mirror/{Examples/Mirror.Examples.asmdef.meta => Transports/Encryption/Editor/EncryptionTransportEditor.asmdef.meta} (76%) create mode 100644 Assets/Mirror/Transports/Encryption/Editor/EncryptionTransportInspector.cs create mode 100644 Assets/Mirror/Transports/Encryption/Editor/EncryptionTransportInspector.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/EncryptedConnection.cs create mode 100644 Assets/Mirror/Transports/Encryption/EncryptedConnection.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionCredentials.cs create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionCredentials.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionTransport.cs create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/PubKeyInfo.cs create mode 100644 Assets/Mirror/Transports/Encryption/PubKeyInfo.cs.meta rename Assets/Mirror/Transports/KCP/{MirrorTransport => }/KcpTransport.cs (76%) rename Assets/Mirror/Transports/KCP/{MirrorTransport => }/KcpTransport.cs.meta (100%) delete mode 100644 Assets/Mirror/Transports/KCP/MirrorTransport.meta create mode 100644 Assets/Mirror/Transports/KCP/ThreadedKcpTransport.cs create mode 100644 Assets/Mirror/Transports/KCP/ThreadedKcpTransport.cs.meta delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpClientConnection.cs delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpClientConnection.cs.meta delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpClientConnectionNonAlloc.cs delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpClientConnectionNonAlloc.cs.meta delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpClientNonAlloc.cs delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpClientNonAlloc.cs.meta delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpServerConnectionNonAlloc.cs delete mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpServerConnectionNonAlloc.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpState.cs rename Assets/Mirror/{Core/Empty/Cloud/ApiConnector.cs.meta => Transports/KCP/kcp2k/highlevel/KcpState.cs.meta} (83%) create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/AckItem.cs rename Assets/Mirror/{Core/Empty/Cloud/ApiUpdater.cs.meta => Transports/KCP/kcp2k/kcp/AckItem.cs.meta} (83%) delete mode 100644 Assets/Mirror/Transports/Middleware/MiddlewareTransport.asmdef.meta delete mode 100644 Assets/Mirror/Transports/Multiplex/MultiplexTransport.asmdef delete mode 100644 Assets/Mirror/Transports/Multiplex/MultiplexTransport.asmdef.meta delete mode 100644 Assets/Mirror/Transports/SimpleWeb/Common/Log.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/Editor.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/Editor/ClientWebsocketSettingsDrawer.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/Editor/ClientWebsocketSettingsDrawer.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb.meta rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/AssemblyInfo.cs (84%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/AssemblyInfo.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/CHANGELOG.md (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/CHANGELOG.md.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client.meta (100%) create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/ClientWebsocketSettings.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/ClientWebsocketSettings.cs.meta rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/SimpleWebClient.cs (95%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/SimpleWebClient.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/StandAlone.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/StandAlone/ClientHandshake.cs (76%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/StandAlone/ClientHandshake.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/StandAlone/ClientSslHelper.cs (92%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/StandAlone/ClientSslHelper.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/StandAlone/WebSocketClientStandAlone.cs (91%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/StandAlone/WebSocketClientStandAlone.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl/SimpleWebJSLib.cs (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl/SimpleWebJSLib.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl/WebSocketClientWebGl.cs (91%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl/WebSocketClientWebGl.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl/plugin.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl/plugin/SimpleWeb.jslib (76%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Client/Webgl/plugin/SimpleWeb.jslib.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/BufferPool.cs (80%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/BufferPool.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Connection.cs (54%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Connection.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Constants.cs (99%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Constants.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/EventType.cs (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/EventType.cs.meta (100%) create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Log.cs rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Log.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Message.cs (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Message.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/MessageProcessor.cs (92%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/MessageProcessor.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/ReadHelper.cs (91%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/ReadHelper.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/ReceiveLoop.cs (86%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/ReceiveLoop.cs.meta (100%) create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Request.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Request.cs.meta rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/SendLoop.cs (94%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/SendLoop.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/TcpConfig.cs (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/TcpConfig.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Utils.cs (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Common/Utils.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/LICENSE (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/LICENSE.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/README.txt (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/README.txt.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/ServerHandshake.cs (80%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/ServerHandshake.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/ServerSslHelper.cs (83%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/ServerSslHelper.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/SimpleWebServer.cs (88%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/SimpleWebServer.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/WebSocketServer.cs (75%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/Server/WebSocketServer.cs.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/SimpleWebTransport.asmdef (81%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/SimpleWebTransport.asmdef.meta (100%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/SslConfigLoader.cs (93%) rename Assets/Mirror/Transports/SimpleWeb/{ => SimpleWeb}/SslConfigLoader.cs.meta (100%) delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty.meta delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/Logger.cs delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/Logger.cs.meta delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/Message.cs delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/Message.cs.meta delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/SafeQueue.cs delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/SafeQueue.cs.meta delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/ThreadExtensions.cs delete mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Empty/ThreadExtensions.cs.meta create mode 100644 Assets/Mirror/Transports/Threaded.meta create mode 100644 Assets/Mirror/Transports/Threaded/ThreadedTransport.cs create mode 100644 Assets/Mirror/Transports/Threaded/ThreadedTransport.cs.meta diff --git a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs index cb2b01f..79775a7 100644 --- a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs +++ b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs @@ -11,21 +11,25 @@ static class PreprocessorDefine [InitializeOnLoadMethod] public static void AddDefineSymbols() { +#if UNITY_2021_2_OR_NEWER + string currentDefines = PlayerSettings.GetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup)); +#else + // Deprecated in Unity 2023.1 string currentDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); +#endif + // Remove oldest when adding next month's symbol. + // Keep a rolling 12 months of symbols. HashSet defines = new HashSet(currentDefines.Split(';')) { "MIRROR", - "MIRROR_57_0_OR_NEWER", - "MIRROR_58_0_OR_NEWER", - "MIRROR_65_0_OR_NEWER", - "MIRROR_66_0_OR_NEWER", - "MIRROR_2022_9_OR_NEWER", - "MIRROR_2022_10_OR_NEWER", - "MIRROR_70_0_OR_NEWER", - "MIRROR_71_0_OR_NEWER", - "MIRROR_73_OR_NEWER" - // Remove oldest when adding next month's symbol. - // Keep a rolling 12 months of symbols. + "MIRROR_79_OR_NEWER", + "MIRROR_81_OR_NEWER", + "MIRROR_82_OR_NEWER", + "MIRROR_83_OR_NEWER", + "MIRROR_84_OR_NEWER", + "MIRROR_85_OR_NEWER", + "MIRROR_86_OR_NEWER", + "MIRROR_89_OR_NEWER" }; // only touch PlayerSettings if we actually modified it, @@ -33,7 +37,12 @@ public static void AddDefineSymbols() string newDefines = string.Join(";", defines); if (newDefines != currentDefines) { +#if UNITY_2021_2_OR_NEWER + PlayerSettings.SetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup), newDefines); +#else + // Deprecated in Unity 2023.1 PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newDefines); +#endif } } } diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs index cc9f116..5fa9397 100644 --- a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs +++ b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs @@ -6,7 +6,7 @@ namespace Mirror.Discovery { [Serializable] - public class ServerFoundUnityEvent : UnityEvent {}; + public class ServerFoundUnityEvent : UnityEvent {}; [DisallowMultipleComponent] [AddComponentMenu("Network/Network Discovery")] @@ -14,27 +14,6 @@ public class NetworkDiscovery : NetworkDiscoveryBase /// Process the request from a client /// @@ -68,9 +47,11 @@ protected override ServerResponse ProcessRequest(ServerRequest request, IPEndPoi throw; } } + #endregion #region Client + /// /// Create a message that will be broadcasted on the network to discover servers /// @@ -106,6 +87,7 @@ protected override void ProcessResponse(ServerResponse response, IPEndPoint endp OnServerFound.Invoke(response); } + #endregion } } diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs index de74fbd..4417344 100644 --- a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs @@ -23,33 +23,46 @@ public abstract class NetworkDiscoveryBase : MonoBehaviour { 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("If true, broadcasts a discovery request every ActiveDiscoveryInterval seconds")] + public bool enableActiveDiscovery = true; + + // broadcast address needs to be configurable on iOS: + // https://github.com/vis2k/Mirror/pull/3255 + [Tooltip("iOS may require LAN IP address here (e.g. 192.168.x.x), otherwise leave blank.")] + public string BroadcastAddress = ""; [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; - - // broadcast address needs to be configurable on iOS: - // https://github.com/vis2k/Mirror/pull/3255 - public string BroadcastAddress = ""; + + [Tooltip("Transport to be advertised during discovery")] + public Transport transport; + + [Tooltip("Invoked when a server is found")] + public ServerFoundUnityEvent OnServerFound; + + // 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; + + public long ServerId { get; private set; } protected UdpClient serverUdpClient; protected UdpClient clientUdpClient; #if UNITY_EDITOR - void OnValidate() + public virtual void OnValidate() { + if (transport == null) + transport = GetComponent(); + if (secretHandshake == 0) { secretHandshake = RandomLong(); @@ -58,22 +71,31 @@ void OnValidate() } #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() { + ServerId = RandomLong(); + + // active transport gets initialized in Awake + // so make sure we set it here in Start() after Awake + // Or just let the user assign it in the inspector + if (transport == null) + transport = Transport.active; + // Server mode? then start advertising -#if UNITY_SERVER - AdvertiseServer(); -#endif + if (Utils.IsHeadless()) + { + AdvertiseServer(); + } + } + + 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); } // Ensure the ports are cleared no matter when Game/Unity UI exits @@ -166,9 +188,7 @@ public async Task ServerListenAsync() // socket has been closed break; } - catch (Exception) - { - } + catch (Exception) {} } } @@ -247,11 +267,12 @@ protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint AndroidJavaObject multicastLock; bool hasMulticastLock; #endif + void BeginMulticastLock() { #if UNITY_ANDROID if (hasMulticastLock) return; - + if (Application.platform == RuntimePlatform.Android) { using (AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic("currentActivity")) @@ -271,7 +292,7 @@ void EndpMulticastLock() { #if UNITY_ANDROID if (!hasMulticastLock) return; - + multicastLock?.Call("release"); hasMulticastLock = false; #endif @@ -328,16 +349,16 @@ public void StopDiscovery() /// ClientListenAsync Task public async Task ClientListenAsync() { - // while clientUpdClient to fix: + // while clientUpdClient to fix: // https://github.com/vis2k/Mirror/pull/2908 // // If, you cancel discovery the clientUdpClient is set to null. // However, nothing cancels ClientListenAsync. If we change the if(true) - // to check if the client is null. You can properly cancel the discovery, + // to check if the client is null. You can properly cancel the discovery, // and kill the listen thread. // - // Prior to this fix, if you cancel the discovery search. It crashes the - // thread, and is super noisy in the output. As well as causes issues on + // Prior to this fix, if you cancel the discovery search. It crashes the + // thread, and is super noisy in the output. As well as causes issues on // the quest. while (clientUdpClient != null) { @@ -372,7 +393,7 @@ public void BroadcastDiscoveryRequest() } IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, serverBroadcastListenPort); - + if (!string.IsNullOrWhiteSpace(BroadcastAddress)) { try diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta index 7dfbaf6..fecf845 100644 --- a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta @@ -5,7 +5,7 @@ MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta b/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta index 84f3232..a7e246c 100644 --- a/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta +++ b/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta @@ -5,7 +5,7 @@ MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta b/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta index 44f23ba..239b218 100644 --- a/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta +++ b/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta @@ -5,7 +5,7 @@ MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs index d9f3042..f3be8c8 100644 --- a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs +++ b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs @@ -1,9 +1,11 @@ +using System; using UnityEngine; namespace Mirror.Experimental { - [AddComponentMenu("Network/ Experimental/Network Lerp Rigidbody")] + [AddComponentMenu("")] [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-lerp-rigidbody")] + [Obsolete("Use the new NetworkRigidbodyReliable/Unreliable component with Snapshot Interpolation instead.")] public class NetworkLerpRigidbody : NetworkBehaviour { [Header("Settings")] @@ -33,10 +35,18 @@ public class NetworkLerpRigidbody : NetworkBehaviour bool ClientWithAuthority => clientAuthority && isOwned; - void OnValidate() + protected override void OnValidate() + { + base.OnValidate(); + Reset(); + } + + public virtual void Reset() { if (target == null) target = GetComponent(); + + syncDirection = SyncDirection.ClientToServer; } void Update() diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs index 660adc5..e99f6ed 100644 --- a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs +++ b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs @@ -1,9 +1,11 @@ +using System; using UnityEngine; namespace Mirror.Experimental { - [AddComponentMenu("Network/ Experimental/Network Rigidbody")] + [AddComponentMenu("")] [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-rigidbody")] + [Obsolete("Use the new NetworkRigidbodyReliable/Unreliable component with Snapshot Interpolation instead.")] public class NetworkRigidbody : NetworkBehaviour { [Header("Settings")] @@ -37,10 +39,18 @@ public class NetworkRigidbody : NetworkBehaviour /// readonly ClientSyncState previousValue = new ClientSyncState(); - void OnValidate() + protected override void OnValidate() + { + base.OnValidate(); + Reset(); + } + + public virtual void Reset() { if (target == null) target = GetComponent(); + + syncDirection = SyncDirection.ClientToServer; } #region Sync vars diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs index 5a2c340..3209dfe 100644 --- a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs +++ b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs @@ -1,9 +1,11 @@ +using System; using UnityEngine; namespace Mirror.Experimental { - [AddComponentMenu("Network/ Experimental/Network Rigidbody 2D")] + [AddComponentMenu("")] [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-rigidbody")] + [Obsolete("Use the new NetworkRigidbodyReliable/Unreliable 2D component with Snapshot Interpolation instead.")] public class NetworkRigidbody2D : NetworkBehaviour { [Header("Settings")] @@ -37,10 +39,18 @@ public class NetworkRigidbody2D : NetworkBehaviour /// readonly ClientSyncState previousValue = new ClientSyncState(); - void OnValidate() + protected override void OnValidate() + { + base.OnValidate(); + Reset(); + } + + public virtual void Reset() { if (target == null) target = GetComponent(); + + syncDirection = SyncDirection.ClientToServer; } #region Sync vars diff --git a/Assets/Mirror/Components/GUIConsole.cs b/Assets/Mirror/Components/GUIConsole.cs index c6acbb8..7055fe1 100644 --- a/Assets/Mirror/Components/GUIConsole.cs +++ b/Assets/Mirror/Components/GUIConsole.cs @@ -31,27 +31,38 @@ public LogEntry(string message, LogType type) public class GUIConsole : MonoBehaviour { - public int height = 150; + public int height = 80; + public int offsetY = 40; // only keep the recent 'n' entries. otherwise memory would grow forever // and drawing would get slower and slower. public int maxLogCount = 50; + // Unity Editor has the Console window, we don't need to show it there. + // unless for testing, so keep it as option. + public bool showInEditor = false; + // log as queue so we can remove the first entry easily - Queue log = new Queue(); + readonly 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; + // Default is BackQuote, because F keys are already assigned in browsers + [Tooltip("Hotkey to show/hide the console at runtime\nBack Quote is usually on the left above Tab\nChange with caution - F keys are generally already taken in Browsers")] + public KeyCode hotKey = KeyCode.BackQuote; // GUI bool visible; Vector2 scroll = Vector2.zero; + // only show at runtime, or if showInEditor is enabled + bool show => !Application.isEditor || showInEditor; + void Awake() { - Application.logMessageReceived += OnLog; + // only show at runtime, or if showInEditor is enabled + if (show) + Application.logMessageReceived += OnLog; } // OnLog logs everything, even Debug.Log messages in release builds @@ -90,7 +101,7 @@ void OnLog(string message, string stackTrace, LogType type) void Update() { - if (Input.GetKeyDown(hotKey)) + if (show && Input.GetKeyDown(hotKey)) visible = !visible; } @@ -98,7 +109,12 @@ void OnGUI() { if (!visible) return; - scroll = GUILayout.BeginScrollView(scroll, "Box", GUILayout.Width(Screen.width), GUILayout.Height(height)); + // If this offset is changed, also change width in NetworkManagerHUD::OnGUI + int offsetX = 300 + 20; + + GUILayout.BeginArea(new Rect(offsetX, offsetY, Screen.width - offsetX - 10, height)); + + scroll = GUILayout.BeginScrollView(scroll, "Box", GUILayout.Width(Screen.width - offsetX - 10), GUILayout.Height(height)); foreach (LogEntry entry in log) { if (entry.type == LogType.Error || entry.type == LogType.Exception) @@ -110,6 +126,8 @@ void OnGUI() GUI.color = Color.white; } GUILayout.EndScrollView(); + + GUILayout.EndArea(); } } } diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs index 0441558..6549961 100644 --- a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs @@ -25,7 +25,7 @@ int GetVisRange(NetworkIdentity identity) } [ServerCallback] - public override void Reset() + public override void ResetState() { lastRebuildTime = 0D; CustomRanges.Clear(); diff --git a/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs index 71238d2..d741d0c 100644 --- a/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs +++ b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs @@ -7,124 +7,119 @@ namespace Mirror [AddComponentMenu("Network/ Interest Management/ Match/Match Interest Management")] public class MatchInterestManagement : InterestManagement { - readonly Dictionary> matchObjects = - new Dictionary>(); + [Header("Diagnostics")] + [ReadOnly, SerializeField] + internal ushort matchCount; - readonly Dictionary lastObjectMatch = - new Dictionary(); + readonly Dictionary> matchObjects = + new Dictionary>(); readonly HashSet dirtyMatches = new HashSet(); + // LateUpdate so that all spawns/despawns/changes are done [ServerCallback] - public override void OnSpawned(NetworkIdentity identity) + void LateUpdate() { - if (!identity.TryGetComponent(out NetworkMatch networkMatch)) - return; - - Guid networkMatchId = networkMatch.matchId; - lastObjectMatch[identity] = networkMatchId; - - // Guid.Empty is never a valid matchId...do not add to matchObjects collection - if (networkMatchId == Guid.Empty) - return; - - // Debug.Log($"MatchInterestManagement.OnSpawned({identity.name}) currentMatch: {currentMatch}"); - if (!matchObjects.TryGetValue(networkMatchId, out HashSet objects)) + // Rebuild all dirty matches + // dirtyMatches will be empty if no matches changed members + // by spawning or destroying or changing matchId in this frame. + foreach (Guid dirtyMatch in dirtyMatches) { - objects = new HashSet(); - matchObjects.Add(networkMatchId, objects); + // rebuild always, even if matchObjects[dirtyMatch] is empty. + // Players might have left the match, but they may still be spawned. + RebuildMatchObservers(dirtyMatch); + + // clean up empty entries in the dict + if (matchObjects[dirtyMatch].Count == 0) + matchObjects.Remove(dirtyMatch); } - objects.Add(identity); + dirtyMatches.Clear(); - // Match ID could have been set in NetworkBehaviour::OnStartServer on this object. - // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here. - RebuildMatchObservers(networkMatchId); + matchCount = (ushort)matchObjects.Count; } [ServerCallback] - public override void OnDestroyed(NetworkIdentity identity) + void RebuildMatchObservers(Guid matchId) { - if (lastObjectMatch.TryGetValue(identity, out Guid currentMatch)) - { - lastObjectMatch.Remove(identity); - if (currentMatch != Guid.Empty && matchObjects.TryGetValue(currentMatch, out HashSet objects) && objects.Remove(identity)) - RebuildMatchObservers(currentMatch); - } + foreach (NetworkMatch networkMatch in matchObjects[matchId]) + if (networkMatch.netIdentity != null) + NetworkServer.RebuildObservers(networkMatch.netIdentity, false); } - // internal so we can update from tests + // called by NetworkMatch.matchId setter [ServerCallback] - internal void Update() + internal void OnMatchChanged(NetworkMatch networkMatch, Guid oldMatch) { - // for each spawned: - // if match changed: - // add previous to dirty - // add new to dirty - foreach (NetworkIdentity identity in NetworkServer.spawned.Values) - { - // Ignore objects that don't have a NetworkMatch component - if (!identity.TryGetComponent(out NetworkMatch networkMatch)) - continue; + // This object is in a new match so observers in the prior match + // and the new match need to rebuild their respective observers lists. - Guid newMatch = networkMatch.matchId; - if (!lastObjectMatch.TryGetValue(identity, out Guid currentMatch)) - continue; - - // Guid.Empty is never a valid matchId - // Nothing to do if matchId hasn't changed - if (newMatch == Guid.Empty || newMatch == currentMatch) - continue; + // Remove this object from the hashset of the match it just left + // Guid.Empty is never a valid matchId + if (oldMatch != Guid.Empty) + { + dirtyMatches.Add(oldMatch); + matchObjects[oldMatch].Remove(networkMatch); + } - // Mark new/old matches as dirty so they get rebuilt - UpdateDirtyMatches(newMatch, currentMatch); + // Guid.Empty is never a valid matchId + if (networkMatch.matchId == Guid.Empty) + 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. - UpdateMatchObjects(identity, newMatch, currentMatch); - } + dirtyMatches.Add(networkMatch.matchId); - // rebuild all dirty matches - foreach (Guid dirtyMatch in dirtyMatches) - RebuildMatchObservers(dirtyMatch); + // Make sure this new match is in the dictionary + if (!matchObjects.ContainsKey(networkMatch.matchId)) + matchObjects[networkMatch.matchId] = new HashSet(); - dirtyMatches.Clear(); + // Add this object to the hashset of the new match + matchObjects[networkMatch.matchId].Add(networkMatch); } - void UpdateDirtyMatches(Guid newMatch, Guid currentMatch) + [ServerCallback] + public override void OnSpawned(NetworkIdentity identity) { - // Guid.Empty is never a valid matchId - if (currentMatch != Guid.Empty) - dirtyMatches.Add(currentMatch); + if (!identity.TryGetComponent(out NetworkMatch networkMatch)) + return; - dirtyMatches.Add(newMatch); - } + Guid networkMatchId = networkMatch.matchId; - void UpdateMatchObjects(NetworkIdentity netIdentity, Guid newMatch, Guid currentMatch) - { - // 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); + // Guid.Empty is never a valid matchId...do not add to matchObjects collection + if (networkMatchId == Guid.Empty) + return; - // Set this to the new match this object just entered - lastObjectMatch[netIdentity] = newMatch; + // Debug.Log($"MatchInterestManagement.OnSpawned({identity.name}) currentMatch: {currentMatch}"); + if (!matchObjects.TryGetValue(networkMatchId, out HashSet objects)) + { + objects = new HashSet(); + matchObjects.Add(networkMatchId, objects); + } - // Make sure this new match is in the dictionary - if (!matchObjects.ContainsKey(newMatch)) - matchObjects.Add(newMatch, new HashSet()); + objects.Add(networkMatch); - // Add this object to the hashset of the new match - matchObjects[newMatch].Add(netIdentity); + // Match ID could have been set in NetworkBehaviour::OnStartServer on this object. + // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here. + // Add the current match to dirtyMatches for LateUpdate to rebuild it. + dirtyMatches.Add(networkMatchId); } - void RebuildMatchObservers(Guid matchId) + [ServerCallback] + public override void OnDestroyed(NetworkIdentity identity) { - foreach (NetworkIdentity netIdentity in matchObjects[matchId]) - if (netIdentity != null) - NetworkServer.RebuildObservers(netIdentity, false); + // Don't RebuildSceneObservers here - that will happen in LateUpdate. + // Multiple objects could be destroyed in same frame and we don't + // want to rebuild for each one...let LateUpdate do it once. + // We must add the current match to dirtyMatches for LateUpdate to rebuild it. + if (identity.TryGetComponent(out NetworkMatch currentMatch)) + { + if (currentMatch.matchId != Guid.Empty && + matchObjects.TryGetValue(currentMatch.matchId, out HashSet objects) && + objects.Remove(currentMatch)) + dirtyMatches.Add(currentMatch.matchId); + } } + [ServerCallback] public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) { // Never observed if no NetworkMatch component @@ -146,24 +141,24 @@ public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnection return identityNetworkMatch.matchId == newObserverNetworkMatch.matchId; } + [ServerCallback] public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) { if (!identity.TryGetComponent(out NetworkMatch networkMatch)) return; - Guid matchId = networkMatch.matchId; - // Guid.Empty is never a valid matchId - if (matchId == Guid.Empty) + if (networkMatch.matchId == Guid.Empty) return; - if (!matchObjects.TryGetValue(matchId, out HashSet objects)) + // Abort if this match hasn't been created yet by OnSpawned or OnMatchChanged + if (!matchObjects.TryGetValue(networkMatch.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); + foreach (NetworkMatch netMatch in objects) + if (netMatch.netIdentity != null && netMatch.netIdentity.connectionToClient != null) + newObservers.Add(netMatch.netIdentity.connectionToClient); } } } diff --git a/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs b/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs index f6689f2..0d55fd0 100644 --- a/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs +++ b/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs @@ -9,7 +9,34 @@ namespace Mirror [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] public class NetworkMatch : NetworkBehaviour { + Guid _matchId; + +#pragma warning disable IDE0052 // Suppress warning for unused field...this is for debugging purposes + [SerializeField, ReadOnly] + [Tooltip("Match ID is shown here on server for debugging purposes.")] + string MatchID = string.Empty; +#pragma warning restore IDE0052 + ///Set this to the same value on all networked objects that belong to a given match - public Guid matchId; + public Guid matchId + { + get => _matchId; + set + { + if (!NetworkServer.active) + throw new InvalidOperationException("matchId can only be set at runtime on active server"); + + if (_matchId == value) + return; + + Guid oldMatch = _matchId; + _matchId = value; + MatchID = value.ToString(); + + // Only inform the AOI if this netIdentity has been spawned (isServer) and only if using a MatchInterestManagement + if (isServer && NetworkServer.aoi is MatchInterestManagement matchInterestManagement) + matchInterestManagement.OnMatchChanged(this, oldMatch); + } + } } } diff --git a/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs index cc4c1b4..28e5eba 100644 --- a/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs +++ b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs @@ -35,11 +35,15 @@ public override void OnSpawned(NetworkIdentity identity) [ServerCallback] public override void OnDestroyed(NetworkIdentity identity) { + // Don't RebuildSceneObservers here - that will happen in Update. + // Multiple objects could be destroyed in same frame and we don't + // want to rebuild for each one...let Update do it once. + // We must add the current scene to dirtyScenes for Update to rebuild it. if (lastObjectScene.TryGetValue(identity, out Scene currentScene)) { lastObjectScene.Remove(identity); if (sceneObjects.TryGetValue(currentScene, out HashSet objects) && objects.Remove(identity)) - RebuildSceneObservers(currentScene); + dirtyScenes.Add(currentScene); } } diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs new file mode 100644 index 0000000..64ca497 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs @@ -0,0 +1,106 @@ +// Grid3D based on Grid2D +// -> not named 'Grid' because Unity already has a Grid type. causes warnings. +// -> struct to avoid memory indirection. it's accessed a lot. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // struct to avoid memory indirection. it's accessed a lot. + public struct Grid3D + { + // 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! + readonly Dictionary> grid; + + // cache a 9 x 3 neighbor grid of vector3 offsets so we can use them more easily + readonly Vector3Int[] neighbourOffsets; + + public Grid3D(int initialCapacity) + { + grid = new Dictionary>(initialCapacity); + + neighbourOffsets = new Vector3Int[9 * 3]; + int i = 0; + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + for (int z = -1; z <= 1; z++) + { + neighbourOffsets[i] = new Vector3Int(x, y, z); + i += 1; + } + } + } + } + + // helper function so we can add an entry without worrying + public void Add(Vector3Int position, T value) + { + // initialize set in grid if it's not in there yet + if (!grid.TryGetValue(position, out HashSet hashSet)) + { + // each grid entry may hold hundreds of entities. + // let's create the HashSet with a large initial capacity + // in order to avoid resizing & allocations. +#if !UNITY_2021_3_OR_NEWER + // Unity 2019 doesn't have "new HashSet(capacity)" yet + hashSet = new HashSet(); +#else + hashSet = new HashSet(128); +#endif + 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(Vector3Int 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(Vector3Int position, HashSet result) + { + // clear result first + result.Clear(); + + // add neighbours + foreach (Vector3Int 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/Grid3D.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs.meta new file mode 100644 index 0000000..f4c2021 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b157c08313c64752b0856469b1b70771 +timeCreated: 1713533175 \ No newline at end of file diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs new file mode 100644 index 0000000..1953de7 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs @@ -0,0 +1,146 @@ +// extremely fast spatial hashing interest management based on uMMORPG GridChecker. +// => 30x faster in initial tests +// => scales way higher +// checks on three dimensions (XYZ) which includes the vertical axes. +// this is slower than XY checking for regular spatial hashing. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Spatial Hash/Spatial Hashing Interest Management")] + public class SpatialHashing3DInterestManagement : InterestManagement + { + [Tooltip("The maximum range that objects will be visible at.")] + public int visRange = 30; + + // we use a 9 neighbour grid. + // so we always see in a distance of 2 grids. + // for example, our own grid and then one on top / below / left / right. + // + // this means that grid resolution needs to be distance / 2. + // so for example, for distance = 30 we see 2 cells = 15 * 2 distance. + // + // on first sight, it seems we need distance / 3 (we see left/us/right). + // but that's not the case. + // resolution would be 10, and we only see 1 cell far, so 10+10=20. + public int resolution => visRange / 2; // same as XY because if XY is rotated 90 degree for 3D, it's still the same distance + + [Tooltip("Rebuild all every 'rebuildInterval' seconds.")] + public float rebuildInterval = 1; + double lastRebuildTime; + + [Header("Debug Settings")] + public bool showSlider; + + // the grid + // begin with a large capacity to avoid resizing & allocations. + Grid3D grid = new Grid3D(1024); + + // project 3d world position to grid position + Vector3Int ProjectToGrid(Vector3 position) => + Vector3Int.RoundToInt(position / resolution); + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // calculate projected positions + Vector3Int projected = ProjectToGrid(identity.transform.position); + Vector3Int 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; // same as XY because if XY is rotated 90 degree for 3D, it's still the same distance + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // add everyone in 9 neighbour grid + // -> pass observers to GetWithNeighbours directly to avoid allocations + // and expensive .UnionWith computations. + Vector3Int current = ProjectToGrid(identity.transform.position); + grid.GetWithNeighbours(current, newObservers); + } + + [ServerCallback] + public override void ResetState() + { + lastRebuildTime = 0D; + } + + // update everyone's position in the grid + // (internal so we can update from tests) + [ServerCallback] + internal void Update() + { + // 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 + Vector3Int 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/SpatialHashing3DInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs.meta new file mode 100644 index 0000000..b6a218b --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 120b4d6121d94e0280cd2ec536b0ea8f +timeCreated: 1713534045 \ No newline at end of file diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs index 2986034..0cb5e23 100644 --- a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs @@ -1,6 +1,8 @@ // extremely fast spatial hashing interest management based on uMMORPG GridChecker. // => 30x faster in initial tests // => scales way higher +// checks on two dimensions only(!), for example: XZ for 3D games or XY for 2D games. +// this is faster than XYZ checking but doesn't check vertical distance. using System.Collections.Generic; using UnityEngine; @@ -36,7 +38,7 @@ public enum CheckMethod [Tooltip("Spatial Hashing supports 3D (XZ) and 2D (XY) games.")] public CheckMethod checkMethod = CheckMethod.XZ_FOR_3D; - // debugging + [Header("Debug Settings")] public bool showSlider; // the grid @@ -72,7 +74,7 @@ public override void OnRebuildObservers(NetworkIdentity identity, HashSet _teamId; + set + { + if (Application.IsPlaying(gameObject) && !NetworkServer.active) + throw new InvalidOperationException("teamId can only be set at runtime on active server"); + + if (_teamId == value) + return; + + string oldTeam = _teamId; + _teamId = value; + + //Only inform the AOI if this netIdentity has been spawned(isServer) and only if using a TeamInterestManagement + if (isServer && NetworkServer.aoi is TeamInterestManagement teamInterestManagement) + teamInterestManagement.OnTeamChanged(this, oldTeam); + } + } [Tooltip("When enabled this object is visible to all clients. Typically this would be true for player objects")] - [SyncVar] public bool forceShown; + public bool forceShown; } } diff --git a/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs index b543586..cb5bdb7 100644 --- a/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs +++ b/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using UnityEngine; namespace Mirror @@ -6,119 +6,110 @@ namespace Mirror [AddComponentMenu("Network/ Interest Management/ Team/Team Interest Management")] public class TeamInterestManagement : InterestManagement { - readonly Dictionary> teamObjects = new Dictionary>(); - readonly Dictionary lastObjectTeam = new Dictionary(); + readonly Dictionary> teamObjects = + new Dictionary>(); + readonly HashSet dirtyTeams = new HashSet(); + // LateUpdate so that all spawns/despawns/changes are done [ServerCallback] - public override void OnSpawned(NetworkIdentity identity) + void LateUpdate() { - if (!identity.TryGetComponent(out NetworkTeam identityNetworkTeam)) - return; - - string networkTeamId = identityNetworkTeam.teamId; - lastObjectTeam[identity] = networkTeamId; - - // Null / Empty string is never a valid teamId...do not add to teamObjects collection - if (string.IsNullOrWhiteSpace(networkTeamId)) - return; - - //Debug.Log($"TeamInterestManagement.OnSpawned {identity.name} {networkTeamId}"); - - if (!teamObjects.TryGetValue(networkTeamId, out HashSet objects)) + // Rebuild all dirty teams + // dirtyTeams will be empty if no teams changed members + // by spawning or destroying or changing teamId in this frame. + foreach (string dirtyTeam in dirtyTeams) { - objects = new HashSet(); - teamObjects.Add(networkTeamId, objects); - } + // rebuild always, even if teamObjects[dirtyTeam] is empty. + // Players might have left the team, but they may still be spawned. + RebuildTeamObservers(dirtyTeam); - objects.Add(identity); + // clean up empty entries in the dict + if (teamObjects[dirtyTeam].Count == 0) + teamObjects.Remove(dirtyTeam); + } - // Team ID could have been set in NetworkBehaviour::OnStartServer on this object. - // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here. - RebuildTeamObservers(networkTeamId); + dirtyTeams.Clear(); } [ServerCallback] - public override void OnDestroyed(NetworkIdentity identity) + void RebuildTeamObservers(string teamId) { - if (lastObjectTeam.TryGetValue(identity, out string currentTeam)) - { - lastObjectTeam.Remove(identity); - if (!string.IsNullOrWhiteSpace(currentTeam) && teamObjects.TryGetValue(currentTeam, out HashSet objects) && objects.Remove(identity)) - RebuildTeamObservers(currentTeam); - } + foreach (NetworkTeam networkTeam in teamObjects[teamId]) + if (networkTeam.netIdentity != null) + NetworkServer.RebuildObservers(networkTeam.netIdentity, false); } - // internal so we can update from tests + // called by NetworkTeam.teamId setter [ServerCallback] - internal void Update() + internal void OnTeamChanged(NetworkTeam networkTeam, string oldTeam) { - // for each spawned: - // if team changed: - // add previous to dirty - // add new to dirty - foreach (NetworkIdentity netIdentity in NetworkServer.spawned.Values) - { - // Ignore objects that don't have a NetworkTeam component - if (!netIdentity.TryGetComponent(out NetworkTeam identityNetworkTeam)) - continue; + // This object is in a new team so observers in the prior team + // and the new team need to rebuild their respective observers lists. - string networkTeamId = identityNetworkTeam.teamId; - if (!lastObjectTeam.TryGetValue(netIdentity, out string currentTeam)) - continue; - - // Null / Empty string is never a valid teamId - // Nothing to do if teamId hasn't changed - if (string.IsNullOrWhiteSpace(networkTeamId) || networkTeamId == currentTeam) - continue; + // Remove this object from the hashset of the team it just left + // Null / Empty string is never a valid teamId + if (!string.IsNullOrWhiteSpace(oldTeam)) + { + dirtyTeams.Add(oldTeam); + teamObjects[oldTeam].Remove(networkTeam); + } - // Mark new/old Teams as dirty so they get rebuilt - UpdateDirtyTeams(networkTeamId, currentTeam); + // Null / Empty string is never a valid teamId + if (string.IsNullOrWhiteSpace(networkTeam.teamId)) + return; - // This object is in a new team so observers in the prior team - // and the new team need to rebuild their respective observers lists. - UpdateTeamObjects(netIdentity, networkTeamId, currentTeam); - } + dirtyTeams.Add(networkTeam.teamId); - // rebuild all dirty teams - foreach (string dirtyTeam in dirtyTeams) - RebuildTeamObservers(dirtyTeam); + // Make sure this new team is in the dictionary + if (!teamObjects.ContainsKey(networkTeam.teamId)) + teamObjects[networkTeam.teamId] = new HashSet(); - dirtyTeams.Clear(); + // Add this object to the hashset of the new team + teamObjects[networkTeam.teamId].Add(networkTeam); } - void UpdateDirtyTeams(string newTeam, string currentTeam) + [ServerCallback] + public override void OnSpawned(NetworkIdentity identity) { - // Null / Empty string is never a valid teamId - if (!string.IsNullOrWhiteSpace(currentTeam)) - dirtyTeams.Add(currentTeam); + if (!identity.TryGetComponent(out NetworkTeam networkTeam)) + return; - dirtyTeams.Add(newTeam); - } + string networkTeamId = networkTeam.teamId; - void UpdateTeamObjects(NetworkIdentity netIdentity, string newTeam, string currentTeam) - { - // Remove this object from the hashset of the team it just left - // string.Empty is never a valid teamId - if (!string.IsNullOrWhiteSpace(currentTeam)) - teamObjects[currentTeam].Remove(netIdentity); + // Null / Empty string is never a valid teamId...do not add to teamObjects collection + if (string.IsNullOrWhiteSpace(networkTeamId)) + return; - // Set this to the new team this object just entered - lastObjectTeam[netIdentity] = newTeam; + // Debug.Log($"TeamInterestManagement.OnSpawned({identity.name}) currentTeam: {currentTeam}"); + if (!teamObjects.TryGetValue(networkTeamId, out HashSet objects)) + { + objects = new HashSet(); + teamObjects.Add(networkTeamId, objects); + } - // Make sure this new team is in the dictionary - if (!teamObjects.ContainsKey(newTeam)) - teamObjects.Add(newTeam, new HashSet()); + objects.Add(networkTeam); - // Add this object to the hashset of the new team - teamObjects[newTeam].Add(netIdentity); + // Team ID could have been set in NetworkBehaviour::OnStartServer on this object. + // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here. + // Add the current team to dirtyTeames for LateUpdate to rebuild it. + dirtyTeams.Add(networkTeamId); } - void RebuildTeamObservers(string teamId) + [ServerCallback] + public override void OnDestroyed(NetworkIdentity identity) { - foreach (NetworkIdentity netIdentity in teamObjects[teamId]) - if (netIdentity != null) - NetworkServer.RebuildObservers(netIdentity, false); + // Don't RebuildSceneObservers here - that will happen in LateUpdate. + // Multiple objects could be destroyed in same frame and we don't + // want to rebuild for each one...let LateUpdate do it once. + // We must add the current team to dirtyTeames for LateUpdate to rebuild it. + if (identity.TryGetComponent(out NetworkTeam currentTeam)) + { + if (!string.IsNullOrWhiteSpace(currentTeam.teamId) && + teamObjects.TryGetValue(currentTeam.teamId, out HashSet objects) && + objects.Remove(currentTeam)) + dirtyTeams.Add(currentTeam.teamId); + } } public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) @@ -130,7 +121,7 @@ public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnection if (identityNetworkTeam.forceShown) return true; - // string.Empty is never a valid teamId + // Null / Empty string is never a valid teamId if (string.IsNullOrWhiteSpace(identityNetworkTeam.teamId)) return false; @@ -144,7 +135,7 @@ public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnection //Debug.Log($"TeamInterestManagement.OnCheckObserver {identity.name} {identityNetworkTeam.teamId} | {newObserver.identity.name} {newObserverNetworkTeam.teamId}"); - // Observed only if teamId's match + // Observed only if teamId's team return identityNetworkTeam.teamId == newObserverNetworkTeam.teamId; } @@ -168,14 +159,14 @@ public override void OnRebuildObservers(NetworkIdentity identity, HashSet objects)) + // Abort if this team hasn't been created yet by OnSpawned or OnTeamChanged + if (!teamObjects.TryGetValue(networkTeam.teamId, out HashSet objects)) return; // Add everything in the hashset for this object's current team - foreach (NetworkIdentity networkIdentity in objects) - if (networkIdentity != null && networkIdentity.connectionToClient != null) - newObservers.Add(networkIdentity.connectionToClient); + foreach (NetworkTeam netTeam in objects) + if (netTeam.netIdentity != null && netTeam.netIdentity.connectionToClient != null) + newObservers.Add(netTeam.netIdentity.connectionToClient); } void AddAllConnections(HashSet newObservers) diff --git a/Assets/Mirror/Core/Empty/Logging.meta b/Assets/Mirror/Components/LagCompensation.meta similarity index 77% rename from Assets/Mirror/Core/Empty/Logging.meta rename to Assets/Mirror/Components/LagCompensation.meta index 867da74..669a5b8 100644 --- a/Assets/Mirror/Core/Empty/Logging.meta +++ b/Assets/Mirror/Components/LagCompensation.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 63d647500ca1bfa4a845bc1f4cff9dcc +guid: 00ac1d0527f234939aba22b4d7cbf280 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs new file mode 100644 index 0000000..876eb18 --- /dev/null +++ b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs @@ -0,0 +1,109 @@ +// Applies HistoryBounds to the physics world by projecting to a trigger Collider. +// This way we can use Physics.Raycast on it. +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/ Lag Compensation/ History Collider")] + public class HistoryCollider : MonoBehaviour + { + [Header("Components")] + [Tooltip("The object's actual collider. We need to know where it is, and how large it is.")] + public Collider actualCollider; + + [Tooltip("The helper collider that the history bounds are projected onto.\nNeeds to be added to a child GameObject to counter-rotate an axis aligned Bounding Box onto it.\nThis is only used by this component.")] + public BoxCollider boundsCollider; + + [Header("History")] + [Tooltip("Keep this many past bounds in the buffer. The larger this is, the further we can raycast into the past.\nMaximum time := historyAmount * captureInterval")] + public int boundsLimit = 8; + + [Tooltip("Gather N bounds at a time into a bucket for faster encapsulation. A factor of 2 will be twice as fast, etc.")] + public int boundsPerBucket = 2; + + [Tooltip("Capture bounds every 'captureInterval' seconds. Larger values will require fewer computations, but may not capture every small move.")] + public float captureInterval = 0.100f; // 100 ms + double lastCaptureTime = 0; + + [Header("Debug")] + public Color historyColor = new Color(1.0f, 0.5f, 0.0f, 1.0f); + public Color currentColor = Color.red; + + protected HistoryBounds history = null; + + protected virtual void Awake() + { + history = new HistoryBounds(boundsLimit, boundsPerBucket); + + // ensure colliders were set. + // bounds collider should always be a trigger. + if (actualCollider == null) Debug.LogError("HistoryCollider: actualCollider was not set."); + if (boundsCollider == null) Debug.LogError("HistoryCollider: boundsCollider was not set."); + if (boundsCollider.transform.parent != transform) Debug.LogError("HistoryCollider: boundsCollider must be a child of this GameObject."); + if (!boundsCollider.isTrigger) Debug.LogError("HistoryCollider: boundsCollider must be a trigger."); + } + + // capturing and projecting onto colliders should use physics update + protected virtual void FixedUpdate() + { + // capture current bounds every interval + if (NetworkTime.localTime >= lastCaptureTime + captureInterval) + { + lastCaptureTime = NetworkTime.localTime; + CaptureBounds(); + } + + // project bounds onto helper collider + ProjectBounds(); + } + + protected virtual void CaptureBounds() + { + // grab current collider bounds + // this is in world space coordinates, and axis aligned + // TODO double check + Bounds bounds = actualCollider.bounds; + + // insert into history + history.Insert(bounds); + } + + protected virtual void ProjectBounds() + { + // grab total collider encapsulating all of history + Bounds total = history.total; + + // don't assign empty bounds, this will throw a Unity warning + if (history.boundsCount == 0) return; + + // scale projection doesn't work yet. + // for now, don't allow scale changes. + if (transform.lossyScale != Vector3.one) + { + Debug.LogWarning($"HistoryCollider: {name}'s transform global scale must be (1,1,1)."); + return; + } + + // counter rotate the child collider against the gameobject's rotation. + // we need this to always be axis aligned. + boundsCollider.transform.localRotation = Quaternion.Inverse(transform.rotation); + + // project world space bounds to collider's local space + boundsCollider.center = boundsCollider.transform.InverseTransformPoint(total.center); + boundsCollider.size = total.size; // TODO projection? + } + + // TODO runtime drawing for debugging? + protected virtual void OnDrawGizmos() + { + // draw total bounds + Gizmos.color = historyColor; + Gizmos.DrawWireCube(history.total.center, history.total.size); + + // draw current bounds + Gizmos.color = currentColor; + Gizmos.DrawWireCube(actualCollider.bounds.center, actualCollider.bounds.size); + } + } +} diff --git a/Assets/Mirror/Core/Empty/ClientScene.cs.meta b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs.meta similarity index 86% rename from Assets/Mirror/Core/Empty/ClientScene.cs.meta rename to Assets/Mirror/Components/LagCompensation/HistoryCollider.cs.meta index 82b617e..6275ff1 100644 --- a/Assets/Mirror/Core/Empty/ClientScene.cs.meta +++ b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 96fc7967f813e4960b9119d7c2118494 +guid: f5f2158d9776d4b569858f793be4da60 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs new file mode 100644 index 0000000..63669c0 --- /dev/null +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -0,0 +1,197 @@ +// Add this component to a Player object with collider. +// Automatically keeps a history for lag compensation. +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public struct Capture3D : Capture + { + public double timestamp { get; set; } + public Vector3 position; + public Vector3 size; + + public Capture3D(double timestamp, Vector3 position, Vector3 size) + { + this.timestamp = timestamp; + this.position = position; + this.size = size; + } + + public void DrawGizmo() + { + Gizmos.DrawWireCube(position, size); + } + + public static Capture3D Interpolate(Capture3D from, Capture3D to, double t) => + new Capture3D( + 0, // interpolated snapshot is applied directly. don't need timestamps. + Vector3.LerpUnclamped(from.position, to.position, (float)t), + Vector3.LerpUnclamped(from.size, to.size, (float)t) + ); + + public override string ToString() => $"(time={timestamp} pos={position} size={size})"; + } + + [DisallowMultipleComponent] + [AddComponentMenu("Network/ Lag Compensation/ Lag Compensator")] + [HelpURL("https://mirror-networking.gitbook.io/docs/manual/general/lag-compensation")] + public class LagCompensator : NetworkBehaviour + { + [Header("Components")] + [Tooltip("The collider to keep a history of.")] + public Collider trackedCollider; // assign this in inspector + + [Header("Settings")] + public LagCompensationSettings lagCompensationSettings = new LagCompensationSettings(); + double lastCaptureTime; + + // lag compensation history of + readonly Queue> history = new Queue>(); + + [Header("Debugging")] + public Color historyColor = Color.white; + + [ServerCallback] + protected virtual void Update() + { + // capture lag compensation snapshots every interval. + // NetworkTime.localTime because Unity 2019 doesn't have 'double' time yet. + if (NetworkTime.localTime >= lastCaptureTime + lagCompensationSettings.captureInterval) + { + lastCaptureTime = NetworkTime.localTime; + Capture(); + } + } + + [ServerCallback] + protected virtual void Capture() + { + // capture current state + Capture3D capture = new Capture3D( + NetworkTime.localTime, + trackedCollider.bounds.center, + trackedCollider.bounds.size + ); + + // insert into history + LagCompensation.Insert(history, lagCompensationSettings.historyLimit, NetworkTime.localTime, capture); + } + + protected virtual void OnDrawGizmos() + { + // draw history + Gizmos.color = historyColor; + LagCompensation.DrawGizmos(history); + } + + // sampling //////////////////////////////////////////////////////////// + // sample the sub-tick (=interpolated) history of this object for a hit test. + // 'viewer' needs to be the player who fired! + // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). + [ServerCallback] + public virtual bool Sample(NetworkConnectionToClient viewer, out Capture3D sample) + { + // never trust the client: estimate client time instead. + // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking + // the estimation is very good. the error is as low as ~6ms for the demo. + // note that passing 'rtt' is fine: EstimateTime halves it to latency. + double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, viewer.rtt, NetworkClient.bufferTime); + + // sample the history to get the nearest snapshots around 'timestamp' + if (LagCompensation.Sample(history, estimatedTime, lagCompensationSettings.captureInterval, out Capture3D resultBefore, out Capture3D resultAfter, out double t)) + { + // interpolate to get a decent estimation at exactly 'timestamp' + sample = Capture3D.Interpolate(resultBefore, resultAfter, t); + return true; + } + else Debug.Log($"CmdClicked: history doesn't contain {estimatedTime:F3}"); + + sample = default; + return false; + } + + // convenience tests /////////////////////////////////////////////////// + // there are multiple different ways to check a hit against the sample: + // - raycasting + // - bounds.contains + // - increasing bounds by tolerance and checking contains + // - threshold to bounds.closestpoint + // let's offer a few solutions directly and see which users prefer. + + // bounds check: checks distance to closest point on bounds in history @ -rtt. + // 'viewer' needs to be the player who fired! + // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). + // this is super simple and fast, but not 100% physically accurate since we don't raycast. + [ServerCallback] + public virtual bool BoundsCheck( + NetworkConnectionToClient viewer, + Vector3 hitPoint, + float toleranceDistance, + out float distance, + out Vector3 nearest) + { + // first, sample the history at -rtt of the viewer. + if (Sample(viewer, out Capture3D capture)) + { + // now that we know where the other player was at that time, + // we can see if the hit point was within tolerance of it. + // TODO consider rotations??? + // TODO consider original collider shape?? + Bounds bounds = new Bounds(capture.position, capture.size); + nearest = bounds.ClosestPoint(hitPoint); + distance = Vector3.Distance(nearest, hitPoint); + return distance <= toleranceDistance; + } + nearest = hitPoint; + distance = 0; + return false; + } + + // raycast check: creates a collider the sampled position and raycasts to hitPoint. + // 'viewer' needs to be the player who fired! + // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). + // this is physically accurate (checks against walls etc.), with the cost + // of a runtime instantiation. + // + // originPoint: where the player fired the weapon. + // hitPoint: where the player's local raycast hit. + // tolerance: scale up the sampled collider by % in order to have a bit of a tolerance. + // 0 means no extra tolerance, 0.05 means 5% extra tolerance. + // layerMask: the layer mask to use for the raycast. + [ServerCallback] + public virtual bool RaycastCheck( + NetworkConnectionToClient viewer, + Vector3 originPoint, + Vector3 hitPoint, + float tolerancePercent, + int layerMask, + out RaycastHit hit) + { + // first, sample the history at -rtt of the viewer. + if (Sample(viewer, out Capture3D capture)) + { + // instantiate a real physics collider on demand. + // TODO rotation?? + // TODO different collier types?? + GameObject temp = new GameObject("LagCompensatorTest"); + temp.transform.position = capture.position; + BoxCollider tempCollider = temp.AddComponent(); + tempCollider.size = capture.size * (1 + tolerancePercent); + + // raycast + Vector3 direction = hitPoint - originPoint; + float maxDistance = direction.magnitude * 2; + bool result = Physics.Raycast(originPoint, direction, out hit, maxDistance, layerMask); + + // cleanup + Destroy(temp); + return result; + } + + hit = default; + return false; + } + } +} diff --git a/Assets/Mirror/Core/Empty/FallbackTransport.cs.meta b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs.meta similarity index 86% rename from Assets/Mirror/Core/Empty/FallbackTransport.cs.meta rename to Assets/Mirror/Components/LagCompensation/LagCompensator.cs.meta index 509a58f..d4912e4 100644 --- a/Assets/Mirror/Core/Empty/FallbackTransport.cs.meta +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 330c9aab13d2d42069c6ebbe582b73ca +guid: a898831dd60c4cdfbfd9a6ea5702ed01 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirror/Components/NetworkAnimator.cs b/Assets/Mirror/Components/NetworkAnimator.cs index 9d36e46..657c28f 100644 --- a/Assets/Mirror/Components/NetworkAnimator.cs +++ b/Assets/Mirror/Components/NetworkAnimator.cs @@ -13,8 +13,8 @@ namespace Mirror /// 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. /// + // [RequireComponent(typeof(NetworkIdentity))] disabled to allow child NetworkBehaviours [AddComponentMenu("Network/Network Animator")] - [RequireComponent(typeof(NetworkIdentity))] [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-animator")] public class NetworkAnimator : NetworkBehaviour { @@ -31,11 +31,12 @@ public class NetworkAnimator : NetworkBehaviour public Animator animator; /// - /// Syncs animator.speed + /// Syncs animator.speed. + /// Default to 1 because Animator.speed defaults to 1. /// [SyncVar(hook = nameof(OnAnimatorSpeedChanged))] - float animatorSpeed; - float previousSpeed; + float animatorSpeed = 1f; + float previousSpeed = 1f; // Note: not an object[] array because otherwise initialization is real annoying int[] lastIntParameters; @@ -71,7 +72,7 @@ bool SendMessagesAllowed } } - void Awake() + void Initialize() { // 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 @@ -87,6 +88,17 @@ void Awake() layerWeight = new float[animator.layerCount]; } + // fix https://github.com/MirrorNetworking/Mirror/issues/2810 + // both Awake and Enable need to initialize arrays. + // in case users call SetActive(false) -> SetActive(true). + void Awake() => Initialize(); + void OnEnable() => Initialize(); + + public virtual void Reset() + { + syncDirection = SyncDirection.ClientToServer; + } + void FixedUpdate() { if (!SendMessagesAllowed) @@ -302,9 +314,18 @@ ulong NextDirtyBits() bool WriteParameters(NetworkWriter writer, bool forceAll = false) { + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize parameterCount to be 100% sure we deserialize correct amount of bytes. + // (255 parameters should be enough for everyone, write it as byte) + byte parameterCount = (byte)parameters.Length; + writer.WriteByte(parameterCount); + ulong dirtyBits = forceAll ? (~0ul) : NextDirtyBits(); writer.WriteULong(dirtyBits); - for (int i = 0; i < parameters.Length; i++) + + // iterate on byte count. if it's >256, it won't break + // serialization - just not serialize excess layers. + for (int i = 0; i < parameterCount; i++) { if ((dirtyBits & (1ul << i)) == 0) continue; @@ -331,11 +352,20 @@ bool WriteParameters(NetworkWriter writer, bool forceAll = false) void ReadParameters(NetworkReader reader) { + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize parameterCount to be 100% sure we deserialize correct amount of bytes. + // mismatch shows error to make this super easy to debug. + byte parameterCount = reader.ReadByte(); + if (parameterCount != parameters.Length) + { + Debug.LogError($"NetworkAnimator: serialized parameter count={parameterCount} does not match expected parameter count={parameters.Length}. Are you changing animators at runtime?", gameObject); + return; + } + 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++) + for (int i = 0; i < parameterCount; i++) { if ((dirtyBits & (1ul << i)) == 0) continue; @@ -367,23 +397,24 @@ public override void OnSerialize(NetworkWriter writer, bool initialState) base.OnSerialize(writer, initialState); if (initialState) { - for (int i = 0; i < animator.layerCount; i++) + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize layerCount to be 100% sure we deserialize correct amount of bytes. + // (255 layers should be enough for everyone, write it as byte) + byte layerCount = (byte)animator.layerCount; + writer.WriteByte(layerCount); + + // iterate on byte count. if it's >256, it won't break + // serialization - just not serialize excess layers. + for (int i = 0; i < 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); - } + AnimatorStateInfo st = animator.IsInTransition(i) + ? animator.GetNextAnimatorStateInfo(i) + : animator.GetCurrentAnimatorStateInfo(i); + writer.WriteInt(st.fullPathHash); + writer.WriteFloat(st.normalizedTime); writer.WriteFloat(animator.GetLayerWeight(i)); } - WriteParameters(writer, initialState); + WriteParameters(writer, true); } } @@ -392,11 +423,23 @@ public override void OnDeserialize(NetworkReader reader, bool initialState) base.OnDeserialize(reader, initialState); if (initialState) { - for (int i = 0; i < animator.layerCount; i++) + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize layerCount to be 100% sure we deserialize correct amount of bytes. + // mismatch shows error to make this super easy to debug. + byte layerCount = reader.ReadByte(); + if (layerCount != animator.layerCount) + { + Debug.LogError($"NetworkAnimator: serialized layer count={layerCount} does not match expected layer count={animator.layerCount}. Are you changing animators at runtime?", gameObject); + return; + } + + for (int i = 0; i < layerCount; i++) { int stateHash = reader.ReadInt(); float normalizedTime = reader.ReadFloat(); - animator.SetLayerWeight(i, reader.ReadFloat()); + float weight = reader.ReadFloat(); + + animator.SetLayerWeight(i, weight); animator.Play(stateHash, i, normalizedTime); } @@ -424,13 +467,13 @@ public void SetTrigger(int hash) { if (!isClient) { - Debug.LogWarning("Tried to set animation in the server for a client-controlled animator"); + Debug.LogWarning("Tried to set animation in the server for a client-controlled animator", gameObject); return; } if (!isOwned) { - Debug.LogWarning("Only the client with authority can set animations"); + Debug.LogWarning("Only the client with authority can set animations", gameObject); return; } @@ -444,7 +487,7 @@ public void SetTrigger(int hash) { if (!isServer) { - Debug.LogWarning("Tried to set animation in the client for a server-controlled animator"); + Debug.LogWarning("Tried to set animation in the client for a server-controlled animator", gameObject); return; } @@ -471,13 +514,13 @@ public void ResetTrigger(int hash) { if (!isClient) { - Debug.LogWarning("Tried to reset animation in the server for a client-controlled animator"); + Debug.LogWarning("Tried to reset animation in the server for a client-controlled animator", gameObject); return; } if (!isOwned) { - Debug.LogWarning("Only the client with authority can reset animations"); + Debug.LogWarning("Only the client with authority can reset animations", gameObject); return; } @@ -491,7 +534,7 @@ public void ResetTrigger(int hash) { if (!isServer) { - Debug.LogWarning("Tried to reset animation in the client for a server-controlled animator"); + Debug.LogWarning("Tried to reset animation in the client for a server-controlled animator", gameObject); return; } @@ -596,21 +639,15 @@ void RpcOnAnimationParametersClientMessage(byte[] parameters) HandleAnimParamsMsg(networkReader); } - [ClientRpc] + [ClientRpc(includeOwner = false)] void RpcOnAnimationTriggerClientMessage(int hash) { - // host/owner handles this before it is sent - if (isServer || (clientAuthority && isOwned)) return; - HandleAnimTriggerMsg(hash); } - [ClientRpc] + [ClientRpc(includeOwner = false)] void RpcOnAnimationResetTriggerClientMessage(int hash) { - // host/owner handles this before it is sent - if (isServer || (clientAuthority && isOwned)) return; - HandleAnimResetTriggerMsg(hash); } diff --git a/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs new file mode 100644 index 0000000..d3c3632 --- /dev/null +++ b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/Network Diagnostics Debugger")] + public class NetworkDiagnosticsDebugger : MonoBehaviour + { + public bool logInMessages = true; + public bool logOutMessages = true; + void OnInMessage(NetworkDiagnostics.MessageInfo msgInfo) + { + if (logInMessages) + Debug.Log(msgInfo); + } + void OnOutMessage(NetworkDiagnostics.MessageInfo msgInfo) + { + if (logOutMessages) + Debug.Log(msgInfo); + } + void OnEnable() + { + NetworkDiagnostics.InMessageEvent += OnInMessage; + NetworkDiagnostics.OutMessageEvent += OnOutMessage; + } + void OnDisable() + { + NetworkDiagnostics.InMessageEvent -= OnInMessage; + NetworkDiagnostics.OutMessageEvent -= OnOutMessage; + } + } +} diff --git a/Assets/Mirror/Core/Empty/LogFilter.cs.meta b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs.meta similarity index 86% rename from Assets/Mirror/Core/Empty/LogFilter.cs.meta rename to Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs.meta index aab4fa0..4a36428 100644 --- a/Assets/Mirror/Core/Empty/LogFilter.cs.meta +++ b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f6928b080072948f7b2909b4025fcc79 +guid: bc9f0a0fe4124424b8f9d4927795ee01 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirror/Components/NetworkPingDisplay.cs b/Assets/Mirror/Components/NetworkPingDisplay.cs index 156a48c..255e62d 100644 --- a/Assets/Mirror/Components/NetworkPingDisplay.cs +++ b/Assets/Mirror/Components/NetworkPingDisplay.cs @@ -21,12 +21,18 @@ void OnGUI() // only while client is active if (!NetworkClient.active) return; - // show rtt in bottom right corner, right aligned + // show stats in bottom right corner, right aligned GUI.color = color; Rect rect = new Rect(Screen.width - width - padding, Screen.height - height - padding, width, height); + GUILayout.BeginArea(rect); GUIStyle style = GUI.skin.GetStyle("Label"); style.alignment = TextAnchor.MiddleRight; - GUI.Label(rect, $"RTT: {Math.Round(NetworkTime.rtt * 1000)}ms", style); + GUILayout.BeginHorizontal(style); + GUILayout.Label($"RTT: {Math.Round(NetworkTime.rtt * 1000)}ms"); + GUI.color = NetworkClient.connectionQuality.ColorCode(); + GUILayout.Label($"Q: {new string('-', (int)NetworkClient.connectionQuality)}"); + GUILayout.EndHorizontal(); + GUILayout.EndArea(); GUI.color = Color.white; } } diff --git a/Assets/Mirror/Components/NetworkRigidbody.meta b/Assets/Mirror/Components/NetworkRigidbody.meta new file mode 100644 index 0000000..a67178e --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 80106690aef541a5b8e2f8fb3d5949ad +timeCreated: 1686733778 \ No newline at end of file diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs new file mode 100644 index 0000000..ba17a70 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs @@ -0,0 +1,112 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody (Reliable)")] + public class NetworkRigidbodyReliable : NetworkTransformReliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody rb; + bool wasKinematic; + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + return; + } + wasKinematic = rb.isKinematic; + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; + + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + } + + protected override void OnValidate() + { + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation; + } + } +} diff --git a/Assets/Mirror/Core/Empty/Logging/NetworkHeadlessLogger.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta similarity index 86% rename from Assets/Mirror/Core/Empty/Logging/NetworkHeadlessLogger.cs.meta rename to Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta index 221a61b..b3b61c9 100644 --- a/Assets/Mirror/Core/Empty/Logging/NetworkHeadlessLogger.cs.meta +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c7627623f2b9fad4484082517cd73e67 +guid: cb803efbe62c34d7baece46c9ffebad9 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs new file mode 100644 index 0000000..f17bab6 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs @@ -0,0 +1,112 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody 2D (Reliable)")] + public class NetworkRigidbodyReliable2D : NetworkTransformReliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody2D rb; + bool wasKinematic; + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + return; + } + wasKinematic = rb.isKinematic; + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; + + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + } + + protected override void OnValidate() + { + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation.eulerAngles.z; + } + } +} diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta new file mode 100644 index 0000000..172c8a4 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ec4f7556ca1e4b55a3381fc6a02b1bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs new file mode 100644 index 0000000..6a34766 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs @@ -0,0 +1,112 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody (Unreliable)")] + public class NetworkRigidbodyUnreliable : NetworkTransformUnreliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody rb; + bool wasKinematic; + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + return; + } + wasKinematic = rb.isKinematic; + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; + + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + } + + protected override void OnValidate() + { + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation; + } + } +} diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta new file mode 100644 index 0000000..2dfb14b --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b20dc110904e47f8a154cdcf6433eae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs new file mode 100644 index 0000000..308ce0e --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs @@ -0,0 +1,112 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody 2D (Unreliable)")] + public class NetworkRigidbodyUnreliable2D : NetworkTransformUnreliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody2D rb; + bool wasKinematic; + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + return; + } + wasKinematic = rb.isKinematic; + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; + + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + } + + protected override void OnValidate() + { + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation.eulerAngles.z; + } + } +} diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta new file mode 100644 index 0000000..8a19149 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c7e12ad9b9ae443c9fdf37e9f5ecd36 +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 index bde8180..4df69c6 100644 --- a/Assets/Mirror/Components/NetworkRoomManager.cs +++ b/Assets/Mirror/Components/NetworkRoomManager.cs @@ -21,7 +21,7 @@ public class NetworkRoomManager : NetworkManager public struct PendingPlayer { public NetworkConnectionToClient conn; - public GameObject roomPlayer; + public GameObject roomPlayer; } [Header("Room Settings")] @@ -56,7 +56,7 @@ public struct PendingPlayer /// List of players that are in the Room /// [FormerlySerializedAs("m_PendingPlayers")] - public List pendingPlayers = new List(); + public HashSet pendingPlayers = new HashSet(); [Header("Diagnostics")] /// @@ -64,14 +64,14 @@ public struct PendingPlayer /// [Tooltip("Diagnostic flag indicating all players are ready to play")] [FormerlySerializedAs("allPlayersReady")] - [SerializeField] bool _allPlayersReady; + [ReadOnly, 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(); + [ReadOnly, Tooltip("List of Room Player objects")] + public HashSet roomSlots = new HashSet(); public bool allPlayersReady { @@ -118,50 +118,9 @@ public override void 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(NetworkConnectionToClient conn) - { - Debug.Log($"NetworkRoomManager OnServerReady {conn}"); - 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(NetworkConnectionToClient conn, GameObject roomPlayer) { - Debug.Log($"NetworkRoom SceneLoadedForPlayer scene: {SceneManager.GetActiveScene().path} {conn}"); + //Debug.Log($"NetworkRoom SceneLoadedForPlayer scene: {SceneManager.GetActiveScene().path} {conn}"); if (Utils.IsSceneActive(RoomScene)) { @@ -190,28 +149,6 @@ void SceneLoadedForPlayer(NetworkConnectionToClient conn, GameObject roomPlayer) 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 (!Utils.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(); @@ -232,6 +169,31 @@ internal void CallOnClientExitRoom() } } + /// + /// 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 (!Utils.IsSceneActive(RoomScene)) + return; + + int numberOfReadyPlayers = NetworkServer.connections.Count(conn => + conn.Value != null && + conn.Value.identity != null && + conn.Value.identity.TryGetComponent(out NetworkRoomPlayer nrp) && + nrp.readyToBegin); + + bool enoughReadyPlayers = minPlayers <= 0 || numberOfReadyPlayers >= minPlayers; + if (enoughReadyPlayers) + { + pendingPlayers.Clear(); + allPlayersReady = true; + } + else + allPlayersReady = false; + } + #region server handlers /// @@ -289,15 +251,35 @@ public override void OnServerDisconnect(NetworkConnectionToClient conn) OnRoomServerDisconnect(conn); base.OnServerDisconnect(conn); -#if UNITY_SERVER - if (numPlayers < 1) + // Restart the server if we're headless and no players are connected. + // This will send server to offline scene, where auto-start will run. + if (Utils.IsHeadless() && 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 is ready. + /// The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process. + /// + /// Connection from client. + public override void OnServerReady(NetworkConnectionToClient conn) + { + //Debug.Log($"NetworkRoomManager OnServerReady {conn}"); + 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); + } + } + /// /// 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. @@ -333,10 +315,9 @@ public void RecalculateRoomPlayerIndices() { if (roomSlots.Count > 0) { - for (int i = 0; i < roomSlots.Count; i++) - { - roomSlots[i].index = i; - } + int i = 0; + foreach (NetworkRoomPlayer player in roomSlots) + player.index = i++; } } @@ -594,6 +575,30 @@ public virtual bool OnRoomServerSceneLoadedForPlayer(NetworkConnectionToClient c return true; } + /// + /// This is called on server from NetworkRoomPlayer.CmdChangeReadyState when client indicates change in Ready status. + /// + public virtual 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; + } + /// /// 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. diff --git a/Assets/Mirror/Components/NetworkRoomPlayer.cs b/Assets/Mirror/Components/NetworkRoomPlayer.cs index 9f5e158..6b7cda4 100644 --- a/Assets/Mirror/Components/NetworkRoomPlayer.cs +++ b/Assets/Mirror/Components/NetworkRoomPlayer.cs @@ -25,14 +25,14 @@ public class NetworkRoomPlayer : NetworkBehaviour /// 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")] + [ReadOnly, 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.")] + [ReadOnly, Tooltip("Diagnostic index of the player, e.g. Player1, Player2, etc.")] [SyncVar(hook = nameof(IndexChanged))] public int index; @@ -41,7 +41,7 @@ public class NetworkRoomPlayer : NetworkBehaviour /// /// Do not use Start - Override OnStartHost / OnStartClient instead! /// - public void Start() + public virtual void Start() { if (NetworkManager.singleton is NetworkRoomManager room) { diff --git a/Assets/Mirror/Components/NetworkStatistics.cs b/Assets/Mirror/Components/NetworkStatistics.cs index 5d09fd0..c00bb19 100644 --- a/Assets/Mirror/Components/NetworkStatistics.cs +++ b/Assets/Mirror/Components/NetworkStatistics.cs @@ -147,8 +147,8 @@ void OnGUI() if (NetworkClient.active || NetworkServer.active) { // create main GUI area - // 105 is below NetworkManager HUD in all cases. - GUILayout.BeginArea(new Rect(10, 105, 215, 300)); + // 120 is below NetworkManager HUD in all cases. + GUILayout.BeginArea(new Rect(10, 120, 215, 300)); // show client / server stats if active if (NetworkClient.active) OnClientGUI(); diff --git a/Assets/Mirror/Components/NetworkTransformReliable.meta b/Assets/Mirror/Components/NetworkTransform.meta similarity index 100% rename from Assets/Mirror/Components/NetworkTransformReliable.meta rename to Assets/Mirror/Components/NetworkTransform.meta diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransform.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransform.cs new file mode 100644 index 0000000..9e6a30e --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransform.cs @@ -0,0 +1,10 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + // DEPRECATED 2023-06-15 + [AddComponentMenu("")] + [Obsolete("NetworkTransform was renamed to NetworkTransformUnreliable.\nYou can easily swap the component's script by going into the Unity Inspector debug mode:\n1. Click the vertical dots on the top right in the Inspector tab.\n2. Find your NetworkTransform component\n3. Drag NetworkTransformUnreliable into the 'Script' field in the Inspector.\n4. Find the three dots and return to Normal mode.")] + public class NetworkTransform : NetworkTransformUnreliable {} +} diff --git a/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransform.cs.meta similarity index 100% rename from Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs.meta rename to Assets/Mirror/Components/NetworkTransform/NetworkTransform.cs.meta diff --git a/Assets/Mirror/Components/NetworkTransformBase.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs similarity index 60% rename from Assets/Mirror/Components/NetworkTransformBase.cs rename to Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs index 1cfe668..a30f5d9 100644 --- a/Assets/Mirror/Components/NetworkTransformBase.cs +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs @@ -22,42 +22,85 @@ namespace Mirror { + public enum CoordinateSpace { Local, World } + public abstract class NetworkTransformBase : NetworkBehaviour { // target transform to sync. can be on a child. + // TODO this field is kind of unnecessary since we now support child NetworkBehaviours [Header("Target")] [Tooltip("The Transform component to sync. May be on on this GameObject, or on a child.")] public Transform target; - // TODO SyncDirection { ClientToServer, ServerToClient } is easier? - // Deprecated 2022-10-25 - [Obsolete("NetworkTransform clientAuthority was replaced with syncDirection. To enable client authority, set SyncDirection to ClientToServer in the Inspector.")] - [Header("[Obsolete]")] // Unity doesn't show obsolete warning for fields. do it manually. - [Tooltip("Obsolete: NetworkTransform clientAuthority was replaced with syncDirection. To enable client authority, set SyncDirection to ClientToServer in the Inspector.")] - 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. protected bool IsClientWithAuthority => isClient && authority; - public readonly SortedList clientSnapshots = new SortedList(); - public readonly SortedList serverSnapshots = new SortedList(); + + // snapshots with initial capacity to avoid early resizing & allocations: see NetworkRigidbodyBenchmark example. + public readonly SortedList clientSnapshots = new SortedList(16); + public readonly SortedList serverSnapshots = new SortedList(16); // selective sync ////////////////////////////////////////////////////// - [Header("Selective Sync & Interpolation\nDon't change these at Runtime")] + [Header("Selective Sync\nDon't change these at Runtime")] public bool syncPosition = true; // do not change at runtime! public bool syncRotation = true; // do not change at runtime! - public bool syncScale = false; // do not change at runtime! rare. off by default. + public bool syncScale = false; // do not change at runtime! rare. off by default. + + [Header("Bandwidth Savings")] + [Tooltip("When true, changes are not sent unless greater than sensitivity values below.")] + public bool onlySyncOnChange = true; + [Tooltip("Apply smallest-three quaternion compression. This is lossy, you can disable it if the small rotation inaccuracies are noticeable in your project.")] + public bool compressRotation = true; + + // interpolation is on by default, but can be disabled to jump to + // the destination immediately. some projects need this. + [Header("Interpolation")] + [Tooltip("Set to false to have a snap-like effect on position movement.")] + public bool interpolatePosition = true; + [Tooltip("Set to false to have a snap-like effect on rotations.")] + public bool interpolateRotation = true; + [Tooltip("Set to false to remove scale smoothing. Example use-case: Instant flipping of sprites that use -X and +X for direction.")] + public bool interpolateScale = true; + + // CoordinateSpace /////////////////////////////////////////////////////////// + [Header("Coordinate Space")] + [Tooltip("Local by default. World may be better when changing hierarchy, or non-NetworkTransforms root position/rotation/scale values.")] + public CoordinateSpace coordinateSpace = CoordinateSpace.Local; + + [Header("Send Interval Multiplier")] + [Tooltip("Check/Sync every multiple of Network Manager send interval (= 1 / NM Send Rate), instead of every send interval.\n(30 NM send rate, and 3 interval, is a send every 0.1 seconds)\nA larger interval means less network sends, which has a variety of upsides. The drawbacks are delays and lower accuracy, you should find a nice balance between not sending too much, but the results looking good for your particular scenario.")] + [Range(1, 120)] + public uint sendIntervalMultiplier = 1; + + [Header("Timeline Offset")] + [Tooltip("Add a small timeline offset to account for decoupled arrival of NetworkTime and NetworkTransform snapshots.\nfixes: https://github.com/MirrorNetworking/Mirror/issues/3427")] + public bool timelineOffset = false; + + // Ninja's Notes on offset & mulitplier: + // + // In a no multiplier scenario: + // 1. Snapshots are sent every frame (frame being 1 NM send interval). + // 2. Time Interpolation is set to be 'behind' by 2 frames times. + // In theory where everything works, we probably have around 2 snapshots before we need to interpolate snapshots. From NT perspective, we should always have around 2 snapshots ready, so no stutter. + // + // In a multiplier scenario: + // 1. Snapshots are sent every 10 frames. + // 2. Time Interpolation remains 'behind by 2 frames'. + // When everything works, we are receiving NT snapshots every 10 frames, but start interpolating after 2. + // Even if I assume we had 2 snapshots to begin with to start interpolating (which we don't), by the time we reach 13th frame, we are out of snapshots, and have to wait 7 frames for next snapshot to come. This is the reason why we absolutely need the timestamp adjustment. We are starting way too early to interpolate. + // + protected double timeStampAdjustment => NetworkServer.sendInterval * (sendIntervalMultiplier - 1); + protected double offset => timelineOffset ? NetworkServer.sendInterval * sendIntervalMultiplier : 0; // debugging /////////////////////////////////////////////////////////// [Header("Debug")] public bool showGizmos; - public bool showOverlay; + public bool showOverlay; public Color overlayColor = new Color(0, 0, 0, 0.5f); // initialization ////////////////////////////////////////////////////// - // make sure to call this when inheriting too! - protected virtual void Awake() {} - - protected virtual void OnValidate() + // forcec configuration of some settings + protected virtual void Configure() { // set target to self if none yet if (target == null) target = transform; @@ -69,19 +112,69 @@ protected virtual void OnValidate() // actually use NetworkServer.sendInterval. syncInterval = 0; - // obsolete clientAuthority compatibility: - // if it was used, then set the new SyncDirection automatically. - // if it wasn't used, then don't touch syncDirection. - #pragma warning disable CS0618 - if (clientAuthority) - { - syncDirection = SyncDirection.ClientToServer; - Debug.LogWarning($"{name}'s NetworkTransform component has obsolete .clientAuthority enabled. Please disable it and set SyncDirection to ClientToServer instead."); - } - #pragma warning restore CS0618 + // Unity doesn't support setting world scale. + // OnValidate force disables syncScale in world mode. + if (coordinateSpace == CoordinateSpace.World) syncScale = false; + } + + // make sure to call this when inheriting too! + protected virtual void Awake() + { + // sometimes OnValidate() doesn't run before launching a project. + // need to guarantee configuration runs. + Configure(); + } + + protected override void OnValidate() + { + base.OnValidate(); + + // configure in awake + Configure(); } // snapshot functions ////////////////////////////////////////////////// + // get local/world position + protected virtual Vector3 GetPosition() => + coordinateSpace == CoordinateSpace.Local ? target.localPosition : target.position; + + // get local/world rotation + protected virtual Quaternion GetRotation() => + coordinateSpace == CoordinateSpace.Local ? target.localRotation : target.rotation; + + // get local/world scale + protected virtual Vector3 GetScale() => + coordinateSpace == CoordinateSpace.Local ? target.localScale : target.lossyScale; + + // set local/world position + protected virtual void SetPosition(Vector3 position) + { + if (coordinateSpace == CoordinateSpace.Local) + target.localPosition = position; + else + target.position = position; + } + + // set local/world rotation + protected virtual void SetRotation(Quaternion rotation) + { + if (coordinateSpace == CoordinateSpace.Local) + target.localRotation = rotation; + else + target.rotation = rotation; + } + + // set local/world position + protected virtual void SetScale(Vector3 scale) + { + if (coordinateSpace == CoordinateSpace.Local) + target.localScale = scale; + // Unity doesn't support setting world scale. + // OnValidate disables syncScale in world mode. + // else + // target.lossyScale = scale; // TODO + } + // construct a snapshot of the current state // => internal for testing protected virtual TransformSnapshot Construct() @@ -89,16 +182,11 @@ protected virtual TransformSnapshot Construct() // NetworkTime.localTime for double precision until Unity has it too return new TransformSnapshot( // our local time is what the other end uses as remote time -#if !UNITY_2020_3_OR_NEWER NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet -#else - Time.timeAsDouble, -#endif - // the other end fills out local time itself - 0, - target.localPosition, - target.localRotation, - target.localScale + 0, // the other end fills out local time itself + GetPosition(), + GetRotation(), + GetScale() ); } @@ -113,22 +201,23 @@ protected void AddSnapshot(SortedList snapshots, doub // 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 = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position : target.localPosition; - if (!rotation.HasValue) rotation = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation : target.localRotation; - if (!scale.HasValue) scale = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].scale : target.localScale; + + if (!position.HasValue) position = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position : GetPosition(); + if (!rotation.HasValue) rotation = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation : GetRotation(); + if (!scale.HasValue) scale = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].scale : GetScale(); // insert transform snapshot - SnapshotInterpolation.InsertIfNotExists(snapshots, new TransformSnapshot( - timeStamp, // arrival remote timestamp. NOT remote time. -#if !UNITY_2020_3_OR_NEWER - NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet -#else - Time.timeAsDouble, -#endif - position.Value, - rotation.Value, - scale.Value - )); + SnapshotInterpolation.InsertIfNotExists( + snapshots, + NetworkClient.snapshotSettings.bufferLimit, + new TransformSnapshot( + timeStamp, // arrival remote timestamp. NOT remote time. + NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet + position.Value, + rotation.Value, + scale.Value + ) + ); } // apply a snapshot to the Transform. @@ -141,7 +230,7 @@ protected void AddSnapshot(SortedList snapshots, doub // // NOTE: stuck detection is unnecessary here. // we always set transform.position anyway, we can't get stuck. - protected virtual void Apply(TransformSnapshot interpolated) + protected virtual void Apply(TransformSnapshot interpolated, TransformSnapshot endGoal) { // local position/rotation for VR support // @@ -150,9 +239,11 @@ protected virtual void Apply(TransformSnapshot interpolated) // -> 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) target.localPosition = interpolated.position; - if (syncRotation) target.localRotation = interpolated.rotation; - if (syncScale) target.localScale = interpolated.scale; + + // interpolate parts + if (syncPosition) SetPosition(interpolatePosition ? interpolated.position : endGoal.position); + if (syncRotation) SetRotation(interpolateRotation ? interpolated.rotation : endGoal.rotation); + if (syncScale) SetScale(interpolateScale ? interpolated.scale : endGoal.scale); } // client->server teleport to force position without interpolation. @@ -232,21 +323,29 @@ public void RpcTeleport(Vector3 destination, Quaternion rotation) } [ClientRpc] - void RpcReset() + void RpcResetState() { - Reset(); + ResetState(); } // 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. target.position = destination; + // reset interpolation to immediately jump to the new position. + // do not call Reset() here, this would cause delta compression to + // get out of sync for NetworkTransformReliable because NTReliable's + // 'override Reset()' resets lastDe/SerializedPosition: + // https://github.com/MirrorNetworking/Mirror/issues/3588 + // because client's next OnSerialize() will delta compress, + // but server's last delta will have been reset, causing offsets. + // + // instead, simply clear snapshots. + ResetState(); + // TODO // what if we still receive a snapshot from before the interpolation? // it could easily happen over unreliable. @@ -256,21 +355,29 @@ protected virtual void OnTeleport(Vector3 destination) // common Teleport code for client->server and server->client protected virtual void OnTeleport(Vector3 destination, Quaternion rotation) { - // reset any in-progress interpolation & buffers - Reset(); - // set the new position. // interpolation will automatically continue. target.position = destination; target.rotation = rotation; + // reset interpolation to immediately jump to the new position. + // do not call Reset() here, this would cause delta compression to + // get out of sync for NetworkTransformReliable because NTReliable's + // 'override Reset()' resets lastDe/SerializedPosition: + // https://github.com/MirrorNetworking/Mirror/issues/3588 + // because client's next OnSerialize() will delta compress, + // but server's last delta will have been reset, causing offsets. + // + // instead, simply clear snapshots. + ResetState(); + // TODO // what if we still receive a snapshot from before the interpolation? // it could easily happen over unreliable. // -> maybe add destination as first entry? } - public virtual void Reset() + public virtual void ResetState() { // disabled objects aren't updated anymore. // so let's clear the buffers. @@ -278,9 +385,16 @@ public virtual void Reset() clientSnapshots.Clear(); } + public virtual void Reset() + { + ResetState(); + // default to ClientToServer so this works immediately for users + syncDirection = SyncDirection.ClientToServer; + } + protected virtual void OnEnable() { - Reset(); + ResetState(); if (NetworkServer.active) NetworkIdentity.clientAuthorityCallback += OnClientAuthorityChanged; @@ -288,7 +402,7 @@ protected virtual void OnEnable() protected virtual void OnDisable() { - Reset(); + ResetState(); if (NetworkServer.active) NetworkIdentity.clientAuthorityCallback -= OnClientAuthorityChanged; @@ -306,8 +420,8 @@ void OnClientAuthorityChanged(NetworkConnectionToClient conn, NetworkIdentity id if (syncDirection == SyncDirection.ClientToServer) { - Reset(); - RpcReset(); + ResetState(); + RpcResetState(); } } @@ -361,7 +475,7 @@ protected virtual void DrawGizmos(SortedList buffer) TransformSnapshot entry = buffer.Values[i]; bool oldEnough = entry.localTime <= threshold; Gizmos.color = oldEnough ? oldEnoughColor : notOldEnoughColor; - Gizmos.DrawCube(entry.position, Vector3.one); + Gizmos.DrawWireCube(entry.position, Vector3.one); } // extra: lines between start<->position<->goal diff --git a/Assets/Mirror/Core/Empty/NetworkTransformBase.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs.meta similarity index 86% rename from Assets/Mirror/Core/Empty/NetworkTransformBase.cs.meta rename to Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs.meta index ab649d9..ef58471 100644 --- a/Assets/Mirror/Core/Empty/NetworkTransformBase.cs.meta +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2e77294d8ccbc4e7cb8ca2bd0d3e99ea +guid: 7c44135fde488424eaf28566206ce473 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransformChild.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformChild.cs similarity index 100% rename from Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransformChild.cs rename to Assets/Mirror/Components/NetworkTransform/NetworkTransformChild.cs diff --git a/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransformChild.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformChild.cs.meta similarity index 100% rename from Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransformChild.cs.meta rename to Assets/Mirror/Components/NetworkTransform/NetworkTransformChild.cs.meta diff --git a/Assets/Mirror/Components/NetworkTransformReliable/NetworkTransformReliable.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs similarity index 71% rename from Assets/Mirror/Components/NetworkTransformReliable/NetworkTransformReliable.cs rename to Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs index 718335b..fd87ff2 100644 --- a/Assets/Mirror/Components/NetworkTransformReliable/NetworkTransformReliable.cs +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs @@ -8,17 +8,16 @@ namespace Mirror [AddComponentMenu("Network/Network Transform (Reliable)")] public class NetworkTransformReliable : NetworkTransformBase { - [Header("Sync Only If Changed")] - [Tooltip("When true, changes are not sent unless greater than sensitivity values below.")] - public bool onlySyncOnChange = true; + uint sendIntervalCounter = 0; + double lastSendIntervalTime = double.MinValue; + + [Header("Additional Settings")] [Tooltip("If we only sync on change, then we need to correct old snapshots if more time than sendInterval * multiplier has elapsed.\n\nOtherwise the first move will always start interpolating from the last move sequence's time, which will make it stutter when starting every time.")] public float onlySyncOnChangeCorrectionMultiplier = 2; [Header("Rotation")] [Tooltip("Sensitivity of changes needed before an updated state is sent over the network")] public float rotationSensitivity = 0.01f; - [Tooltip("Apply smallest-three quaternion compression. This is lossy, you can disable it if the small rotation inaccuracies are noticeable in your project.")] - public bool compressRotation = false; // delta compression is capable of detecting byte-level changes. // if we scale float position to bytes, @@ -31,31 +30,47 @@ public class NetworkTransformReliable : NetworkTransformBase [Range(0.00_01f, 1f)] // disallow 0 division. 1mm to 1m precision is enough range. public float positionPrecision = 0.01f; // 1 cm [Range(0.00_01f, 1f)] // disallow 0 division. 1mm to 1m precision is enough range. - public float scalePrecision = 0.01f; // 1 cm + public float scalePrecision = 0.01f; // 1 cm // delta compression needs to remember 'last' to compress against - protected Vector3Long lastSerializedPosition = Vector3Long.zero; + protected Vector3Long lastSerializedPosition = Vector3Long.zero; protected Vector3Long lastDeserializedPosition = Vector3Long.zero; - protected Vector3Long lastSerializedScale = Vector3Long.zero; - protected Vector3Long lastDeserializedScale = Vector3Long.zero; + protected Vector3Long lastSerializedScale = Vector3Long.zero; + protected Vector3Long lastDeserializedScale = Vector3Long.zero; // Used to store last sent snapshots protected TransformSnapshot last; - int lastClientCount = 0; + protected int lastClientCount = 1; // update ////////////////////////////////////////////////////////////// void Update() { // if server then always sync to others. - if (isServer) UpdateServer(); + 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(); } - void UpdateServer() + void LateUpdate() + { + // set dirty to trigger OnSerialize. either always, or only if changed. + // It has to be checked in LateUpdate() for onlySyncOnChange to avoid + // the possibility of Update() running first before the object's movement + // script's Update(), which then causes NT to send every alternate frame + // instead. + if (isServer || (IsClientWithAuthority && NetworkClient.ready)) + { + if (sendIntervalCounter == sendIntervalMultiplier && (!onlySyncOnChange || Changed(Construct()))) + SetDirty(); + + CheckLastSendTime(); + } + } + + protected virtual void UpdateServer() { // apply buffered snapshots IF client authority // -> in server authority, server moves the object @@ -82,42 +97,19 @@ void UpdateServer() // interpolate & apply TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); - Apply(computed); + Apply(computed, to); } } - - // set dirty to trigger OnSerialize. either always, or only if changed. - // technically snapshot interpolation requires constant sending. - // however, with reliable it should be fine without constant sends. - // - // detect changes _after_ all changes were applied above. - if (!onlySyncOnChange || Changed(Construct())) - SetDirty(); } - void UpdateClient() + protected virtual void UpdateClient() { // client authority, and local player (= allowed to move myself)? - if (IsClientWithAuthority) + if (!IsClientWithAuthority) { - // https://github.com/vis2k/Mirror/pull/2992/ - if (!NetworkClient.ready) return; - - // set dirty to trigger OnSerialize. either always, or only if changed. - // technically snapshot interpolation requires constant sending. - // however, with reliable it should be fine without constant sends. - if (!onlySyncOnChange || Changed(Construct())) - SetDirty(); - } - // for all other clients (and for local player if !authority), - // we need to apply snapshots from the buffer - else - { - // only while we have snapshots if (clientSnapshots.Count > 0) { - // step the interpolation without touching time. // NetworkClient is responsible for time globally. SnapshotInterpolation.StepInterpolation( @@ -129,24 +121,24 @@ void UpdateClient() // interpolate & apply TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); - Apply(computed); - - } - - // 'only sync if moved' - // explain.. - // from 1 snap to next snap.. - // it'll be old... - if (lastClientCount > 1 && clientSnapshots.Count == 1) - { - // this is it. snapshots are down to '1'. - // does this cause stuck? + Apply(computed, to); } lastClientCount = clientSnapshots.Count; } } + protected virtual void CheckLastSendTime() + { + // timeAsDouble not available in older Unity versions. + if (AccurateInterval.Elapsed(NetworkTime.localTime, NetworkServer.sendInterval, ref lastSendIntervalTime)) + { + if (sendIntervalCounter == sendIntervalMultiplier) + sendIntervalCounter = 0; + sendIntervalCounter++; + } + } + // check if position / rotation / scale changed since last sync protected virtual bool Changed(TransformSnapshot current) => // position is quantized and delta compressed. @@ -191,6 +183,16 @@ public override void OnSerialize(NetworkWriter writer, bool initialState) // initial if (initialState) { + // If there is a last serialized snapshot, we use it. + // This prevents the new client getting a snapshot that is different + // from what the older clients last got. If this happens, and on the next + // regular serialisation the delta compression will get wrong values. + // Notes: + // 1. Interestingly only the older clients have it wrong, because at the end + // of this function, last = snapshot which is the initial state's snapshot + // 2. Regular NTR gets by this bug because it sends every frame anyway so initialstate + // snapshot constructed would have been the same as the last anyway. + if (last.remoteTime > 0) snapshot = last; if (syncPosition) writer.WriteVector3(snapshot.position); if (syncRotation) { @@ -200,7 +202,7 @@ public override void OnSerialize(NetworkWriter writer, bool initialState) else writer.WriteQuaternion(snapshot.rotation); } - if (syncScale) writer.WriteVector3(snapshot.scale); + if (syncScale) writer.WriteVector3(snapshot.scale); } // delta else @@ -227,14 +229,11 @@ public override void OnSerialize(NetworkWriter writer, bool initialState) Compression.ScaleToLong(snapshot.scale, scalePrecision, out Vector3Long quantized); DeltaCompression.Compress(writer, lastSerializedScale, quantized); } - - // int written = writer.Position - before; - // Debug.Log($"{name} compressed to {written} bytes"); } // save serialized as 'last' for next delta compression if (syncPosition) Compression.ScaleToLong(snapshot.position, positionPrecision, out lastSerializedPosition); - if (syncScale) Compression.ScaleToLong(snapshot.scale, scalePrecision, out lastSerializedScale); + if (syncScale) Compression.ScaleToLong(snapshot.scale, scalePrecision, out lastSerializedScale); // set 'last' last = snapshot; @@ -242,9 +241,9 @@ public override void OnSerialize(NetworkWriter writer, bool initialState) public override void OnDeserialize(NetworkReader reader, bool initialState) { - Vector3? position = null; + Vector3? position = null; Quaternion? rotation = null; - Vector3? scale = null; + Vector3? scale = null; // initial if (initialState) @@ -258,7 +257,7 @@ public override void OnDeserialize(NetworkReader reader, bool initialState) else rotation = reader.ReadQuaternion(); } - if (syncScale) scale = reader.ReadVector3(); + if (syncScale) scale = reader.ReadVector3(); } // delta else @@ -286,12 +285,12 @@ public override void OnDeserialize(NetworkReader reader, bool initialState) // handle depending on server / client / host. // server has priority for host mode. - if (isServer) OnClientToServerSync(position, rotation, scale); + if (isServer) OnClientToServerSync(position, rotation, scale); else if (isClient) OnServerToClientSync(position, rotation, scale); // save deserialized as 'last' for next delta compression if (syncPosition) Compression.ScaleToLong(position.Value, positionPrecision, out lastDeserializedPosition); - if (syncScale) Compression.ScaleToLong(scale.Value, scalePrecision, out lastDeserializedScale); + if (syncScale) Compression.ScaleToLong(scale.Value, scalePrecision, out lastDeserializedScale); } // sync //////////////////////////////////////////////////////////////// @@ -307,20 +306,24 @@ protected virtual void OnClientToServerSync(Vector3? position, Quaternion? rotat // 'only sync on change' needs a correction on every new move sequence. if (onlySyncOnChange && - NeedsCorrection(serverSnapshots, connectionToClient.remoteTimeStamp, NetworkServer.sendInterval, onlySyncOnChangeCorrectionMultiplier)) + NeedsCorrection(serverSnapshots, connectionToClient.remoteTimeStamp, NetworkServer.sendInterval * sendIntervalMultiplier, onlySyncOnChangeCorrectionMultiplier)) { RewriteHistory( serverSnapshots, connectionToClient.remoteTimeStamp, - NetworkTime.localTime, // arrival remote timestamp. NOT remote timeline. - NetworkServer.sendInterval, // Unity 2019 doesn't have timeAsDouble yet - target.localPosition, - target.localRotation, - target.localScale); - // Debug.Log($"{name}: corrected history on server to fix initial stutter after not sending for a while."); + NetworkTime.localTime, // arrival remote timestamp. NOT remote timeline. + NetworkServer.sendInterval * sendIntervalMultiplier, // Unity 2019 doesn't have timeAsDouble yet + GetPosition(), + GetRotation(), + GetScale()); } - AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp, position, rotation, scale); + // add a small timeline offset to account for decoupled arrival of + // NetworkTime and NetworkTransform snapshots. + // needs to be sendInterval. half sendInterval doesn't solve it. + // https://github.com/MirrorNetworking/Mirror/issues/3427 + // remove this after LocalWorldState. + AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); } // server broadcasts sync message to all clients @@ -331,20 +334,24 @@ protected virtual void OnServerToClientSync(Vector3? position, Quaternion? rotat // 'only sync on change' needs a correction on every new move sequence. if (onlySyncOnChange && - NeedsCorrection(clientSnapshots, NetworkClient.connection.remoteTimeStamp, NetworkClient.sendInterval, onlySyncOnChangeCorrectionMultiplier)) + NeedsCorrection(clientSnapshots, NetworkClient.connection.remoteTimeStamp, NetworkClient.sendInterval * sendIntervalMultiplier, onlySyncOnChangeCorrectionMultiplier)) { RewriteHistory( clientSnapshots, - NetworkClient.connection.remoteTimeStamp, // arrival remote timestamp. NOT remote timeline. - NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet - NetworkClient.sendInterval, - target.localPosition, - target.localRotation, - target.localScale); - // Debug.Log($"{name}: corrected history on client to fix initial stutter after not sending for a while."); + NetworkClient.connection.remoteTimeStamp, // arrival remote timestamp. NOT remote timeline. + NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet + NetworkClient.sendInterval * sendIntervalMultiplier, + GetPosition(), + GetRotation(), + GetScale()); } - AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp, position, rotation, scale); + // add a small timeline offset to account for decoupled arrival of + // NetworkTime and NetworkTransform snapshots. + // needs to be sendInterval. half sendInterval doesn't solve it. + // https://github.com/MirrorNetworking/Mirror/issues/3427 + // remove this after LocalWorldState. + AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); } // only sync on change ///////////////////////////////////////////////// @@ -380,25 +387,35 @@ static void RewriteHistory( // insert a fake one at where we used to be, // 'sendInterval' behind the new one. - SnapshotInterpolation.InsertIfNotExists(snapshots, new TransformSnapshot( - remoteTimeStamp - sendInterval, // arrival remote timestamp. NOT remote time. - localTime - sendInterval, // Unity 2019 doesn't have timeAsDouble yet - position, - rotation, - scale - )); + SnapshotInterpolation.InsertIfNotExists( + snapshots, + NetworkClient.snapshotSettings.bufferLimit, + new TransformSnapshot( + remoteTimeStamp - sendInterval, // arrival remote timestamp. NOT remote time. + localTime - sendInterval, // Unity 2019 doesn't have timeAsDouble yet + position, + rotation, + scale + ) + ); } - public override void Reset() + // reset state for next session. + // do not ever call this during a session (i.e. after teleport). + // calling this will break delta compression. + public override void ResetState() { - base.Reset(); + base.ResetState(); // reset delta - lastSerializedPosition = Vector3Long.zero; + lastSerializedPosition = Vector3Long.zero; lastDeserializedPosition = Vector3Long.zero; - lastSerializedScale = Vector3Long.zero; + lastSerializedScale = Vector3Long.zero; lastDeserializedScale = Vector3Long.zero; + + // reset 'last' for delta too + last = new TransformSnapshot(0, 0, Vector3.zero, Quaternion.identity, Vector3.zero); } } } diff --git a/Assets/Mirror/Components/NetworkTransformReliable/NetworkTransformReliable.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs.meta similarity index 100% rename from Assets/Mirror/Components/NetworkTransformReliable/NetworkTransformReliable.cs.meta rename to Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs.meta diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs new file mode 100644 index 0000000..ab3b2d7 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs @@ -0,0 +1,679 @@ +// NetworkTransform V2 by mischa (2021-07) +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/Network Transform (Unreliable)")] + public class NetworkTransformUnreliable : NetworkTransformBase + { + uint sendIntervalCounter = 0; + double lastSendIntervalTime = double.MinValue; + + [Header("Additional Settings")] + // Testing under really bad network conditions, 2%-5% packet loss and 250-1200ms ping, 5 proved to eliminate any twitching, however this should not be the default as it is a rare case Developers may want to cover. + [Tooltip("How much time, as a multiple of send interval, has passed before clearing buffers.\nA larger buffer means more delay, but results in smoother movement.\nExample: 1 for faster responses minimal smoothing, 5 covers bad pings but has noticable delay, 3 is recommended for balanced results,.")] + public float bufferResetMultiplier = 3; + [Tooltip("Detect and send only changed data, such as Position X and Z, not the full Vector3 of X Y Z. Lowers network data at cost of extra calculations.")] + public bool changedDetection = true; + + [Header("Sensitivity"), Tooltip("Sensitivity of changes needed before an updated state is sent over the network")] + public float positionSensitivity = 0.01f; + public float rotationSensitivity = 0.01f; + public float scaleSensitivity = 0.01f; + + protected bool positionChanged; + protected bool rotationChanged; + protected bool scaleChanged; + + // Used to store last sent snapshots + protected TransformSnapshot lastSnapshot; + protected bool cachedSnapshotComparison; + protected Changed cachedChangedComparison; + protected bool hasSentUnchangedPosition; + + // update ////////////////////////////////////////////////////////////// + // Update applies interpolation + void Update() + { + if (isServer) UpdateServerInterpolation(); + // for all other clients (and for local player if !authority), + // we need to apply snapshots from the buffer. + // 'else if' because host mode shouldn't interpolate client + else if (isClient && !IsClientWithAuthority) UpdateClientInterpolation(); + } + + // LateUpdate broadcasts. + // movement scripts may change positions in Update. + // use LateUpdate to ensure changes are detected in the same frame. + // otherwise this may run before user update, delaying detection until next frame. + // this could cause visible jitter. + void LateUpdate() + { + // if server then always sync to others. + if (isServer) UpdateServerBroadcast(); + // client authority, and local player (= allowed to move myself)? + // 'else if' because host mode shouldn't send anything to server. + // it is the server. don't overwrite anything there. + else if (isClient && IsClientWithAuthority) UpdateClientBroadcast(); + } + + protected virtual void CheckLastSendTime() + { + // We check interval every frame, and then send if interval is reached. + // So by the time sendIntervalCounter == sendIntervalMultiplier, data is sent, + // thus we reset the counter here. + // This fixes previous issue of, if sendIntervalMultiplier = 1, we send every frame, + // because intervalCounter is always = 1 in the previous version. + + // Changing == to >= https://github.com/MirrorNetworking/Mirror/issues/3571 + + if (sendIntervalCounter >= sendIntervalMultiplier) + sendIntervalCounter = 0; + + // timeAsDouble not available in older Unity versions. + if (AccurateInterval.Elapsed(NetworkTime.localTime, NetworkServer.sendInterval, ref lastSendIntervalTime)) + sendIntervalCounter++; + } + + void UpdateServerBroadcast() + { + // 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. + // TODO send same time that NetworkServer sends time snapshot? + CheckLastSendTime(); + + if (sendIntervalCounter == sendIntervalMultiplier && // same interval as time interpolation! + (syncDirection == SyncDirection.ServerToClient || IsClientWithAuthority)) + { + // send snapshot without timestamp. + // receiver gets it from batch timestamp to save bandwidth. + TransformSnapshot snapshot = Construct(); + + if (changedDetection) + { + cachedChangedComparison = CompareChangedSnapshots(snapshot); + + if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; } + + SyncData syncData = new SyncData(cachedChangedComparison, snapshot); + + RpcServerToClientSync(syncData); + + if (cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) + { + hasSentUnchangedPosition = true; + } + else + { + hasSentUnchangedPosition = false; + UpdateLastSentSnapshot(cachedChangedComparison, snapshot); + } + } + else + { + cachedSnapshotComparison = CompareSnapshots(snapshot); + if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; } + + if (compressRotation) + { + RpcServerToClientSyncCompressRotation( + // only sync what the user wants to sync + syncPosition && positionChanged ? snapshot.position : default(Vector3?), + syncRotation && rotationChanged ? Compression.CompressQuaternion(snapshot.rotation) : default(uint?), + syncScale && scaleChanged ? snapshot.scale : default(Vector3?) + ); + } + else + { + RpcServerToClientSync( + // only sync what the user wants to sync + syncPosition && positionChanged ? snapshot.position : default(Vector3?), + syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?), + syncScale && scaleChanged ? snapshot.scale : default(Vector3?) + ); + } + + if (cachedSnapshotComparison) + { + hasSentUnchangedPosition = true; + } + else + { + hasSentUnchangedPosition = false; + + // Fixes https://github.com/MirrorNetworking/Mirror/issues/3572 + // This also fixes https://github.com/MirrorNetworking/Mirror/issues/3573 + // with the exception of Quaternion.Angle sensitivity has to be > 0.16. + // Unity issue, we are leaving it as is. + + if (positionChanged) lastSnapshot.position = snapshot.position; + if (rotationChanged) lastSnapshot.rotation = snapshot.rotation; + if (positionChanged) lastSnapshot.scale = snapshot.scale; + } + } + } + } + + void UpdateServerInterpolation() + { + // 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. + // -> connectionToClient is briefly null after scene changes: + // https://github.com/MirrorNetworking/Mirror/issues/3329 + if (syncDirection == SyncDirection.ClientToServer && + connectionToClient != null && + !isOwned) + { + if (serverSnapshots.Count == 0) return; + + // step the transform interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + serverSnapshots, + connectionToClient.remoteTimeline, + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + Apply(computed, to); + } + } + + void UpdateClientBroadcast() + { + // https://github.com/vis2k/Mirror/pull/2992/ + if (!NetworkClient.ready) return; + + // 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. + CheckLastSendTime(); + if (sendIntervalCounter == sendIntervalMultiplier) // same interval as time interpolation! + { + // send snapshot without timestamp. + // receiver gets it from batch timestamp to save bandwidth. + TransformSnapshot snapshot = Construct(); + + if (changedDetection) + { + cachedChangedComparison = CompareChangedSnapshots(snapshot); + + if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; } + + SyncData syncData = new SyncData(cachedChangedComparison, snapshot); + + CmdClientToServerSync(syncData); + + if (cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) + { + hasSentUnchangedPosition = true; + } + else + { + hasSentUnchangedPosition = false; + UpdateLastSentSnapshot(cachedChangedComparison, snapshot); + } + } + else + { + cachedSnapshotComparison = CompareSnapshots(snapshot); + if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; } + + if (compressRotation) + { + CmdClientToServerSyncCompressRotation( + // only sync what the user wants to sync + syncPosition && positionChanged ? snapshot.position : default(Vector3?), + syncRotation && rotationChanged ? Compression.CompressQuaternion(snapshot.rotation) : default(uint?), + syncScale && scaleChanged ? snapshot.scale : default(Vector3?) + ); + } + else + { + CmdClientToServerSync( + // only sync what the user wants to sync + syncPosition && positionChanged ? snapshot.position : default(Vector3?), + syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?), + syncScale && scaleChanged ? snapshot.scale : default(Vector3?) + ); + } + + if (cachedSnapshotComparison) + { + hasSentUnchangedPosition = true; + } + else + { + hasSentUnchangedPosition = false; + + // Fixes https://github.com/MirrorNetworking/Mirror/issues/3572 + // This also fixes https://github.com/MirrorNetworking/Mirror/issues/3573 + // with the exception of Quaternion.Angle sensitivity has to be > 0.16. + // Unity issue, we are leaving it as is. + if (positionChanged) lastSnapshot.position = snapshot.position; + if (rotationChanged) lastSnapshot.rotation = snapshot.rotation; + if (positionChanged) lastSnapshot.scale = snapshot.scale; + } + } + } + } + + void UpdateClientInterpolation() + { + // only while we have snapshots + if (clientSnapshots.Count == 0) return; + + // step the interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + clientSnapshots, + NetworkTime.time, // == NetworkClient.localTimeline from snapshot interpolation + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + Apply(computed, to); + } + + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + // sync target component's position on spawn. + // fixes https://github.com/vis2k/Mirror/pull/3051/ + // (Spawn message wouldn't sync NTChild positions either) + if (initialState) + { + if (syncPosition) writer.WriteVector3(GetPosition()); + if (syncRotation) writer.WriteQuaternion(GetRotation()); + if (syncScale) writer.WriteVector3(GetScale()); + } + } + + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + // sync target component's position on spawn. + // fixes https://github.com/vis2k/Mirror/pull/3051/ + // (Spawn message wouldn't sync NTChild positions either) + if (initialState) + { + if (syncPosition) SetPosition(reader.ReadVector3()); + if (syncRotation) SetRotation(reader.ReadQuaternion()); + if (syncScale) SetScale(reader.ReadVector3()); + } + } + + // Returns true if position, rotation AND scale are unchanged, within given sensitivity range. + protected virtual bool CompareSnapshots(TransformSnapshot currentSnapshot) + { + positionChanged = Vector3.SqrMagnitude(lastSnapshot.position - currentSnapshot.position) > positionSensitivity * positionSensitivity; + rotationChanged = Quaternion.Angle(lastSnapshot.rotation, currentSnapshot.rotation) > rotationSensitivity; + scaleChanged = Vector3.SqrMagnitude(lastSnapshot.scale - currentSnapshot.scale) > scaleSensitivity * scaleSensitivity; + + return (!positionChanged && !rotationChanged && !scaleChanged); + } + + // 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 (syncDirection == SyncDirection.ClientToServer) + RpcServerToClientSync(position, rotation, scale); + } + + // cmd ///////////////////////////////////////////////////////////////// + // only unreliable. see comment above of this file. + [Command(channel = Channels.Unreliable)] + void CmdClientToServerSyncCompressRotation(Vector3? position, uint? rotation, Vector3? scale) + { + // A fix to not apply current interpolated GetRotation when receiving null/unchanged value, instead use last sent snapshot rotation. + Quaternion newRotation; + if (rotation.HasValue) + { + newRotation = Compression.DecompressQuaternion((uint)rotation); + } + else + { + newRotation = serverSnapshots.Count > 0 ? serverSnapshots.Values[serverSnapshots.Count - 1].rotation : GetRotation(); + } + OnClientToServerSync(position, newRotation, scale); + //For client authority, immediately pass on the client snapshot to all other + //clients instead of waiting for server to send its snapshots. + if (syncDirection == SyncDirection.ClientToServer) + RpcServerToClientSyncCompressRotation(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 (syncDirection != SyncDirection.ClientToServer) return; + + // protect against ever growing buffer size attacks + if (serverSnapshots.Count >= connectionToClient.snapshotBufferSizeLimit) return; + + // only player owned objects (with a connection) can send to + // server. we can get the timestamp from the connection. + double timestamp = connectionToClient.remoteTimeStamp; + + if (onlySyncOnChange) + { + double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkClient.sendInterval; + + if (serverSnapshots.Count > 0 && serverSnapshots.Values[serverSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) + ResetState(); + } + + AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); + } + + // 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); + + // rpc ///////////////////////////////////////////////////////////////// + // only unreliable. see comment above of this file. + [ClientRpc(channel = Channels.Unreliable)] + void RpcServerToClientSyncCompressRotation(Vector3? position, uint? rotation, Vector3? scale) + { + // A fix to not apply current interpolated GetRotation when receiving null/unchanged value, instead use last sent snapshot rotation. + Quaternion newRotation; + if (rotation.HasValue) + { + newRotation = Compression.DecompressQuaternion((uint)rotation); + } + else + { + newRotation = clientSnapshots.Count > 0 ? clientSnapshots.Values[clientSnapshots.Count - 1].rotation : GetRotation(); + } + OnServerToClientSync(position, newRotation, 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; + + // 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; + + if (onlySyncOnChange) + { + double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkServer.sendInterval; + + if (clientSnapshots.Count > 0 && clientSnapshots.Values[clientSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) + ResetState(); + } + + AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); + } + + protected virtual void UpdateLastSentSnapshot(Changed change, TransformSnapshot currentSnapshot) + { + if (change == Changed.None || change == Changed.CompressRot) return; + + if ((change & Changed.PosX) > 0) lastSnapshot.position.x = currentSnapshot.position.x; + if ((change & Changed.PosY) > 0) lastSnapshot.position.y = currentSnapshot.position.y; + if ((change & Changed.PosZ) > 0) lastSnapshot.position.z = currentSnapshot.position.z; + + if (compressRotation) + { + if ((change & Changed.Rot) > 0) lastSnapshot.rotation = currentSnapshot.rotation; + } + else + { + Vector3 newRotation; + newRotation.x = (change & Changed.RotX) > 0 ? currentSnapshot.rotation.eulerAngles.x : lastSnapshot.rotation.eulerAngles.x; + newRotation.y = (change & Changed.RotY) > 0 ? currentSnapshot.rotation.eulerAngles.y : lastSnapshot.rotation.eulerAngles.y; + newRotation.z = (change & Changed.RotZ) > 0 ? currentSnapshot.rotation.eulerAngles.z : lastSnapshot.rotation.eulerAngles.z; + + lastSnapshot.rotation = Quaternion.Euler(newRotation); + } + + if ((change & Changed.Scale) > 0) lastSnapshot.scale = currentSnapshot.scale; + } + + // Returns true if position, rotation AND scale are unchanged, within given sensitivity range. + // Note the sensitivity comparison are different for pos, rot and scale. + protected virtual Changed CompareChangedSnapshots(TransformSnapshot currentSnapshot) + { + Changed change = Changed.None; + + if (syncPosition) + { + bool positionChanged = Vector3.SqrMagnitude(lastSnapshot.position - currentSnapshot.position) > positionSensitivity * positionSensitivity; + if (positionChanged) + { + if (Mathf.Abs(lastSnapshot.position.x - currentSnapshot.position.x) > positionSensitivity) change |= Changed.PosX; + if (Mathf.Abs(lastSnapshot.position.y - currentSnapshot.position.y) > positionSensitivity) change |= Changed.PosY; + if (Mathf.Abs(lastSnapshot.position.z - currentSnapshot.position.z) > positionSensitivity) change |= Changed.PosZ; + } + } + + if (syncRotation) + { + if (compressRotation) + { + bool rotationChanged = Quaternion.Angle(lastSnapshot.rotation, currentSnapshot.rotation) > rotationSensitivity; + if (rotationChanged) + { + // Here we set all Rot enum flags, to tell us if there was a change in rotation + // when using compression. If no change, we don't write the compressed Quat. + change |= Changed.CompressRot; + change |= Changed.Rot; + } + else + { + change |= Changed.CompressRot; + } + } + else + { + if (Mathf.Abs(lastSnapshot.rotation.eulerAngles.x - currentSnapshot.rotation.eulerAngles.x) > rotationSensitivity) change |= Changed.RotX; + if (Mathf.Abs(lastSnapshot.rotation.eulerAngles.y - currentSnapshot.rotation.eulerAngles.y) > rotationSensitivity) change |= Changed.RotY; + if (Mathf.Abs(lastSnapshot.rotation.eulerAngles.z - currentSnapshot.rotation.eulerAngles.z) > rotationSensitivity) change |= Changed.RotZ; + } + } + + if (syncScale) + { + if (Vector3.SqrMagnitude(lastSnapshot.scale - currentSnapshot.scale) > scaleSensitivity * scaleSensitivity) change |= Changed.Scale; + } + + return change; + } + + [Command(channel = Channels.Unreliable)] + void CmdClientToServerSync(SyncData syncData) + { + OnClientToServerSync(syncData); + //For client authority, immediately pass on the client snapshot to all other + //clients instead of waiting for server to send its snapshots. + if (syncDirection == SyncDirection.ClientToServer) + RpcServerToClientSync(syncData); + } + + protected virtual void OnClientToServerSync(SyncData syncData) + { + // only apply if in client authority mode + if (syncDirection != SyncDirection.ClientToServer) return; + + // protect against ever growing buffer size attacks + if (serverSnapshots.Count >= connectionToClient.snapshotBufferSizeLimit) return; + + // only player owned objects (with a connection) can send to + // server. we can get the timestamp from the connection. + double timestamp = connectionToClient.remoteTimeStamp; + + if (onlySyncOnChange) + { + double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkClient.sendInterval; + + if (serverSnapshots.Count > 0 && serverSnapshots.Values[serverSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) + ResetState(); + } + + UpdateSyncData(ref syncData, serverSnapshots); + + AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + timeStampAdjustment + offset, syncData.position, syncData.quatRotation, syncData.scale); + } + + + [ClientRpc(channel = Channels.Unreliable)] + void RpcServerToClientSync(SyncData syncData) => + OnServerToClientSync(syncData); + + protected virtual void OnServerToClientSync(SyncData syncData) + { + // 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; + + // 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; + + if (onlySyncOnChange) + { + double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkServer.sendInterval; + + if (clientSnapshots.Count > 0 && clientSnapshots.Values[clientSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) + ResetState(); + } + + UpdateSyncData(ref syncData, clientSnapshots); + + AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + timeStampAdjustment + offset, syncData.position, syncData.quatRotation, syncData.scale); + } + + protected virtual void UpdateSyncData(ref SyncData syncData, SortedList snapshots) + { + if (syncData.changedDataByte == Changed.None || syncData.changedDataByte == Changed.CompressRot) + { + syncData.position = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position : GetPosition(); + syncData.quatRotation = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation : GetRotation(); + syncData.scale = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].scale : GetScale(); + } + else + { + // Just going to update these without checking if syncposition or not, + // because if not syncing position, NT will not apply any position data + // to the target during Apply(). + + syncData.position.x = (syncData.changedDataByte & Changed.PosX) > 0 ? syncData.position.x : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position.x : GetPosition().x); + syncData.position.y = (syncData.changedDataByte & Changed.PosY) > 0 ? syncData.position.y : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position.y : GetPosition().y); + syncData.position.z = (syncData.changedDataByte & Changed.PosZ) > 0 ? syncData.position.z : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position.z : GetPosition().z); + + // If compressRot is true, we already have the Quat in syncdata. + if ((syncData.changedDataByte & Changed.CompressRot) == 0) + { + syncData.vecRotation.x = (syncData.changedDataByte & Changed.RotX) > 0 ? syncData.vecRotation.x : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation.eulerAngles.x : GetRotation().eulerAngles.x); + syncData.vecRotation.y = (syncData.changedDataByte & Changed.RotY) > 0 ? syncData.vecRotation.y : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation.eulerAngles.y : GetRotation().eulerAngles.y); ; + syncData.vecRotation.z = (syncData.changedDataByte & Changed.RotZ) > 0 ? syncData.vecRotation.z : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation.eulerAngles.z : GetRotation().eulerAngles.z); + + syncData.quatRotation = Quaternion.Euler(syncData.vecRotation); + } + else + { + syncData.quatRotation = (syncData.changedDataByte & Changed.Rot) > 0 ? syncData.quatRotation : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation : GetRotation()); + } + + syncData.scale = (syncData.changedDataByte & Changed.Scale) > 0 ? syncData.scale : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].scale : GetScale()); + } + } + + // This is to extract position/rotation/scale data from payload. Override + // Construct and Deconstruct if you are implementing a different SyncData logic. + // Note however that snapshot interpolation still requires the basic 3 data + // position, rotation and scale, which are computed from here. + protected virtual void DeconstructSyncData(System.ArraySegment receivedPayload, out byte? changedFlagData, out Vector3? position, out Quaternion? rotation, out Vector3? scale) + { + using (NetworkReaderPooled reader = NetworkReaderPool.Get(receivedPayload)) + { + SyncData syncData = reader.Read(); + changedFlagData = (byte)syncData.changedDataByte; + position = syncData.position; + rotation = syncData.quatRotation; + scale = syncData.scale; + } + } + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta new file mode 100644 index 0000000..3a4a75a --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a553cb17010b2403e8523b558bffbc14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkTransformUnreliable/TransformSnapshot.cs b/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs similarity index 92% rename from Assets/Mirror/Components/NetworkTransformUnreliable/TransformSnapshot.cs rename to Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs index 912b10d..01b863c 100644 --- a/Assets/Mirror/Components/NetworkTransformUnreliable/TransformSnapshot.cs +++ b/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs @@ -29,9 +29,9 @@ public struct TransformSnapshot : Snapshot // used to know if the first two snapshots are old enough to start. public double localTime { get; set; } - public Vector3 position; + public Vector3 position; public Quaternion rotation; - public Vector3 scale; + public Vector3 scale; public TransformSnapshot(double remoteTime, double localTime, Vector3 position, Quaternion rotation, Vector3 scale) { @@ -61,5 +61,8 @@ public static TransformSnapshot Interpolate(TransformSnapshot from, TransformSna Vector3.LerpUnclamped(from.scale, to.scale, (float)t) ); } + + public override string ToString() => + $"TransformSnapshot(remoteTime={remoteTime:F2}, localTime={localTime:F2}, pos={position}, rot={rotation}, scale={scale})"; } } diff --git a/Assets/Mirror/Components/NetworkTransformUnreliable/TransformSnapshot.cs.meta b/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs.meta similarity index 100% rename from Assets/Mirror/Components/NetworkTransformUnreliable/TransformSnapshot.cs.meta rename to Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs.meta diff --git a/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs new file mode 100644 index 0000000..9b6d51c --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs @@ -0,0 +1,156 @@ +using UnityEngine; +using System; +using Mirror; + +namespace Mirror +{ + [Serializable] + public struct SyncData + { + public Changed changedDataByte; + public Vector3 position; + public Quaternion quatRotation; + public Vector3 vecRotation; + public Vector3 scale; + + public SyncData(Changed _dataChangedByte, Vector3 _position, Quaternion _rotation, Vector3 _scale) + { + this.changedDataByte = _dataChangedByte; + this.position = _position; + this.quatRotation = _rotation; + this.vecRotation = quatRotation.eulerAngles; + this.scale = _scale; + } + + public SyncData(Changed _dataChangedByte, TransformSnapshot _snapshot) + { + this.changedDataByte = _dataChangedByte; + this.position = _snapshot.position; + this.quatRotation = _snapshot.rotation; + this.vecRotation = quatRotation.eulerAngles; + this.scale = _snapshot.scale; + } + + public SyncData(Changed _dataChangedByte, Vector3 _position, Vector3 _vecRotation, Vector3 _scale) + { + this.changedDataByte = _dataChangedByte; + this.position = _position; + this.vecRotation = _vecRotation; + this.quatRotation = Quaternion.Euler(vecRotation); + this.scale = _scale; + } + } + + [Flags] + public enum Changed : byte + { + None = 0, + PosX = 1 << 0, + PosY = 1 << 1, + PosZ = 1 << 2, + CompressRot = 1 << 3, + RotX = 1 << 4, + RotY = 1 << 5, + RotZ = 1 << 6, + Scale = 1 << 7, + + Pos = PosX | PosY | PosZ, + Rot = RotX | RotY | RotZ + } + + + public static class SyncDataReaderWriter + { + public static void WriteSyncData(this NetworkWriter writer, SyncData syncData) + { + writer.WriteByte((byte)syncData.changedDataByte); + + // Write position + if ((syncData.changedDataByte & Changed.PosX) > 0) + { + writer.WriteFloat(syncData.position.x); + } + + if ((syncData.changedDataByte & Changed.PosY) > 0) + { + writer.WriteFloat(syncData.position.y); + } + + if ((syncData.changedDataByte & Changed.PosZ) > 0) + { + writer.WriteFloat(syncData.position.z); + } + + // Write rotation + if ((syncData.changedDataByte & Changed.CompressRot) > 0) + { + if((syncData.changedDataByte & Changed.Rot) > 0) + { + writer.WriteUInt(Compression.CompressQuaternion(syncData.quatRotation)); + } + } + else + { + if ((syncData.changedDataByte & Changed.RotX) > 0) + { + writer.WriteFloat(syncData.quatRotation.eulerAngles.x); + } + + if ((syncData.changedDataByte & Changed.RotY) > 0) + { + writer.WriteFloat(syncData.quatRotation.eulerAngles.y); + } + + if ((syncData.changedDataByte & Changed.RotZ) > 0) + { + writer.WriteFloat(syncData.quatRotation.eulerAngles.z); + } + } + + // Write scale + if ((syncData.changedDataByte & Changed.Scale) > 0) + { + writer.WriteVector3(syncData.scale); + } + } + + public static SyncData ReadSyncData(this NetworkReader reader) + { + Changed changedData = (Changed)reader.ReadByte(); + + // If we have nothing to read here, let's say because posX is unchanged, then we can write anything + // for now, but in the NT, we will need to check changedData again, to put the right values of the axis + // back. We don't have it here. + + Vector3 position = + new Vector3( + (changedData & Changed.PosX) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.PosY) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.PosZ) > 0 ? reader.ReadFloat() : 0 + ); + + Vector3 vecRotation = new Vector3(); + Quaternion quatRotation = new Quaternion(); + + if ((changedData & Changed.CompressRot) > 0) + { + quatRotation = (changedData & Changed.RotX) > 0 ? Compression.DecompressQuaternion(reader.ReadUInt()) : new Quaternion(); + } + else + { + vecRotation = + new Vector3( + (changedData & Changed.RotX) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.RotY) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.RotZ) > 0 ? reader.ReadFloat() : 0 + ); + } + + Vector3 scale = (changedData & Changed.Scale) == Changed.Scale ? reader.ReadVector3() : new Vector3(); + + SyncData _syncData = (changedData & Changed.CompressRot) > 0 ? new SyncData(changedData, position, quatRotation, scale) : new SyncData(changedData, position, vecRotation, scale); + + return _syncData; + } + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta new file mode 100644 index 0000000..15bb004 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a1c0832ca88e749ff96fe04cebb617ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs b/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs deleted file mode 100644 index 35a9154..0000000 --- a/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs +++ /dev/null @@ -1,359 +0,0 @@ -// NetworkTransform V2 by mischa (2021-07) -// comment out the below line to quickly revert the onlySyncOnChange feature -#define onlySyncOnChange_BANDWIDTH_SAVING -using UnityEngine; - -namespace Mirror -{ - [AddComponentMenu("Network/Network Transform (Unreliable)")] - public class NetworkTransform : NetworkTransformBase - { - // only sync when changed hack ///////////////////////////////////////// -#if onlySyncOnChange_BANDWIDTH_SAVING - [Header("Sync Only If Changed")] - [Tooltip("When true, changes are not sent unless greater than sensitivity values below.")] - public bool onlySyncOnChange = true; - - // 3 was original, but testing under really bad network conditions, 2%-5% packet loss and 250-1200ms ping, 5 proved to eliminate any twitching. - [Tooltip("How much time, as a multiple of send interval, has passed before clearing buffers.")] - public float bufferResetMultiplier = 5; - - [Header("Sensitivity"), Tooltip("Sensitivity of changes needed before an updated state is sent over the network")] - public float positionSensitivity = 0.01f; - public float rotationSensitivity = 0.01f; - public float scaleSensitivity = 0.01f; - - protected bool positionChanged; - protected bool rotationChanged; - protected bool scaleChanged; - - // Used to store last sent snapshots - protected TransformSnapshot lastSnapshot; - protected bool cachedSnapshotComparison; - protected bool hasSentUnchangedPosition; -#endif - - double lastClientSendTime; - double lastServerSendTime; - - // update ////////////////////////////////////////////////////////////// - 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(); - } - - 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. - // TODO send same time that NetworkServer sends time snapshot? - if (NetworkTime.localTime >= lastServerSendTime + NetworkServer.sendInterval && // same interval as time interpolation! - (syncDirection == SyncDirection.ServerToClient || IsClientWithAuthority)) - { - // send snapshot without timestamp. - // receiver gets it from batch timestamp to save bandwidth. - TransformSnapshot snapshot = Construct(); -#if onlySyncOnChange_BANDWIDTH_SAVING - cachedSnapshotComparison = CompareSnapshots(snapshot); - if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; } -#endif - -#if onlySyncOnChange_BANDWIDTH_SAVING - RpcServerToClientSync( - // only sync what the user wants to sync - syncPosition && positionChanged ? snapshot.position : default(Vector3?), - syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?), - syncScale && scaleChanged ? snapshot.scale : default(Vector3?) - ); -#else - RpcServerToClientSync( - // only sync what the user wants to sync - syncPosition ? snapshot.position : default(Vector3?), - syncRotation ? snapshot.rotation : default(Quaternion?), - syncScale ? snapshot.scale : default(Vector3?) - ); -#endif - - lastServerSendTime = NetworkTime.localTime; -#if onlySyncOnChange_BANDWIDTH_SAVING - if (cachedSnapshotComparison) - { - hasSentUnchangedPosition = true; - } - else - { - hasSentUnchangedPosition = false; - lastSnapshot = snapshot; - } -#endif - } - - // 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. - // -> connectionToClient is briefly null after scene changes: - // https://github.com/MirrorNetworking/Mirror/issues/3329 - if (syncDirection == SyncDirection.ClientToServer && - connectionToClient != null && - !isOwned) - { - if (serverSnapshots.Count > 0) - { - // step the transform interpolation without touching time. - // NetworkClient is responsible for time globally. - SnapshotInterpolation.StepInterpolation( - serverSnapshots, - connectionToClient.remoteTimeline, - out TransformSnapshot from, - out TransformSnapshot to, - out double t); - - // interpolate & apply - TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); - Apply(computed); - } - } - } - - void UpdateClient() - { - // client authority, and local player (= allowed to move myself)? - if (IsClientWithAuthority) - { - // https://github.com/vis2k/Mirror/pull/2992/ - if (!NetworkClient.ready) return; - - // 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 + NetworkClient.sendInterval) // same interval as time interpolation! - { - // send snapshot without timestamp. - // receiver gets it from batch timestamp to save bandwidth. - TransformSnapshot snapshot = Construct(); -#if onlySyncOnChange_BANDWIDTH_SAVING - cachedSnapshotComparison = CompareSnapshots(snapshot); - if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; } -#endif - -#if onlySyncOnChange_BANDWIDTH_SAVING - CmdClientToServerSync( - // only sync what the user wants to sync - syncPosition && positionChanged ? snapshot.position : default(Vector3?), - syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?), - syncScale && scaleChanged ? snapshot.scale : default(Vector3?) - ); -#else - CmdClientToServerSync( - // only sync what the user wants to sync - syncPosition ? snapshot.position : default(Vector3?), - syncRotation ? snapshot.rotation : default(Quaternion?), - syncScale ? snapshot.scale : default(Vector3?) - ); -#endif - - lastClientSendTime = NetworkTime.localTime; -#if onlySyncOnChange_BANDWIDTH_SAVING - if (cachedSnapshotComparison) - { - hasSentUnchangedPosition = true; - } - else - { - hasSentUnchangedPosition = false; - lastSnapshot = snapshot; - } -#endif - } - } - // for all other clients (and for local player if !authority), - // we need to apply snapshots from the buffer - else - { - // only while we have snapshots - if (clientSnapshots.Count > 0) - { - // step the interpolation without touching time. - // NetworkClient is responsible for time globally. - SnapshotInterpolation.StepInterpolation( - clientSnapshots, - NetworkTime.time, // == NetworkClient.localTimeline from snapshot interpolation - out TransformSnapshot from, - out TransformSnapshot to, - out double t); - - // interpolate & apply - TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); - Apply(computed); - } - } - } - - public override void OnSerialize(NetworkWriter writer, bool initialState) - { - // sync target component's position on spawn. - // fixes https://github.com/vis2k/Mirror/pull/3051/ - // (Spawn message wouldn't sync NTChild positions either) - if (initialState) - { - if (syncPosition) writer.WriteVector3(target.localPosition); - if (syncRotation) writer.WriteQuaternion(target.localRotation); - if (syncScale) writer.WriteVector3(target.localScale); - } - } - - public override void OnDeserialize(NetworkReader reader, bool initialState) - { - // sync target component's position on spawn. - // fixes https://github.com/vis2k/Mirror/pull/3051/ - // (Spawn message wouldn't sync NTChild positions either) - if (initialState) - { - if (syncPosition) target.localPosition = reader.ReadVector3(); - if (syncRotation) target.localRotation = reader.ReadQuaternion(); - if (syncScale) target.localScale = reader.ReadVector3(); - } - } - -#if onlySyncOnChange_BANDWIDTH_SAVING - // Returns true if position, rotation AND scale are unchanged, within given sensitivity range. - protected virtual bool CompareSnapshots(TransformSnapshot currentSnapshot) - { - positionChanged = Vector3.SqrMagnitude(lastSnapshot.position - currentSnapshot.position) > positionSensitivity * positionSensitivity; - rotationChanged = Quaternion.Angle(lastSnapshot.rotation, currentSnapshot.rotation) > rotationSensitivity; - scaleChanged = Vector3.SqrMagnitude(lastSnapshot.scale - currentSnapshot.scale) > scaleSensitivity * scaleSensitivity; - - return (!positionChanged && !rotationChanged && !scaleChanged); - } -#endif - // 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 (syncDirection == SyncDirection.ClientToServer) - { - 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 (syncDirection != SyncDirection.ClientToServer) return; - - // protect against ever growing buffer size attacks - if (serverSnapshots.Count >= connectionToClient.snapshotBufferSizeLimit) return; - - // only player owned objects (with a connection) can send to - // server. we can get the timestamp from the connection. - double timestamp = connectionToClient.remoteTimeStamp; -#if onlySyncOnChange_BANDWIDTH_SAVING - if (onlySyncOnChange) - { - double timeIntervalCheck = bufferResetMultiplier * NetworkClient.sendInterval; - - if (serverSnapshots.Count > 0 && serverSnapshots.Values[serverSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) - { - Reset(); - } - } -#endif - AddSnapshot(serverSnapshots, timestamp, position, rotation, scale); - } - - // 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; - - // 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; -#if onlySyncOnChange_BANDWIDTH_SAVING - if (onlySyncOnChange) - { - double timeIntervalCheck = bufferResetMultiplier * NetworkServer.sendInterval; - - if (clientSnapshots.Count > 0 && clientSnapshots.Values[clientSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) - { - Reset(); - } - } -#endif - AddSnapshot(clientSnapshots, timestamp, position, rotation, scale); - } - } -} diff --git a/Assets/Mirror/Components/PredictedRigidbody.meta b/Assets/Mirror/Components/PredictedRigidbody.meta new file mode 100644 index 0000000..3bd5cec --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 09cc6745984c453a8cfb4cf4244d2570 +timeCreated: 1693576410 \ No newline at end of file diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat similarity index 83% rename from Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat rename to Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat index 7ec88f5..ff29a73 100644 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat +++ b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat @@ -2,14 +2,18 @@ %TAG !u! tag:unity3d.com,2011: --- !u!21 &2100000 Material: - serializedVersion: 6 + serializedVersion: 8 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: StartPoint + m_Name: LocalGhostMaterial m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON + m_InvalidKeywords: [] m_LightmapFlags: 4 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 @@ -17,6 +21,7 @@ Material: stringTagMap: RenderType: Transparent disabledShaderPasses: [] + m_LockedProperties: m_SavedProperties: serializedVersion: 3 m_TexEnvs: @@ -56,23 +61,25 @@ Material: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} + m_Ints: [] m_Floats: - _BumpScale: 1 - _Cutoff: 0.5 - _DetailNormalMapScale: 1 - _DstBlend: 10 - _GlossMapScale: 1 - - _Glossiness: 1 - - _GlossyReflections: 0 + - _Glossiness: 0.92 + - _GlossyReflections: 1 - _Metallic: 0 - _Mode: 3 - _OcclusionStrength: 1 - _Parallax: 0.02 - _SmoothnessTextureChannel: 0 - - _SpecularHighlights: 0 + - _SpecularHighlights: 1 - _SrcBlend: 1 - _UVSec: 0 - _ZWrite: 0 m_Colors: - - _Color: {r: 1, g: 0.6236605, b: 0, a: 0.5372549} + - _Color: {r: 1, g: 0, b: 0.067070484, a: 0.15686275} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat.meta b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat.meta similarity index 79% rename from Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat.meta rename to Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat.meta index 1bfa547..bd5cfe5 100644 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat.meta +++ b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 38950807c6bf6454dbef567827b770b6 +guid: 411a48b4a197d4924bec3e3809bc9320 NativeFormatImporter: externalObjects: {} mainObjectFileID: 2100000 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs new file mode 100644 index 0000000..0fd5e6a --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs @@ -0,0 +1,997 @@ +// PredictedRigidbody which stores & indidvidually rewinds history per Rigidbody. +// +// This brings significant performance savings because: +// - if a scene has 1000 objects +// - and a player interacts with say 3 objects at a time +// - Physics.Simulate() would resimulate 1000 objects +// - where as this component only resimulates the 3 changed objects +// +// The downside is that history rewinding is done manually via Vector math, +// instead of real physics. It's not 100% correct - but it sure is fast! +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + public enum PredictionMode { Smooth, Fast } + + // [RequireComponent(typeof(Rigidbody))] <- RB is moved out at runtime, can't require it. + public class PredictedRigidbody : NetworkBehaviour + { + Transform tf; // this component is performance critical. cache .transform getter! + + // Prediction sometimes moves the Rigidbody to a ghost object. + // .predictedRigidbody is always kept up to date to wherever the RB is. + // other components should use this when accessing Rigidbody. + public Rigidbody predictedRigidbody; + Transform predictedRigidbodyTransform; // predictedRigidbody.transform for performance (Get/SetPositionAndRotation) + + Vector3 lastPosition; + + // motion smoothing happen on-demand, because it requires moving physics components to another GameObject. + // this only starts at a given velocity and ends when stopped moving. + // to avoid constant on/off/on effects, it also stays on for a minimum time. + [Header("Motion Smoothing")] + [Tooltip("Prediction supports two different modes: Smooth and Fast:\n\nSmooth: Physics are separated from the GameObject & applied in the background. Rendering smoothly follows the physics for perfectly smooth interpolation results. Much softer, can be even too soft where sharp collisions won't look as sharp (i.e. Billiard balls avoid the wall before even hitting it).\n\nFast: Physics remain on the GameObject and corrections are applied hard. Much faster since we don't need to update a separate GameObject, a bit harsher, more precise.")] + public PredictionMode mode = PredictionMode.Smooth; + [Tooltip("Smoothing via Ghost-following only happens on demand, while moving with a minimum velocity.")] + public float motionSmoothingVelocityThreshold = 0.1f; + float motionSmoothingVelocityThresholdSqr; // ² cached in Awake + public float motionSmoothingAngularVelocityThreshold = 5.0f; // Billiards demo: 0.1 is way too small, takes forever for IsMoving()==false + float motionSmoothingAngularVelocityThresholdSqr; // ² cached in Awake + public float motionSmoothingTimeTolerance = 0.5f; + double motionSmoothingLastMovedTime; + + // client keeps state history for correction & reconciliation. + // this needs to be a SortedList because we need to be able to insert inbetween. + // => RingBuffer: see prediction_ringbuffer_2 branch, but it's slower! + [Header("State History")] + public int stateHistoryLimit = 32; // 32 x 50 ms = 1.6 seconds is definitely enough + readonly SortedList stateHistory = new SortedList(); + public float recordInterval = 0.050f; + + [Tooltip("(Optional) performance optimization where FixedUpdate.RecordState() only inserts state into history if the state actually changed.\nThis is generally a good idea.")] + public bool onlyRecordChanges = true; + + [Tooltip("(Optional) performance optimization where received state is compared to the LAST recorded state first, before sampling the whole history.\n\nThis can save significant traversal overhead for idle objects with a tiny chance of missing corrections for objects which revisisted the same position in the recent history twice.")] + public bool compareLastFirst = true; + + [Header("Reconciliation")] + [Tooltip("Correction threshold in meters. For example, 0.1 means that if the client is off by more than 10cm, it gets corrected.")] + public double positionCorrectionThreshold = 0.10; + double positionCorrectionThresholdSqr; // ² cached in Awake + [Tooltip("Correction threshold in degrees. For example, 5 means that if the client is off by more than 5 degrees, it gets corrected.")] + public double rotationCorrectionThreshold = 5; + + [Tooltip("Applying server corrections one frame ahead gives much better results. We don't know why yet, so this is an option for now.")] + public bool oneFrameAhead = true; + + [Header("Smoothing")] + [Tooltip("Snap to the server state directly when velocity is < threshold. This is useful to reduce jitter/fighting effects before coming to rest.\nNote this applies position, rotation and velocity(!) so it's still smooth.")] + public float snapThreshold = 2; // 0.5 has too much fighting-at-rest, 2 seems ideal. + + [Header("Visual Interpolation")] + [Tooltip("After creating the visual interpolation object, keep showing the original Rigidbody with a ghost (transparent) material for debugging.")] + public bool showGhost = true; + [Tooltip("Physics components are moved onto a ghost object beyond this threshold. Main object visually interpolates to it.")] + public float ghostVelocityThreshold = 0.1f; + + [Tooltip("After creating the visual interpolation object, replace this object's renderer materials with the ghost (ideally transparent) material.")] + public Material localGhostMaterial; + public Material remoteGhostMaterial; + + [Tooltip("Performance optimization: only create/destroy ghosts every n-th frame is enough.")] + public int checkGhostsEveryNthFrame = 4; + + [Tooltip("How fast to interpolate to the target position, relative to how far we are away from it.\nHigher value will be more jitter but sharper moves, lower value will be less jitter but a little too smooth / rounded moves.")] + public float positionInterpolationSpeed = 15; // 10 is a little too low for billiards at least + public float rotationInterpolationSpeed = 10; + + [Tooltip("Teleport if we are further than 'multiplier x collider size' behind.")] + public float teleportDistanceMultiplier = 10; + + [Header("Bandwidth")] + [Tooltip("Reduce sends while velocity==0. Client's objects may slightly move due to gravity/physics, so we still want to send corrections occasionally even if an object is idle on the server the whole time.")] + public bool reduceSendsWhileIdle = true; + + // Rigidbody & Collider are moved out into a separate object. + // this way the visual object can smoothly follow. + protected GameObject physicsCopy; + // protected Transform physicsCopyTransform; // caching to avoid GetComponent + // protected Rigidbody physicsCopyRigidbody => rb; // caching to avoid GetComponent + // protected Collider physicsCopyCollider; // caching to avoid GetComponent + float smoothFollowThreshold; // caching to avoid calculation in LateUpdate + float smoothFollowThresholdSqr; // caching to avoid calculation in LateUpdate + + // we also create one extra ghost for the exact known server state. + protected GameObject remoteCopy; + + // joints + Vector3 initialPosition; + Quaternion initialRotation; + // Vector3 initialScale; // don't change scale for now. causes issues with parenting. + + Color originalColor; + + protected virtual void Awake() + { + tf = transform; + predictedRigidbody = GetComponent(); + if (predictedRigidbody == null) throw new InvalidOperationException($"Prediction: {name} is missing a Rigidbody component."); + predictedRigidbodyTransform = predictedRigidbody.transform; + + // in fast mode, we need to force enable Rigidbody.interpolation. + // otherwise there's not going to be any smoothing whatsoever. + if (mode == PredictionMode.Fast) + { + predictedRigidbody.interpolation = RigidbodyInterpolation.Interpolate; + } + + // cache some threshold to avoid calculating them in LateUpdate + float colliderSize = GetComponentInChildren().bounds.size.magnitude; + smoothFollowThreshold = colliderSize * teleportDistanceMultiplier; + smoothFollowThresholdSqr = smoothFollowThreshold * smoothFollowThreshold; + + // cache initial position/rotation/scale to be used when moving physics components (configurable joints' range of motion) + initialPosition = tf.position; + initialRotation = tf.rotation; + // initialScale = tf.localScale; + + // cache ² computations + motionSmoothingVelocityThresholdSqr = motionSmoothingVelocityThreshold * motionSmoothingVelocityThreshold; + motionSmoothingAngularVelocityThresholdSqr = motionSmoothingAngularVelocityThreshold * motionSmoothingAngularVelocityThreshold; + positionCorrectionThresholdSqr = positionCorrectionThreshold * positionCorrectionThreshold; + } + + protected virtual void CopyRenderersAsGhost(GameObject destination, Material material) + { + // find the MeshRenderer component, which sometimes is on a child. + MeshRenderer originalMeshRenderer = GetComponentInChildren(true); + MeshFilter originalMeshFilter = GetComponentInChildren(true); + if (originalMeshRenderer != null && originalMeshFilter != null) + { + MeshFilter meshFilter = destination.AddComponent(); + meshFilter.mesh = originalMeshFilter.mesh; + + MeshRenderer meshRenderer = destination.AddComponent(); + meshRenderer.material = originalMeshRenderer.material; + + // renderers often have multiple materials. copy all. + if (originalMeshRenderer.materials != null) + { + Material[] materials = new Material[originalMeshRenderer.materials.Length]; + for (int i = 0; i < materials.Length; ++i) + { + materials[i] = material; + } + meshRenderer.materials = materials; // need to reassign to see it in effect + } + } + // if we didn't find a renderer, show a warning + else Debug.LogWarning($"PredictedRigidbody: {name} found no renderer to copy onto the visual object. If you are using a custom setup, please overwrite PredictedRigidbody.CreateVisualCopy()."); + } + + // instantiate a physics-only copy of the gameobject to apply corrections. + // this way the main visual object can smoothly follow. + // it's best to separate the physics instead of separating the renderers. + // some projects have complex rendering / animation setups which we can't touch. + // besides, Rigidbody+Collider are two components, where as renders may be many. + protected virtual void CreateGhosts() + { + // skip if host mode or already separated + if (isServer || physicsCopy != null) return; + + // Debug.Log($"Separating Physics for {name}"); // logging this allocates too much + + // create an empty GameObject with the same name + _Physical + // it's important to copy world position/rotation/scale, not local! + // because the original object may be a child of another. + // + // for example: + // parent (scale=1.5) + // child (scale=0.5) + // + // if we copy localScale then the copy has scale=0.5, where as the + // original would have a global scale of ~1.0. + physicsCopy = new GameObject($"{name}_Physical"); + + // assign the same Layer for the physics copy. + // games may use a custom physics collision matrix, layer matters. + physicsCopy.layer = gameObject.layer; + + // add the PredictedRigidbodyPhysical component + PredictedRigidbodyPhysicsGhost physicsGhostRigidbody = physicsCopy.AddComponent(); + physicsGhostRigidbody.target = tf; + + // when moving (Configurable)Joints, their range of motion is + // relative to the initial position. if we move them after the + // GameObject rotated, the range of motion is wrong. + // the easiest solution is to move to initial position, + // then move physics components, then move back. + // => remember previous + Vector3 position = tf.position; + Quaternion rotation = tf.rotation; + // Vector3 scale = tf.localScale; // don't change scale for now. causes issues with parenting. + // => reset to initial + physicsGhostRigidbody.transform.position = tf.position = initialPosition; + physicsGhostRigidbody.transform.rotation = tf.rotation = initialRotation; + physicsGhostRigidbody.transform.localScale = tf.lossyScale;// world scale! // = initialScale; // don't change scale for now. causes issues with parenting. + // => move physics components + PredictionUtils.MovePhysicsComponents(gameObject, physicsCopy); + // => reset previous + physicsGhostRigidbody.transform.position = tf.position = position; + physicsGhostRigidbody.transform.rotation = tf.rotation = rotation; + //physicsGhostRigidbody.transform.localScale = tf.lossyScale; // world scale! //= scale; // don't change scale for now. causes issues with parenting. + + // show ghost by copying all renderers / materials with ghost material applied + if (showGhost) + { + // one for the locally predicted rigidbody + CopyRenderersAsGhost(physicsCopy, localGhostMaterial); + + // one for the latest remote state for comparison + // it's important to copy world position/rotation/scale, not local! + // because the original object may be a child of another. + // + // for example: + // parent (scale=1.5) + // child (scale=0.5) + // + // if we copy localScale then the copy has scale=0.5, where as the + // original would have a global scale of ~1.0. + remoteCopy = new GameObject($"{name}_Remote"); + remoteCopy.transform.position = tf.position; // world position! + remoteCopy.transform.rotation = tf.rotation; // world rotation! + remoteCopy.transform.localScale = tf.lossyScale; // world scale! + CopyRenderersAsGhost(remoteCopy, remoteGhostMaterial); + } + + // assign our Rigidbody reference to the ghost + predictedRigidbody = physicsCopy.GetComponent(); + predictedRigidbodyTransform = predictedRigidbody.transform; + } + + protected virtual void DestroyGhosts() + { + // move the copy's Rigidbody back onto self. + // important for scene objects which may be reused for AOI spawn/despawn. + // otherwise next time they wouldn't have a collider anymore. + if (physicsCopy != null) + { + // when moving (Configurable)Joints, their range of motion is + // relative to the initial position. if we move them after the + // GameObject rotated, the range of motion is wrong. + // the easiest solution is to move to initial position, + // then move physics components, then move back. + // => remember previous + Vector3 position = tf.position; + Quaternion rotation = tf.rotation; + Vector3 scale = tf.localScale; + // => reset to initial + physicsCopy.transform.position = tf.position = initialPosition; + physicsCopy.transform.rotation = tf.rotation = initialRotation; + physicsCopy.transform.localScale = tf.lossyScale;// = initialScale; + // => move physics components + PredictionUtils.MovePhysicsComponents(physicsCopy, gameObject); + // => reset previous + tf.position = position; + tf.rotation = rotation; + tf.localScale = scale; + + // when moving components back, we need to undo the joints initial-delta rotation that we added. + Destroy(physicsCopy); + + // reassign our Rigidbody reference + predictedRigidbody = GetComponent(); + predictedRigidbodyTransform = predictedRigidbody.transform; + } + + // simply destroy the remote copy + if (remoteCopy != null) Destroy(remoteCopy); + } + + // this shows in profiler LateUpdates! need to make this as fast as possible! + protected virtual void SmoothFollowPhysicsCopy() + { + // hard follow: + // predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation); + // tf.SetPositionAndRotation(physicsPosition, physicsRotation); + + // ORIGINAL VERSION: CLEAN AND SIMPLE + /* + // if we are further than N colliders sizes behind, then teleport + float colliderSize = physicsCopyCollider.bounds.size.magnitude; + float threshold = colliderSize * teleportDistanceMultiplier; + float distance = Vector3.Distance(tf.position, physicsCopyRigidbody.position); + if (distance > threshold) + { + tf.position = physicsCopyRigidbody.position; + tf.rotation = physicsCopyRigidbody.rotation; + Debug.Log($"[PredictedRigidbody] Teleported because distance to physics copy = {distance:F2} > threshold {threshold:F2}"); + return; + } + + // smoothly interpolate to the target position. + // speed relative to how far away we are + float positionStep = distance * positionInterpolationSpeed; + tf.position = Vector3.MoveTowards(tf.position, physicsCopyRigidbody.position, positionStep * Time.deltaTime); + + // smoothly interpolate to the target rotation. + // Quaternion.RotateTowards doesn't seem to work at all, so let's use SLerp. + tf.rotation = Quaternion.Slerp(tf.rotation, physicsCopyRigidbody.rotation, rotationInterpolationSpeed * Time.deltaTime); + */ + + // FAST VERSION: this shows in profiler a lot, so cache EVERYTHING! + tf.GetPositionAndRotation(out Vector3 currentPosition, out Quaternion currentRotation); // faster than tf.position + tf.rotation + predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation); // faster than Rigidbody .position and .rotation + float deltaTime = Time.deltaTime; + + // slow and simple version: + // float distance = Vector3.Distance(currentPosition, physicsPosition); + // if (distance > smoothFollowThreshold) + // faster version + Vector3 delta = physicsPosition - currentPosition; + float sqrDistance = Vector3.SqrMagnitude(delta); + float distance = Mathf.Sqrt(sqrDistance); + if (sqrDistance > smoothFollowThresholdSqr) + { + tf.SetPositionAndRotation(physicsPosition, physicsRotation); // faster than .position and .rotation manually + Debug.Log($"[PredictedRigidbody] Teleported because distance to physics copy = {distance:F2} > threshold {smoothFollowThreshold:F2}"); + return; + } + + // smoothly interpolate to the target position. + // speed relative to how far away we are. + // => speed increases by distance² because the further away, the + // sooner we need to catch the fuck up + // float positionStep = (distance * distance) * interpolationSpeed; + float positionStep = distance * positionInterpolationSpeed; + + Vector3 newPosition = MoveTowardsCustom(currentPosition, physicsPosition, delta, sqrDistance, distance, positionStep * deltaTime); + + // smoothly interpolate to the target rotation. + // Quaternion.RotateTowards doesn't seem to work at all, so let's use SLerp. + // Quaternions always need to be normalized in order to be a valid rotation after operations + Quaternion newRotation = Quaternion.Slerp(currentRotation, physicsRotation, rotationInterpolationSpeed * deltaTime).normalized; + + // assign position and rotation together. faster than accessing manually. + tf.SetPositionAndRotation(newPosition, newRotation); + } + + // simple and slow version with MoveTowards, which recalculates delta and delta.sqrMagnitude: + // Vector3 newPosition = Vector3.MoveTowards(currentPosition, physicsPosition, positionStep * deltaTime); + // faster version copied from MoveTowards: + // this increases Prediction Benchmark Client's FPS from 615 -> 640. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static Vector3 MoveTowardsCustom( + Vector3 current, + Vector3 target, + Vector3 _delta, // pass this in since we already calculated it + float _sqrDistance, // pass this in since we already calculated it + float _distance, // pass this in since we already calculated it + float maxDistanceDelta) + { + if (_sqrDistance == 0.0 || maxDistanceDelta >= 0.0 && _sqrDistance <= maxDistanceDelta * maxDistanceDelta) + return target; + + float distFactor = maxDistanceDelta / _distance; // unlike Vector3.MoveTowards, we only calculate this once + return new Vector3( + // current.x + (_delta.x / _distance) * maxDistanceDelta, + // current.y + (_delta.y / _distance) * maxDistanceDelta, + // current.z + (_delta.z / _distance) * maxDistanceDelta); + current.x + _delta.x * distFactor, + current.y + _delta.y * distFactor, + current.z + _delta.z * distFactor); + } + + // destroy visual copy only in OnStopClient(). + // OnDestroy() wouldn't be called for scene objects that are only disabled instead of destroyed. + public override void OnStopClient() + { + DestroyGhosts(); + } + + void UpdateServer() + { + // bandwidth optimization while idle. + if (reduceSendsWhileIdle) + { + // while moving, always sync every frame for immediate corrections. + // while idle, only sync once per second. + // + // we still need to sync occasionally because objects on client + // may still slide or move slightly due to gravity, physics etc. + // and those still need to get corrected if not moving on server. + // + // TODO + // next round of optimizations: if client received nothing for 1s, + // force correct to last received state. then server doesn't need + // to send once per second anymore. + syncInterval = IsMoving() ? 0 : 1; + } + + // always set dirty to always serialize in next sync interval. + SetDirty(); + } + + // movement detection is virtual, in case projects want to use other methods. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual bool IsMoving() => + // straight forward implementation + // predictedRigidbody.velocity.magnitude >= motionSmoothingVelocityThreshold || + // predictedRigidbody.angularVelocity.magnitude >= motionSmoothingAngularVelocityThreshold; + // faster implementation with cached ² + predictedRigidbody.velocity.sqrMagnitude >= motionSmoothingVelocityThresholdSqr || + predictedRigidbody.angularVelocity.sqrMagnitude >= motionSmoothingAngularVelocityThresholdSqr; + + // TODO maybe merge the IsMoving() checks & callbacks with UpdateState(). + void UpdateGhosting() + { + // perf: enough to check ghosts every few frames. + // PredictionBenchmark: only checking every 4th frame: 585 => 600 FPS + if (Time.frameCount % checkGhostsEveryNthFrame != 0) return; + + // client only uses ghosts on demand while interacting. + // this way 1000 GameObjects don't need +1000 Ghost GameObjects all the time! + + // no ghost at the moment + if (physicsCopy == null) + { + // faster than velocity threshold? then create the ghosts. + // with 10% buffer zone so we don't flip flop all the time. + if (IsMoving()) + { + CreateGhosts(); + OnBeginPrediction(); + } + } + // ghosting at the moment + else + { + // always set last moved time while moving. + // this way we can avoid on/off/oneffects when stopping. + if (IsMoving()) + { + motionSmoothingLastMovedTime = NetworkTime.time; + } + // slower than velocity threshold? then destroy the ghosts. + // with a minimum time since starting to move, to avoid on/off/on effects. + else + { + if (NetworkTime.time >= motionSmoothingLastMovedTime + motionSmoothingTimeTolerance) + { + DestroyGhosts(); + OnEndPrediction(); + physicsCopy = null; // TESTING + } + } + } + } + + // when using Fast mode, we don't create any ghosts. + // but we still want to check IsMoving() in order to support the same + // user callbacks. + bool lastMoving = false; + void UpdateState() + { + // perf: enough to check ghosts every few frames. + // PredictionBenchmark: only checking every 4th frame: 770 => 800 FPS + if (Time.frameCount % checkGhostsEveryNthFrame != 0) return; + + bool moving = IsMoving(); + + // started moving? + if (moving && !lastMoving) + { + OnBeginPrediction(); + lastMoving = true; + } + // stopped moving? + else if (!moving && lastMoving) + { + // ensure a minimum time since starting to move, to avoid on/off/on effects. + if (NetworkTime.time >= motionSmoothingLastMovedTime + motionSmoothingTimeTolerance) + { + OnEndPrediction(); + lastMoving = false; + } + } + } + + void Update() + { + if (isServer) UpdateServer(); + if (isClientOnly) + { + if (mode == PredictionMode.Smooth) + UpdateGhosting(); + else if (mode == PredictionMode.Fast) + UpdateState(); + } + } + + void LateUpdate() + { + // only follow on client-only, not in server or host mode + if (isClientOnly && mode == PredictionMode.Smooth && physicsCopy) SmoothFollowPhysicsCopy(); + } + + void FixedUpdate() + { + // on clients (not host) we record the current state every FixedUpdate. + // this is cheap, and allows us to keep a dense history. + if (!isClientOnly) return; + + // OPTIMIZATION: RecordState() is expensive because it inserts into a SortedList. + // only record if state actually changed! + // risks not having up to date states when correcting, + // but it doesn't matter since we'll always compare with the 'newest' anyway. + // + // we check in here instead of in RecordState() because RecordState() should definitely record if we call it! + if (onlyRecordChanges) + { + // TODO maybe don't reuse the correction thresholds? + tf.GetPositionAndRotation(out Vector3 position, out Quaternion rotation); + // clean & simple: + // if (Vector3.Distance(lastRecorded.position, position) < positionCorrectionThreshold && + // Quaternion.Angle(lastRecorded.rotation, rotation) < rotationCorrectionThreshold) + // faster: + if ((lastRecorded.position - position).sqrMagnitude < positionCorrectionThresholdSqr && + Quaternion.Angle(lastRecorded.rotation, rotation) < rotationCorrectionThreshold) + { + // Debug.Log($"FixedUpdate for {name}: taking optimized early return instead of recording state."); + return; + } + } + + RecordState(); + } + + // manually store last recorded so we can easily check against this + // without traversing the SortedList. + RigidbodyState lastRecorded; + double lastRecordTime; + void RecordState() + { + // performance optimization: only call NetworkTime.time getter once + double networkTime = NetworkTime.time; + + // instead of recording every fixedupdate, let's record in an interval. + // we don't want to record every tiny move and correct too hard. + if (networkTime < lastRecordTime + recordInterval) return; + lastRecordTime = networkTime; + + // NetworkTime.time is always behind by bufferTime. + // prediction aims to be on the exact same server time (immediately). + // use predictedTime to record state, otherwise we would record in the past. + double predictedTime = NetworkTime.predictedTime; + + // FixedUpdate may run twice in the same frame / NetworkTime.time. + // for now, simply don't record if already recorded there. + // previously we checked ContainsKey which is O(logN) for SortedList + // if (stateHistory.ContainsKey(predictedTime)) + // return; + // instead, simply store the last recorded time and don't insert if same. + if (predictedTime == lastRecorded.timestamp) return; + + // keep state history within limit + if (stateHistory.Count >= stateHistoryLimit) + stateHistory.RemoveAt(0); + + // grab current position/rotation/velocity only once. + // this is performance critical, avoid calling .transform multiple times. + tf.GetPositionAndRotation(out Vector3 currentPosition, out Quaternion currentRotation); // faster than accessing .position + .rotation manually + Vector3 currentVelocity = predictedRigidbody.velocity; + Vector3 currentAngularVelocity = predictedRigidbody.angularVelocity; + + // calculate delta to previous state (if any) + Vector3 positionDelta = Vector3.zero; + Vector3 velocityDelta = Vector3.zero; + Vector3 angularVelocityDelta = Vector3.zero; + Quaternion rotationDelta = Quaternion.identity; + int stateHistoryCount = stateHistory.Count; // perf: only grab .Count once + if (stateHistoryCount > 0) + { + RigidbodyState last = stateHistory.Values[stateHistoryCount - 1]; + positionDelta = currentPosition - last.position; + velocityDelta = currentVelocity - last.velocity; + // Quaternions always need to be normalized in order to be valid rotations after operations + rotationDelta = (currentRotation * Quaternion.Inverse(last.rotation)).normalized; + angularVelocityDelta = currentAngularVelocity - last.angularVelocity; + + // debug draw the recorded state + // Debug.DrawLine(last.position, currentPosition, Color.red, lineTime); + } + + // create state to insert + RigidbodyState state = new RigidbodyState( + predictedTime, + positionDelta, + currentPosition, + rotationDelta, + currentRotation, + velocityDelta, + currentVelocity, + angularVelocityDelta, + currentAngularVelocity + ); + + // add state to history + stateHistory.Add(predictedTime, state); + + // manually remember last inserted state for faster .Last comparisons + lastRecorded = state; + } + + // optional user callbacks, in case people need to know about events. + protected virtual void OnSnappedIntoPlace() {} + protected virtual void OnBeforeApplyState() {} + protected virtual void OnCorrected() {} + protected virtual void OnBeginPrediction() {} // when the Rigidbody moved above threshold and we created a ghost + protected virtual void OnEndPrediction() {} // when the Rigidbody came to rest and we destroyed the ghost + + void ApplyState(double timestamp, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity) + { + // fix rigidbodies seemingly dancing in place instead of coming to rest. + // hard snap to the position below a threshold velocity. + // this is fine because the visual object still smoothly interpolates to it. + // => consider both velocity and angular velocity (in case of Rigidbodies only rotating with joints etc.) + if (predictedRigidbody.velocity.magnitude <= snapThreshold && + predictedRigidbody.angularVelocity.magnitude <= snapThreshold) + { + // Debug.Log($"Prediction: snapped {name} into place because velocity {predictedRigidbody.velocity.magnitude:F3} <= {snapThreshold:F3}"); + + // apply server state immediately. + // important to apply velocity as well, instead of Vector3.zero. + // in case an object is still slightly moving, we don't want it + // to stop and start moving again on client - slide as well here. + predictedRigidbody.position = position; + predictedRigidbody.rotation = rotation; + // projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error + if (!predictedRigidbody.isKinematic) + { + predictedRigidbody.velocity = velocity; + predictedRigidbody.angularVelocity = angularVelocity; + } + + // clear history and insert the exact state we just applied. + // this makes future corrections more accurate. + stateHistory.Clear(); + stateHistory.Add(timestamp, new RigidbodyState( + timestamp, + Vector3.zero, + position, + Quaternion.identity, + rotation, + Vector3.zero, + velocity, + Vector3.zero, + angularVelocity + )); + + // user callback + OnSnappedIntoPlace(); + return; + } + + // we have a callback for snapping into place (above). + // we also need one for corrections without snapping into place. + // call it before applying pos/rot/vel in case we need to set kinematic etc. + OnBeforeApplyState(); + + // apply the state to the Rigidbody + if (mode == PredictionMode.Smooth) + { + // Smooth mode separates Physics from Renderering. + // Rendering smoothly follows Physics in SmoothFollowPhysicsCopy(). + // this allows us to be able to hard teleport to the correction. + // which gives most accurate results since the Rigidbody can't + // be stopped by another object when trying to correct. + predictedRigidbody.position = position; + predictedRigidbody.rotation = rotation; + } + else if (mode == PredictionMode.Fast) + { + // Fast mode doesn't separate physics from rendering. + // The only smoothing we get is from Rigidbody.MovePosition. + predictedRigidbody.MovePosition(position); + predictedRigidbody.MoveRotation(rotation); + } + + // there's only one way to set velocity. + // (projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error) + if (!predictedRigidbody.isKinematic) + { + predictedRigidbody.velocity = velocity; + predictedRigidbody.angularVelocity = angularVelocity; + } + } + + // process a received server state. + // compares it against our history and applies corrections if needed. + void OnReceivedState(double timestamp, RigidbodyState state)//, bool sleeping) + { + // always update remote state ghost + if (remoteCopy != null) + { + Transform remoteCopyTransform = remoteCopy.transform; + remoteCopyTransform.SetPositionAndRotation(state.position, state.rotation); // faster than .position + .rotation setters + remoteCopyTransform.localScale = tf.lossyScale; // world scale! see CreateGhosts comment. + } + + + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // color code remote sleeping objects to debug objects coming to rest + // if (showRemoteSleeping) + // { + // rend.material.color = sleeping ? Color.gray : originalColor; + // } + + // performance: get Rigidbody position & rotation only once, + // and together via its transform + predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation); + + // OPTIONAL performance optimization when comparing idle objects. + // even idle objects will have a history of ~32 entries. + // sampling & traversing through them is unnecessarily costly. + // instead, compare directly against the current rigidbody position! + // => this is technically not 100% correct if an object runs in + // circles where it may revisit the same position twice. + // => but practically, objects that didn't move will have their + // whole history look like the last inserted state. + // => comparing against that is free and gives us a significant + // performance saving vs. a tiny chance of incorrect results due + // to objects running in circles. + // => the RecordState() call below is expensive too, so we want to + // do this before even recording the latest state. the only way + // to do this (in case last recorded state is too old), is to + // compare against live rigidbody.position without any recording. + // this is as fast as it gets for skipping idle objects. + // + // if this ever causes issues, feel free to disable it. + float positionToStateDistanceSqr = Vector3.SqrMagnitude(state.position - physicsPosition); + if (compareLastFirst && + // Vector3.Distance(state.position, physicsPosition) < positionCorrectionThreshold && // slow comparison + positionToStateDistanceSqr < positionCorrectionThresholdSqr && // fast comparison + Quaternion.Angle(state.rotation, physicsRotation) < rotationCorrectionThreshold) + { + // Debug.Log($"OnReceivedState for {name}: taking optimized early return!"); + return; + } + + // we only capture state every 'interval' milliseconds. + // so the newest entry in 'history' may be up to 'interval' behind 'now'. + // if there's no latency, we may receive a server state for 'now'. + // sampling would fail, if we haven't recorded anything in a while. + // to solve this, always record the current state when receiving a server state. + RecordState(); + + // correction requires at least 2 existing states for 'before' and 'after'. + // if we don't have two yet, drop this state and try again next time once we recorded more. + if (stateHistory.Count < 2) return; + + RigidbodyState oldest = stateHistory.Values[0]; + RigidbodyState newest = stateHistory.Values[stateHistory.Count - 1]; + + // edge case: is the state older than the oldest state in history? + // this can happen if the client gets so far behind the server + // that it doesn't have a recored history to sample from. + // in that case, we should hard correct the client. + // otherwise it could be out of sync as long as it's too far behind. + if (state.timestamp < oldest.timestamp) + { + // when starting, client may only have 2-3 states in history. + // it's expected that server states would be behind those 2-3. + // only show a warning if it's behind the full history limit! + if (stateHistory.Count >= stateHistoryLimit) + Debug.LogWarning($"Hard correcting client object {name} because the client is too far behind the server. History of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This would cause the client to be out of sync as long as it's behind."); + + // force apply the state + ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity); + return; + } + + // edge case: is it newer than the newest state in history? + // this can happen if client's predictedTime predicts too far ahead of the server. + // in that case, log a warning for now but still apply the correction. + // otherwise it could be out of sync as long as it's too far ahead. + // + // for example, when running prediction on the same machine with near zero latency. + // when applying corrections here, this looks just fine on the local machine. + if (newest.timestamp < state.timestamp) + { + // the correction is for a state in the future. + // we clamp it to 'now'. + // but only correct if off by threshold. + // TODO maybe we should interpolate this back to 'now'? + // if (Vector3.Distance(state.position, physicsPosition) >= positionCorrectionThreshold) // slow comparison + if (positionToStateDistanceSqr >= positionCorrectionThresholdSqr) // fast comparison + { + // this can happen a lot when latency is ~0. logging all the time allocates too much and is too slow. + // double ahead = state.timestamp - newest.timestamp; + // Debug.Log($"Hard correction because the client is ahead of the server by {(ahead*1000):F1}ms. History of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This can happen when latency is near zero, and is fine unless it shows jitter."); + ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity); + } + return; + } + + // find the two closest client states between timestamp + if (!Prediction.Sample(stateHistory, timestamp, out RigidbodyState before, out RigidbodyState after, out int afterIndex, out double t)) + { + // something went very wrong. sampling should've worked. + // hard correct to recover the error. + Debug.LogError($"Failed to sample history of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This should never happen because the timestamp is within history."); + ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity); + return; + } + + // interpolate between them to get the best approximation + RigidbodyState interpolated = RigidbodyState.Interpolate(before, after, (float)t); + + // calculate the difference between where we were and where we should be + // TODO only position for now. consider rotation etc. too later + // float positionToInterpolatedDistance = Vector3.Distance(state.position, interpolated.position); // slow comparison + float positionToInterpolatedDistanceSqr = Vector3.SqrMagnitude(state.position - interpolated.position); // fast comparison + float rotationToInterpolatedDistance = Quaternion.Angle(state.rotation, interpolated.rotation); + // Debug.Log($"Sampled history of size={stateHistory.Count} @ {timestamp:F3}: client={interpolated.position} server={state.position} difference={difference:F3} / {correctionThreshold:F3}"); + + // too far off? then correct it + if (positionToInterpolatedDistanceSqr >= positionCorrectionThresholdSqr || // fast comparison + //positionToInterpolatedDistance >= positionCorrectionThreshold || // slow comparison + rotationToInterpolatedDistance >= rotationCorrectionThreshold) + { + // Debug.Log($"CORRECTION NEEDED FOR {name} @ {timestamp:F3}: client={interpolated.position} server={state.position} difference={difference:F3}"); + + // show the received correction position + velocity for debugging. + // helps to compare with the interpolated/applied correction locally. + //Debug.DrawLine(state.position, state.position + state.velocity * 0.1f, Color.white, lineTime); + + // insert the correction and correct the history on top of it. + // returns the final recomputed state after rewinding. + RigidbodyState recomputed = Prediction.CorrectHistory(stateHistory, stateHistoryLimit, state, before, after, afterIndex); + + // log, draw & apply the final position. + // always do this here, not when iterating above, in case we aren't iterating. + // for example, on same machine with near zero latency. + // int correctedAmount = stateHistory.Count - afterIndex; + // Debug.Log($"Correcting {name}: {correctedAmount} / {stateHistory.Count} states to final position from: {rb.position} to: {last.position}"); + //Debug.DrawLine(physicsCopyRigidbody.position, recomputed.position, Color.green, lineTime); + ApplyState(recomputed.timestamp, recomputed.position, recomputed.rotation, recomputed.velocity, recomputed.angularVelocity); + + // user callback + OnCorrected(); + } + } + + // send state to clients every sendInterval. + // reliable for now. + // TODO we should use the one from FixedUpdate + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + // Time.time was at the beginning of this frame. + // NetworkLateUpdate->Broadcast->OnSerialize is at the end of the frame. + // as result, client should use this to correct the _next_ frame. + // otherwise we see noticeable resets that seem off by one frame. + // + // to solve this, we can send the current deltaTime. + // server is technically supposed to be at a fixed frame rate, but this can vary. + // sending server's current deltaTime is the safest option. + // client then applies it on top of remoteTimestamp. + + + // FAST VERSION: this shows in profiler a lot, so cache EVERYTHING! + tf.GetPositionAndRotation(out Vector3 position, out Quaternion rotation); // faster than tf.position + tf.rotation. server's rigidbody is on the same transform. + + // simple but slow write: + // writer.WriteFloat(Time.deltaTime); + // writer.WriteVector3(position); + // writer.WriteQuaternion(rotation); + // writer.WriteVector3(predictedRigidbody.velocity); + // writer.WriteVector3(predictedRigidbody.angularVelocity); + + // performance optimization: write a whole struct at once via blittable: + PredictedSyncData data = new PredictedSyncData( + Time.deltaTime, + position, + rotation, + predictedRigidbody.velocity, + predictedRigidbody.angularVelocity);//, + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // predictedRigidbody.IsSleeping()); + writer.WritePredictedSyncData(data); + } + + // read the server's state, compare with client state & correct if necessary. + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + // deserialize data + // we want to know the time on the server when this was sent, which is remoteTimestamp. + double timestamp = NetworkClient.connection.remoteTimeStamp; + + // simple but slow read: + // double serverDeltaTime = reader.ReadFloat(); + // Vector3 position = reader.ReadVector3(); + // Quaternion rotation = reader.ReadQuaternion(); + // Vector3 velocity = reader.ReadVector3(); + // Vector3 angularVelocity = reader.ReadVector3(); + + // performance optimization: read a whole struct at once via blittable: + PredictedSyncData data = reader.ReadPredictedSyncData(); + double serverDeltaTime = data.deltaTime; + Vector3 position = data.position; + Quaternion rotation = data.rotation; + Vector3 velocity = data.velocity; + Vector3 angularVelocity = data.angularVelocity; + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // bool sleeping = data.sleeping != 0; + + // server sends state at the end of the frame. + // parse and apply the server's delta time to our timestamp. + // otherwise we see noticeable resets that seem off by one frame. + timestamp += serverDeltaTime; + + // however, adding yet one more frame delay gives much(!) better results. + // we don't know why yet, so keep this as an option for now. + // possibly because client captures at the beginning of the frame, + // with physics happening at the end of the frame? + if (oneFrameAhead) timestamp += serverDeltaTime; + + // process received state + OnReceivedState(timestamp, new RigidbodyState(timestamp, Vector3.zero, position, Quaternion.identity, rotation, Vector3.zero, velocity, Vector3.zero, angularVelocity));//, sleeping); + } + + protected override void OnValidate() + { + base.OnValidate(); + + // force syncDirection to be ServerToClient + syncDirection = SyncDirection.ServerToClient; + + // state should be synced immediately for now. + // later when we have prediction fully dialed in, + // then we can maybe relax this a bit. + syncInterval = 0; + } + + // helper function for Physics tests to check if a Rigidbody belongs to + // a PredictedRigidbody component (either on it, or on its ghost). + public static bool IsPredicted(Rigidbody rb, out PredictedRigidbody predictedRigidbody) + { + // by default, Rigidbody is on the PredictedRigidbody GameObject + if (rb.TryGetComponent(out predictedRigidbody)) + return true; + + // it might be on a ghost while interacting + if (rb.TryGetComponent(out PredictedRigidbodyPhysicsGhost ghost)) + { + predictedRigidbody = ghost.target.GetComponent(); + return true; + } + + // otherwise the Rigidbody does not belong to any PredictedRigidbody. + predictedRigidbody = null; + return false; + } + + // helper function for Physics tests to check if a Collider (which may be in children) belongs to + // a PredictedRigidbody component (either on it, or on its ghost). + public static bool IsPredicted(Collider co, out PredictedRigidbody predictedRigidbody) + { + // by default, Collider is on the PredictedRigidbody GameObject or it's children. + predictedRigidbody = co.GetComponentInParent(); + if (predictedRigidbody != null) + return true; + + // it might be on a ghost while interacting + PredictedRigidbodyPhysicsGhost ghost = co.GetComponentInParent(); + if (ghost != null && ghost.target != null && ghost.target.TryGetComponent(out predictedRigidbody)) + return true; + + // otherwise the Rigidbody does not belong to any PredictedRigidbody. + predictedRigidbody = null; + return false; + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta new file mode 100644 index 0000000..6456058 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: d38927cdc6024b9682b5fe9778b9ef99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - localGhostMaterial: {fileID: 2100000, guid: 411a48b4a197d4924bec3e3809bc9320, + type: 2} + - remoteGhostMaterial: {fileID: 2100000, guid: 04f0b2088c857414393bab3b80356776, + type: 2} + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs new file mode 100644 index 0000000..f28d49f --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs @@ -0,0 +1,15 @@ +// Prediction moves out the Rigidbody & Collider into a separate object. +// this component simply points back to the owner component. +// in case Raycasts hit it and need to know the owner, etc. +using UnityEngine; + +namespace Mirror +{ + public class PredictedRigidbodyPhysicsGhost : MonoBehaviour + { + // this is performance critical, so store target's .Transform instead of + // PredictedRigidbody, this way we don't need to call the .transform getter. + [Tooltip("The predicted rigidbody owner.")] + public Transform target; + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta new file mode 100644 index 0000000..e4b8787 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 25593abc9bf0d44878a4ad6018204061 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs new file mode 100644 index 0000000..636f397 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs @@ -0,0 +1 @@ +// removed 2024-02-09 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta new file mode 100644 index 0000000..f79f911 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62e7e9424c7e48d69b6a3517796142a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs new file mode 100644 index 0000000..fa652fd --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs @@ -0,0 +1,54 @@ +// this struct exists only for OnDe/Serialize performance. +// instead of WriteVector3+Quaternion+Vector3+Vector3, +// we read & write the whole struct as blittable once. +// +// struct packing can cause odd results with blittable on different platforms, +// so this is usually not recommended! +// +// in this case however, we need to squeeze everything we can out of prediction +// to support low even devices / VR. +using System.Runtime.InteropServices; +using UnityEngine; + +namespace Mirror +{ + // struct packing + + [StructLayout(LayoutKind.Sequential)] // explicitly force sequential + public struct PredictedSyncData + { + public float deltaTime; // 4 bytes (word aligned) + public Vector3 position; // 12 bytes (word aligned) + public Quaternion rotation; // 16 bytes (word aligned) + public Vector3 velocity; // 12 bytes (word aligned) + public Vector3 angularVelocity; // 12 bytes (word aligned) + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // public byte sleeping; // 1 byte: bool isn't blittable + + // constructor for convenience + public PredictedSyncData(float deltaTime, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)//, bool sleeping) + { + this.deltaTime = deltaTime; + this.position = position; + this.rotation = rotation; + this.velocity = velocity; + this.angularVelocity = angularVelocity; + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // this.sleeping = sleeping ? (byte)1 : (byte)0; + } + } + + // NetworkReader/Writer extensions to write this struct + public static class PredictedSyncDataReadWrite + { + public static void WritePredictedSyncData(this NetworkWriter writer, PredictedSyncData data) + { + writer.WriteBlittable(data); + } + + public static PredictedSyncData ReadPredictedSyncData(this NetworkReader reader) + { + return reader.ReadBlittable(); + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta new file mode 100644 index 0000000..f78b78d --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f595f112a39e4634b670d56991b23823 +timeCreated: 1710387026 \ No newline at end of file diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs new file mode 100644 index 0000000..6c88923 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs @@ -0,0 +1,419 @@ +// standalone utility functions for PredictedRigidbody component. +using System; +using UnityEngine; + +namespace Mirror +{ + public static class PredictionUtils + { + // rigidbody /////////////////////////////////////////////////////////// + // move a Rigidbody + settings from one GameObject to another. + public static void MoveRigidbody(GameObject source, GameObject destination, bool destroySource = true) + { + // create a new Rigidbody component on destination. + // note that adding a Joint automatically adds a Rigidbody. + // so first check if one was added yet. + Rigidbody original = source.GetComponent(); + if (original == null) throw new Exception($"Prediction: attempted to move {source}'s Rigidbody to the predicted copy, but there was no component."); + Rigidbody rigidbodyCopy; + if (!destination.TryGetComponent(out rigidbodyCopy)) + rigidbodyCopy = destination.AddComponent(); + + // copy all properties + rigidbodyCopy.mass = original.mass; + rigidbodyCopy.drag = original.drag; + rigidbodyCopy.angularDrag = original.angularDrag; + rigidbodyCopy.useGravity = original.useGravity; + rigidbodyCopy.isKinematic = original.isKinematic; + rigidbodyCopy.interpolation = original.interpolation; + rigidbodyCopy.collisionDetectionMode = original.collisionDetectionMode; + rigidbodyCopy.constraints = original.constraints; + rigidbodyCopy.sleepThreshold = original.sleepThreshold; + rigidbodyCopy.freezeRotation = original.freezeRotation; + + // moving (Configurable)Joints messes up their range of motion unless + // we reset to initial position first (we do this in PredictedRigibody.cs). + // so here we don't set the Rigidbody's physics position at all. + // rigidbodyCopy.position = original.position; + // rigidbodyCopy.rotation = original.rotation; + + // projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error + if (!original.isKinematic) + { + rigidbodyCopy.velocity = original.velocity; + rigidbodyCopy.angularVelocity = original.angularVelocity; + } + + // destroy original + if (destroySource) GameObject.Destroy(original); + } + + // helper function: if a collider is on a child, copy that child first. + // this way child's relative position/rotation/scale are preserved. + public static GameObject CopyRelativeTransform(GameObject source, Transform sourceChild, GameObject destination) + { + // is this on the source root? then we want to put it on the destination root. + if (sourceChild == source.transform) return destination; + + // is this on a child? then create the same child with the same transform on destination. + // note this is technically only correct for the immediate child since + // .localPosition is relative to parent, but this is good enough. + GameObject child = new GameObject(sourceChild.name); + child.transform.SetParent(destination.transform, true); + child.transform.localPosition = sourceChild.localPosition; + child.transform.localRotation = sourceChild.localRotation; + child.transform.localScale = sourceChild.localScale; + + // assign the same Layer for the physics copy. + // games may use a custom physics collision matrix, layer matters. + child.layer = sourceChild.gameObject.layer; + + return child; + } + + // colliders /////////////////////////////////////////////////////////// + // move all BoxColliders + settings from one GameObject to another. + public static void MoveBoxColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + BoxCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (BoxCollider sourceCollider in sourceColliders) + { + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + BoxCollider colliderCopy = target.AddComponent(); + colliderCopy.center = sourceCollider.center; + colliderCopy.size = sourceCollider.size; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all SphereColliders + settings from one GameObject to another. + public static void MoveSphereColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + SphereCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (SphereCollider sourceCollider in sourceColliders) + { + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + SphereCollider colliderCopy = target.AddComponent(); + colliderCopy.center = sourceCollider.center; + colliderCopy.radius = sourceCollider.radius; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all CapsuleColliders + settings from one GameObject to another. + public static void MoveCapsuleColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + CapsuleCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (CapsuleCollider sourceCollider in sourceColliders) + { + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + CapsuleCollider colliderCopy = target.AddComponent(); + colliderCopy.center = sourceCollider.center; + colliderCopy.radius = sourceCollider.radius; + colliderCopy.height = sourceCollider.height; + colliderCopy.direction = sourceCollider.direction; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all MeshColliders + settings from one GameObject to another. + public static void MoveMeshColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + MeshCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (MeshCollider sourceCollider in sourceColliders) + { + // when Models have Mesh->Read/Write disabled, it means that Unity + // uploads the mesh directly to the GPU and erases it on the CPU. + // on some platforms this makes moving a MeshCollider in builds impossible: + // + // "CollisionMeshData couldn't be created because the mesh has been marked as non-accessible." + // + // on other platforms, this works fine. + // let's show an explicit log message so in case collisions don't + // work at runtime, it's obvious why it happens and how to fix it. + if (!sourceCollider.sharedMesh.isReadable) + { + Debug.Log($"[Prediction]: MeshCollider on {sourceCollider.name} isn't readable, which may indicate that the Mesh only exists on the GPU. If {sourceCollider.name} is missing collisions, then please select the model in the Project Area, and enable Mesh->Read/Write so it's also available on the CPU!"); + // don't early return. keep trying, it may work. + } + + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + MeshCollider colliderCopy = target.AddComponent(); + colliderCopy.sharedMesh = sourceCollider.sharedMesh; + colliderCopy.convex = sourceCollider.convex; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all Colliders + settings from one GameObject to another. + public static void MoveAllColliders(GameObject source, GameObject destination, bool destroySource = true) + { + MoveBoxColliders(source, destination, destroySource); + MoveSphereColliders(source, destination, destroySource); + MoveCapsuleColliders(source, destination, destroySource); + MoveMeshColliders(source, destination, destroySource); + } + + // joints ////////////////////////////////////////////////////////////// + // move all CharacterJoints + settings from one GameObject to another. + public static void MoveCharacterJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + CharacterJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (CharacterJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + CharacterJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.enableProjection = sourceJoint.enableProjection; + jointCopy.highTwistLimit = sourceJoint.highTwistLimit; + jointCopy.lowTwistLimit = sourceJoint.lowTwistLimit; + jointCopy.massScale = sourceJoint.massScale; + jointCopy.projectionAngle = sourceJoint.projectionAngle; + jointCopy.projectionDistance = sourceJoint.projectionDistance; + jointCopy.swing1Limit = sourceJoint.swing1Limit; + jointCopy.swing2Limit = sourceJoint.swing2Limit; + jointCopy.swingAxis = sourceJoint.swingAxis; + jointCopy.swingLimitSpring = sourceJoint.swingLimitSpring; + jointCopy.twistLimitSpring = sourceJoint.twistLimitSpring; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all ConfigurableJoints + settings from one GameObject to another. + public static void MoveConfigurableJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + ConfigurableJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (ConfigurableJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + ConfigurableJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.angularXLimitSpring = sourceJoint.angularXLimitSpring; + jointCopy.angularXDrive = sourceJoint.angularXDrive; + jointCopy.angularXMotion = sourceJoint.angularXMotion; + jointCopy.angularYLimit = sourceJoint.angularYLimit; + jointCopy.angularYMotion = sourceJoint.angularYMotion; + jointCopy.angularYZDrive = sourceJoint.angularYZDrive; + jointCopy.angularYZLimitSpring = sourceJoint.angularYZLimitSpring; + jointCopy.angularZLimit = sourceJoint.angularZLimit; + jointCopy.angularZMotion = sourceJoint.angularZMotion; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.configuredInWorldSpace = sourceJoint.configuredInWorldSpace; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.highAngularXLimit = sourceJoint.highAngularXLimit; // moving this only works if the object is at initial position/rotation/scale, see PredictedRigidbody.cs + jointCopy.linearLimitSpring = sourceJoint.linearLimitSpring; + jointCopy.linearLimit = sourceJoint.linearLimit; + jointCopy.lowAngularXLimit = sourceJoint.lowAngularXLimit; // moving this only works if the object is at initial position/rotation/scale, see PredictedRigidbody.cs + jointCopy.massScale = sourceJoint.massScale; + jointCopy.projectionAngle = sourceJoint.projectionAngle; + jointCopy.projectionDistance = sourceJoint.projectionDistance; + jointCopy.projectionMode = sourceJoint.projectionMode; + jointCopy.rotationDriveMode = sourceJoint.rotationDriveMode; + jointCopy.secondaryAxis = sourceJoint.secondaryAxis; + jointCopy.slerpDrive = sourceJoint.slerpDrive; + jointCopy.swapBodies = sourceJoint.swapBodies; + jointCopy.targetAngularVelocity = sourceJoint.targetAngularVelocity; + jointCopy.targetPosition = sourceJoint.targetPosition; + jointCopy.targetRotation = sourceJoint.targetRotation; + jointCopy.targetVelocity = sourceJoint.targetVelocity; + jointCopy.xDrive = sourceJoint.xDrive; + jointCopy.xMotion = sourceJoint.xMotion; + jointCopy.yDrive = sourceJoint.yDrive; + jointCopy.yMotion = sourceJoint.yMotion; + jointCopy.zDrive = sourceJoint.zDrive; + jointCopy.zMotion = sourceJoint.zMotion; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all FixedJoints + settings from one GameObject to another. + public static void MoveFixedJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + FixedJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (FixedJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + FixedJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.massScale = sourceJoint.massScale; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all HingeJoints + settings from one GameObject to another. + public static void MoveHingeJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + HingeJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (HingeJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + HingeJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.limits = sourceJoint.limits; + jointCopy.massScale = sourceJoint.massScale; + jointCopy.motor = sourceJoint.motor; + jointCopy.spring = sourceJoint.spring; + jointCopy.useLimits = sourceJoint.useLimits; + jointCopy.useMotor = sourceJoint.useMotor; + jointCopy.useSpring = sourceJoint.useSpring; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif +#if UNITY_2022_3_OR_NEWER + jointCopy.extendedLimits = sourceJoint.extendedLimits; + jointCopy.useAcceleration = sourceJoint.useAcceleration; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all SpringJoints + settings from one GameObject to another. + public static void MoveSpringJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + SpringJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (SpringJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + SpringJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.damper = sourceJoint.damper; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.massScale = sourceJoint.massScale; + jointCopy.maxDistance = sourceJoint.maxDistance; + jointCopy.minDistance = sourceJoint.minDistance; + jointCopy.spring = sourceJoint.spring; + jointCopy.tolerance = sourceJoint.tolerance; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all Joints + settings from one GameObject to another. + public static void MoveAllJoints(GameObject source, GameObject destination, bool destroySource = true) + { + MoveCharacterJoints(source, destination, destroySource); + MoveConfigurableJoints(source, destination, destroySource); + MoveFixedJoints(source, destination, destroySource); + MoveHingeJoints(source, destination, destroySource); + MoveSpringJoints(source, destination, destroySource); + } + + // all ///////////////////////////////////////////////////////////////// + // move all physics components from one GameObject to another. + public static void MovePhysicsComponents(GameObject source, GameObject destination, bool destroySource = true) + { + // need to move joints first, otherwise we might see: + // 'can't move Rigidbody because a Joint depends on it' + MoveAllJoints(source, destination, destroySource); + MoveAllColliders(source, destination, destroySource); + MoveRigidbody(source, destination, destroySource); + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta new file mode 100644 index 0000000..52cc737 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17cfe1beb3f94a69b94bf60afc37ef7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat similarity index 83% rename from Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat rename to Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat index 462e16d..d652a50 100644 --- a/Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat +++ b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat @@ -2,14 +2,18 @@ %TAG !u! tag:unity3d.com,2011: --- !u!21 &2100000 Material: - serializedVersion: 6 + serializedVersion: 8 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: Zone + m_Name: RemoteGhostMaterial m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON + m_InvalidKeywords: [] m_LightmapFlags: 4 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 @@ -17,6 +21,7 @@ Material: stringTagMap: RenderType: Transparent disabledShaderPasses: [] + m_LockedProperties: m_SavedProperties: serializedVersion: 3 m_TexEnvs: @@ -56,23 +61,25 @@ Material: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} + m_Ints: [] m_Floats: - _BumpScale: 1 - _Cutoff: 0.5 - _DetailNormalMapScale: 1 - _DstBlend: 10 - _GlossMapScale: 1 - - _Glossiness: 0 - - _GlossyReflections: 0 + - _Glossiness: 0.92 + - _GlossyReflections: 1 - _Metallic: 0 - _Mode: 3 - _OcclusionStrength: 1 - _Parallax: 0.02 - _SmoothnessTextureChannel: 0 - - _SpecularHighlights: 0 + - _SpecularHighlights: 1 - _SrcBlend: 1 - _UVSec: 0 - _ZWrite: 0 m_Colors: - - _Color: {r: 0, g: 0, b: 0, a: 0.039215688} + - _Color: {r: 0.09849727, g: 1, b: 0, a: 0.15686275} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat.meta b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta similarity index 79% rename from Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat.meta rename to Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta index 9541526..50854eb 100644 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat.meta +++ b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 20d755ab53045e545ab0b6e59c710ed9 +guid: 04f0b2088c857414393bab3b80356776 NativeFormatImporter: externalObjects: {} mainObjectFileID: 2100000 diff --git a/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs new file mode 100644 index 0000000..c30ce4a --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs @@ -0,0 +1,60 @@ +// PredictedRigidbody stores a history of its rigidbody states. +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + // inline everything because this is performance critical! + public struct RigidbodyState : PredictedState + { + public double timestamp { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] private set; } + + // we want to store position delta (last + delta = current), and current. + // this way we can apply deltas on top of corrected positions to get the corrected final position. + public Vector3 positionDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this position + public Vector3 position { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public Quaternion rotationDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this rotation + public Quaternion rotation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public Vector3 velocityDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this velocity + public Vector3 velocity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public Vector3 angularVelocityDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this velocity + public Vector3 angularVelocity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public RigidbodyState( + double timestamp, + Vector3 positionDelta, + Vector3 position, + Quaternion rotationDelta, + Quaternion rotation, + Vector3 velocityDelta, + Vector3 velocity, + Vector3 angularVelocityDelta, + Vector3 angularVelocity) + { + this.timestamp = timestamp; + this.positionDelta = positionDelta; + this.position = position; + this.rotationDelta = rotationDelta; + this.rotation = rotation; + this.velocityDelta = velocityDelta; + this.velocity = velocity; + this.angularVelocityDelta = angularVelocityDelta; + this.angularVelocity = angularVelocity; + } + + public static RigidbodyState Interpolate(RigidbodyState a, RigidbodyState b, float t) + { + return new RigidbodyState + { + position = Vector3.Lerp(a.position, b.position, t), + // Quaternions always need to be normalized in order to be a valid rotation after operations + rotation = Quaternion.Slerp(a.rotation, b.rotation, t).normalized, + velocity = Vector3.Lerp(a.velocity, b.velocity, t), + angularVelocity = Vector3.Lerp(a.angularVelocity, b.angularVelocity, t) + }; + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta new file mode 100644 index 0000000..93affc5 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed0e1c0c874c4c9db6be2d5885bb7bee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/RemoteStatistics.cs b/Assets/Mirror/Components/RemoteStatistics.cs index 6e872b1..5b3ede9 100644 --- a/Assets/Mirror/Components/RemoteStatistics.cs +++ b/Assets/Mirror/Components/RemoteStatistics.cs @@ -91,7 +91,7 @@ public class RemoteStatistics : NetworkBehaviour [Header("GUI")] public bool showGui; - public KeyCode hotKey = KeyCode.F11; + public KeyCode hotKey = KeyCode.BackQuote; Rect windowRect = new Rect(0, 0, 400, 400); // password can't be stored in code or in Unity project. @@ -133,8 +133,9 @@ void LoadPassword() } } - void OnValidate() + protected override void OnValidate() { + base.OnValidate(); syncMode = SyncMode.Owner; } @@ -209,6 +210,7 @@ void UpdateServer() )); } } + void UpdateClient() { if (Input.GetKeyDown(hotKey)) diff --git a/Assets/Mirror/Core/AssemblyInfo.cs b/Assets/Mirror/Core/AssemblyInfo.cs index f342716..a9c6442 100644 --- a/Assets/Mirror/Core/AssemblyInfo.cs +++ b/Assets/Mirror/Core/AssemblyInfo.cs @@ -10,3 +10,4 @@ [assembly: InternalsVisibleTo("Mirror.Tests.Performance.Editor")] [assembly: InternalsVisibleTo("Mirror.Tests.Performance.Runtime")] [assembly: InternalsVisibleTo("Mirror.Editor")] +[assembly: InternalsVisibleTo("Mirror.Components")] diff --git a/Assets/Mirror/Core/Attributes.cs b/Assets/Mirror/Core/Attributes.cs index 39b06fd..0aebfba 100644 --- a/Assets/Mirror/Core/Attributes.cs +++ b/Assets/Mirror/Core/Attributes.cs @@ -4,8 +4,12 @@ namespace Mirror { /// - /// SyncVars are used to synchronize a variable from the server to all clients automatically. - /// Value must be changed on server, not directly by clients. Hook parameter allows you to define a client-side method to be invoked when the client gets an update from the server. + /// SyncVars are used to automatically synchronize a variable between the server and all clients. The direction of synchronization depends on the Sync Direction property, ServerToClient by default. + /// + /// When Sync Direction is equal to ServerToClient, the value should be changed on the server side and synchronized to all clients. + /// Otherwise, the value should be changed on the client side and synchronized to server and other clients. + /// + /// Hook parameter allows you to define a method to be invoked when gets an value update. Notice that the hook method will not be called on the change side. /// [AttributeUsage(AttributeTargets.Field)] public class SyncVarAttribute : PropertyAttribute @@ -82,4 +86,10 @@ public class SceneAttribute : PropertyAttribute {} /// [AttributeUsage(AttributeTargets.Field)] public class ShowInInspectorAttribute : Attribute {} + + /// + /// Used to make a field readonly in the inspector + /// + [AttributeUsage(AttributeTargets.Field)] + public class ReadOnlyAttribute : PropertyAttribute {} } diff --git a/Assets/Mirror/Core/Batching/Batcher.cs b/Assets/Mirror/Core/Batching/Batcher.cs index 3a8d457..41f467d 100644 --- a/Assets/Mirror/Core/Batching/Batcher.cs +++ b/Assets/Mirror/Core/Batching/Batcher.cs @@ -29,8 +29,17 @@ public class Batcher // they would not contain a timestamp readonly int threshold; - // TimeStamp header size for those who need it - public const int HeaderSize = sizeof(double); + // TimeStamp header size. each batch has one. + public const int TimestampSize = sizeof(double); + + // Message header size. each message has one. + public static int MessageHeaderSize(int messageSize) => + Compression.VarUIntSize((ulong)messageSize); + + // maximum overhead for a single message. + // useful for the outside to calculate max message sizes. + public static int MaxMessageOverhead(int messageSize) => + TimestampSize + MessageHeaderSize(messageSize); // full batches ready to be sent. // DO NOT queue NetworkMessage, it would box. @@ -38,7 +47,7 @@ public class Batcher // it would allocate too many writers. // https://github.com/vis2k/Mirror/pull/3127 // => best to build batches on the fly. - Queue batches = new Queue(); + readonly Queue batches = new Queue(); // current batch in progress NetworkWriterPooled batch; @@ -53,13 +62,17 @@ public Batcher(int threshold) // caller needs to make sure they are within max packet size. public void AddMessage(ArraySegment message, double timeStamp) { + // predict the needed size, which is varint(size) + content + int headerSize = Compression.VarUIntSize((ulong)message.Count); + int neededSize = headerSize + message.Count; + // when appending to a batch in progress, check final size. // if it expands beyond threshold, then we should finalize it first. // => less than or exactly threshold is fine. // GetBatch() will finalize it. // => see unit tests. if (batch != null && - batch.Position + message.Count > threshold) + batch.Position + neededSize > threshold) { batches.Enqueue(batch); batch = null; @@ -82,6 +95,16 @@ public void AddMessage(ArraySegment message, double timeStamp) // -> we do allow > threshold sized messages as single batch // -> WriteBytes instead of WriteSegment because the latter // would add a size header. we want to write directly. + // + // include size prefix as varint! + // -> fixes NetworkMessage serialization mismatch corrupting the + // next message in a batch. + // -> a _lot_ of time was wasted debugging corrupt batches. + // no easy way to figure out which NetworkMessage has a mismatch. + // -> this is worth everyone's sanity. + // -> varint means we prefix with 1 byte most of the time. + // -> the same issue in NetworkIdentity was why Mirror started! + Compression.CompressVarUInt(batch, (ulong)message.Count); batch.WriteBytes(message.Array, message.Offset, message.Count); } @@ -123,5 +146,22 @@ public bool GetBatch(NetworkWriter writer) // nothing was written return false; } + + // return all batches to the pool for cleanup + public void Clear() + { + // return batch in progress + if (batch != null) + { + NetworkWriterPool.Return(batch); + batch = null; + } + + // return all queued batches + foreach (NetworkWriterPooled queued in batches) + NetworkWriterPool.Return(queued); + + batches.Clear(); + } } } diff --git a/Assets/Mirror/Core/Batching/Unbatcher.cs b/Assets/Mirror/Core/Batching/Unbatcher.cs index 997b54a..6b2c405 100644 --- a/Assets/Mirror/Core/Batching/Unbatcher.cs +++ b/Assets/Mirror/Core/Batching/Unbatcher.cs @@ -14,13 +14,13 @@ public class Unbatcher { // supporting adding multiple batches before GetNextMessage is called. // just in case. - Queue batches = new Queue(); + readonly Queue batches = new Queue(); public int BatchesCount => batches.Count; // NetworkReader is only created once, // then pointed to the first batch. - NetworkReader reader = new NetworkReader(new byte[0]); + readonly NetworkReader reader = new NetworkReader(new byte[0]); // timestamp that was written into the batch remotely. // for the batch that our reader is currently pointed at. @@ -48,7 +48,7 @@ public bool AddBatch(ArraySegment batch) // don't need to check against that. // make sure we have at least 8 bytes to read for tick timestamp - if (batch.Count < Batcher.HeaderSize) + if (batch.Count < Batcher.TimestampSize) return false; // put into a (pooled) writer @@ -69,43 +69,22 @@ public bool AddBatch(ArraySegment batch) } // get next message, unpacked from batch (if any) + // message ArraySegment is only valid until the next call. // timestamp is the REMOTE time when the batch was created remotely. - public bool GetNextMessage(out NetworkReader message, out double remoteTimeStamp) + public bool GetNextMessage(out ArraySegment message, out double remoteTimeStamp) { - // getting messages would be easy via - // <> - // but to save A LOT of bandwidth, we use - // < - // in other words, we don't know where the current message ends - // - // BUT: it doesn't matter! - // -> we simply return the reader - // * if we have one yet - // * and if there's more to read - // -> the caller can then read one message from it - // -> when the end is reached, we retire the batch! - // - // for example: - // while (GetNextMessage(out message)) - // ProcessMessage(message); - // - message = null; + message = default; + remoteTimeStamp = 0; // do nothing if we don't have any batches. // otherwise the below queue.Dequeue() would throw an // InvalidOperationException if operating on empty queue. if (batches.Count == 0) - { - remoteTimeStamp = 0; return false; - } // was our reader pointed to anything yet? if (reader.Capacity == 0) - { - remoteTimeStamp = 0; return false; - } // no more data to read? if (reader.Remaining == 0) @@ -123,19 +102,27 @@ public bool GetNextMessage(out NetworkReader message, out double remoteTimeStamp StartReadingBatch(next); } // otherwise there's nothing more to read - else - { - remoteTimeStamp = 0; - return false; - } + else return false; } // use the current batch's remote timestamp // AFTER potentially moving to the next batch ABOVE! remoteTimeStamp = readerRemoteTimeStamp; - // if we got here, then we have more data to read. - message = reader; + // enough data to read the size prefix? + if (reader.Remaining == 0) + return false; + + // read the size prefix as varint + // see Batcher.AddMessage comments for explanation. + int size = (int)Compression.DecompressVarUInt(reader); + + // validate size prefix, in case attackers send malicious data + if (reader.Remaining < size) + return false; + + // return the message of size + message = reader.ReadBytesSegment(size); return true; } } diff --git a/Assets/Mirror/Core/ConnectionQuality.cs b/Assets/Mirror/Core/ConnectionQuality.cs new file mode 100644 index 0000000..ee0720a --- /dev/null +++ b/Assets/Mirror/Core/ConnectionQuality.cs @@ -0,0 +1,74 @@ +// standalone, Unity-independent connection-quality algorithm & enum. +// don't need to use this directly, it's built into Mirror's NetworkClient. +using UnityEngine; + +namespace Mirror +{ + public enum ConnectionQuality : byte + { + ESTIMATING, // still estimating + POOR, // unplayable + FAIR, // very noticeable latency, not very enjoyable anymore + GOOD, // very playable for everyone but high level competitors + EXCELLENT // ideal experience for high level competitors + } + + public enum ConnectionQualityMethod : byte + { + Simple, // simple estimation based on rtt and jitter + Pragmatic // based on snapshot interpolation adjustment + } + + // provide different heuristics for users to choose from. + // simple heuristics to get started. + // this will be iterated on over time based on user feedback. + public static class ConnectionQualityHeuristics + { + // convenience extension to color code Connection Quality + public static Color ColorCode(this ConnectionQuality quality) + { + switch (quality) + { + case ConnectionQuality.POOR: return Color.red; + case ConnectionQuality.FAIR: return new Color(1.0f, 0.647f, 0.0f); + case ConnectionQuality.GOOD: return Color.yellow; + case ConnectionQuality.EXCELLENT: return Color.green; + default: return Color.gray; // ESTIMATING + } + } + + // straight forward estimation + // rtt: average round trip time in seconds. + // jitter: average latency variance. + public static ConnectionQuality Simple(double rtt, double jitter) + { + if (rtt <= 0.100 && jitter <= 0.10) return ConnectionQuality.EXCELLENT; + if (rtt <= 0.200 && jitter <= 0.20) return ConnectionQuality.GOOD; + if (rtt <= 0.400 && jitter <= 0.50) return ConnectionQuality.FAIR; + return ConnectionQuality.POOR; + } + + // snapshot interpolation based estimation. + // snap. interp. adjusts buffer time based on connection quality. + // based on this, we can measure how far away we are from the ideal. + // the returned quality will always directly correlate with gameplay. + // => requires SnapshotInterpolation dynamicAdjustment to be enabled! + public static ConnectionQuality Pragmatic(double targetBufferTime, double currentBufferTime) + { + // buffer time is set by the game developer. + // estimating in multiples is a great way to be game independent. + // for example, a fast paced shooter and a slow paced RTS will both + // have poor connection if the multiplier is >10. + double multiplier = currentBufferTime / targetBufferTime; + + // empirically measured with Tanks demo + LatencySimulation. + // it's not obvious to estimate on paper. + if (multiplier <= 1.15) return ConnectionQuality.EXCELLENT; + if (multiplier <= 1.25) return ConnectionQuality.GOOD; + if (multiplier <= 1.50) return ConnectionQuality.FAIR; + + // anything else is poor + return ConnectionQuality.POOR; + } + } +} diff --git a/Assets/Mirror/Core/ConnectionQuality.cs.meta b/Assets/Mirror/Core/ConnectionQuality.cs.meta new file mode 100644 index 0000000..1712ffe --- /dev/null +++ b/Assets/Mirror/Core/ConnectionQuality.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff663b880e33e4606b545c8b497041c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty.meta b/Assets/Mirror/Core/Empty.meta deleted file mode 100644 index e702402..0000000 --- a/Assets/Mirror/Core/Empty.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: a99666a026b14cf6ba1a2b65946b1b27 -timeCreated: 1615288671 \ No newline at end of file diff --git a/Assets/Mirror/Core/Empty/ClientScene.cs b/Assets/Mirror/Core/Empty/ClientScene.cs deleted file mode 100644 index 0d1b96e..0000000 --- a/Assets/Mirror/Core/Empty/ClientScene.cs +++ /dev/null @@ -1 +0,0 @@ -// moved into NetworkClient on 2021-03-07 diff --git a/Assets/Mirror/Core/Empty/Cloud/ApiConnector.cs b/Assets/Mirror/Core/Empty/Cloud/ApiConnector.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ApiConnector.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ApiUpdater.cs b/Assets/Mirror/Core/Empty/Cloud/ApiUpdater.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ApiUpdater.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/Ball.cs b/Assets/Mirror/Core/Empty/Cloud/Ball.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Ball.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/BallManager.cs b/Assets/Mirror/Core/Empty/Cloud/BallManager.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/BallManager.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/BallManager.cs.meta b/Assets/Mirror/Core/Empty/Cloud/BallManager.cs.meta deleted file mode 100644 index b914a33..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/BallManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9cc796972dc396a42ba3686bd952e329 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/BaseApi.cs b/Assets/Mirror/Core/Empty/Cloud/BaseApi.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/BaseApi.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/BaseApi.cs.meta b/Assets/Mirror/Core/Empty/Cloud/BaseApi.cs.meta deleted file mode 100644 index f66b84e..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/BaseApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 70f563b7a7210ae43bbcde5cb7721a94 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/Events.cs b/Assets/Mirror/Core/Empty/Cloud/Events.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Events.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/Events.cs.meta b/Assets/Mirror/Core/Empty/Cloud/Events.cs.meta deleted file mode 100644 index 150d85b..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Events.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c7c472a3ea1bc4348bd5a0b05bf7cc3b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/Extensions.cs b/Assets/Mirror/Core/Empty/Cloud/Extensions.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Extensions.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/Extensions.cs.meta b/Assets/Mirror/Core/Empty/Cloud/Extensions.cs.meta deleted file mode 100644 index 6bf6291..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Extensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 97501e783fc67a4459b15d10e6c63563 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs b/Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs.meta deleted file mode 100644 index f1149a9..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ICoroutineRunner.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 43472c60a7c72e54eafe559290dd0fc6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs b/Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs.meta b/Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs.meta deleted file mode 100644 index 966c503..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/IRequestCreator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b80b95532a9d6e8418aa676a261e4f69 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs b/Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs.meta b/Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs.meta deleted file mode 100644 index 7cb2a59..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/IUnityEqualCheck.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 05185b973ba389a4588fc8a99c75a4f6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs b/Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs.meta b/Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs.meta deleted file mode 100644 index 4b7219b..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/InstantiateNetworkManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dbabb497385c20346a3c8bda4ae69508 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs b/Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs.meta b/Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs.meta deleted file mode 100644 index 2c04009..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/JsonStructs.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0688c0fdae5376e4ea74d5c3904eed17 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServer.cs b/Assets/Mirror/Core/Empty/Cloud/ListServer.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServer.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServer.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ListServer.cs.meta deleted file mode 100644 index 519876d..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6f0311899162c5b49a3c11fa9bd9c133 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs b/Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs.meta deleted file mode 100644 index a9d32ea..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerBaseApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b6838f9df45594d48873518cbb75b329 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs b/Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs.meta deleted file mode 100644 index 306bf7c..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerClientApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d49649fb32cb96b46b10f013b38a4b50 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs b/Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs.meta deleted file mode 100644 index 7e206f1..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerJson.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a963606335eae0f47abe7ecb5fd028ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs b/Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs.meta deleted file mode 100644 index 82e23fd..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ListServerServerApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 675f0d0fd4e82b04290c4d30c8d78ede -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/Logger.cs b/Assets/Mirror/Core/Empty/Cloud/Logger.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Logger.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/Logger.cs.meta b/Assets/Mirror/Core/Empty/Cloud/Logger.cs.meta deleted file mode 100644 index 5984ce3..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Logger.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 457ba2df6cb6e1542996c17c715ee81b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs b/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs.meta b/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs.meta deleted file mode 100644 index 86775df..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 95bebb8e810e2954485291a26324f7d5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs b/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs.meta b/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs.meta deleted file mode 100644 index 5c4294f..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/NetworkManagerListServerPong.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 068feff770f710141afa4a90063a5e6c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/Player.cs b/Assets/Mirror/Core/Empty/Cloud/Player.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Player.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/Player.cs.meta b/Assets/Mirror/Core/Empty/Cloud/Player.cs.meta deleted file mode 100644 index 1c85828..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/Player.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2b6cfd54b79bb464dbc6ae7f331ed45f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs b/Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs.meta b/Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs.meta deleted file mode 100644 index 4a22565..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/QuickListServerDebug.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 07d1ea5260bc06e4d831c4b61d494bff -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs b/Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs.meta b/Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs.meta deleted file mode 100644 index 67341ea..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/QuitButtonHUD.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 76dab753e7255254687cd57985d8d675 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs b/Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs.meta b/Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs.meta deleted file mode 100644 index eb139af..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/RequestCreator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cfaa626443cc7c94eae138a2e3a04d7c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs b/Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs.meta deleted file mode 100644 index 74c6a0f..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ServerListManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bfc354d4a7f63ca45a653bf5d479afa0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs b/Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs.meta deleted file mode 100644 index f7fe4f2..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ServerListUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ed11184fcffcdc04c9850d82c8014926 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs b/Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs deleted file mode 100644 index 2f11787..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 diff --git a/Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs.meta b/Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs.meta deleted file mode 100644 index d8857e8..0000000 --- a/Assets/Mirror/Core/Empty/Cloud/ServerListUIItem.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c67eda1b451338a428df87fda1e3a7c9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/DotNetCompatibility.cs b/Assets/Mirror/Core/Empty/DotNetCompatibility.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/DotNetCompatibility.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/DotNetCompatibility.cs.meta b/Assets/Mirror/Core/Empty/DotNetCompatibility.cs.meta deleted file mode 100644 index 8742197..0000000 --- a/Assets/Mirror/Core/Empty/DotNetCompatibility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b307f850ccbbe450295acf24d70e5c28 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/FallbackTransport.cs b/Assets/Mirror/Core/Empty/FallbackTransport.cs deleted file mode 100644 index 57f3344..0000000 --- a/Assets/Mirror/Core/Empty/FallbackTransport.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-05-13 \ No newline at end of file diff --git a/Assets/Mirror/Core/Empty/LogFactory.cs b/Assets/Mirror/Core/Empty/LogFactory.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/LogFactory.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/LogFactory.cs.meta b/Assets/Mirror/Core/Empty/LogFactory.cs.meta deleted file mode 100644 index 0715501..0000000 --- a/Assets/Mirror/Core/Empty/LogFactory.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 353c7c9e14e82f349b1679112050b196 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/LogFilter.cs b/Assets/Mirror/Core/Empty/LogFilter.cs deleted file mode 100644 index 391c5bd..0000000 --- a/Assets/Mirror/Core/Empty/LogFilter.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-03-08 diff --git a/Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs b/Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs.meta b/Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs.meta deleted file mode 100644 index 329c6eb..0000000 --- a/Assets/Mirror/Core/Empty/Logging/ConsoleColorLogHandler.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2a9618569c20a504aa86feb5913c70e9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs b/Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs.meta b/Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs.meta deleted file mode 100644 index 81b33e9..0000000 --- a/Assets/Mirror/Core/Empty/Logging/EditorLogSettingsLoader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a39aa1e48aa54eb4e964f0191c1dcdce -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Logging/LogFactory.cs b/Assets/Mirror/Core/Empty/Logging/LogFactory.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/Logging/LogFactory.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/Logging/LogFactory.cs.meta b/Assets/Mirror/Core/Empty/Logging/LogFactory.cs.meta deleted file mode 100644 index acf3b63..0000000 --- a/Assets/Mirror/Core/Empty/Logging/LogFactory.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d06522432d5a44e1587967a4731cd279 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Logging/LogSettings.cs b/Assets/Mirror/Core/Empty/Logging/LogSettings.cs deleted file mode 100644 index 264a1cd..0000000 --- a/Assets/Mirror/Core/Empty/Logging/LogSettings.cs +++ /dev/null @@ -1,2 +0,0 @@ -// removed 2021-02-16 - diff --git a/Assets/Mirror/Core/Empty/Logging/LogSettings.cs.meta b/Assets/Mirror/Core/Empty/Logging/LogSettings.cs.meta deleted file mode 100644 index 90c4e4d..0000000 --- a/Assets/Mirror/Core/Empty/Logging/LogSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 633889a39717fde4fa28dd6b948dfac7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/Logging/NetworkHeadlessLogger.cs b/Assets/Mirror/Core/Empty/Logging/NetworkHeadlessLogger.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/Logging/NetworkHeadlessLogger.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs b/Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs.meta b/Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs.meta deleted file mode 100644 index 2f7ecdf..0000000 --- a/Assets/Mirror/Core/Empty/Logging/NetworkLogSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ac6e8eccf4b6f4dc7b24c276ef47fde8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/NetworkMatchChecker.cs b/Assets/Mirror/Core/Empty/NetworkMatchChecker.cs deleted file mode 100644 index 3797620..0000000 --- a/Assets/Mirror/Core/Empty/NetworkMatchChecker.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-01-06 diff --git a/Assets/Mirror/Core/Empty/NetworkMatchChecker.cs.meta b/Assets/Mirror/Core/Empty/NetworkMatchChecker.cs.meta deleted file mode 100644 index 7c7d6cf..0000000 --- a/Assets/Mirror/Core/Empty/NetworkMatchChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/Core/Empty/NetworkOwnerChecker.cs b/Assets/Mirror/Core/Empty/NetworkOwnerChecker.cs deleted file mode 100644 index 712833c..0000000 --- a/Assets/Mirror/Core/Empty/NetworkOwnerChecker.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-01-06 diff --git a/Assets/Mirror/Core/Empty/NetworkOwnerChecker.cs.meta b/Assets/Mirror/Core/Empty/NetworkOwnerChecker.cs.meta deleted file mode 100644 index fee7725..0000000 --- a/Assets/Mirror/Core/Empty/NetworkOwnerChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/Core/Empty/NetworkProximityChecker.cs b/Assets/Mirror/Core/Empty/NetworkProximityChecker.cs deleted file mode 100644 index 3797620..0000000 --- a/Assets/Mirror/Core/Empty/NetworkProximityChecker.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-01-06 diff --git a/Assets/Mirror/Core/Empty/NetworkProximityChecker.cs.meta b/Assets/Mirror/Core/Empty/NetworkProximityChecker.cs.meta deleted file mode 100644 index c5aa112..0000000 --- a/Assets/Mirror/Core/Empty/NetworkProximityChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/Core/Empty/NetworkSceneChecker.cs b/Assets/Mirror/Core/Empty/NetworkSceneChecker.cs deleted file mode 100644 index 3797620..0000000 --- a/Assets/Mirror/Core/Empty/NetworkSceneChecker.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-01-06 diff --git a/Assets/Mirror/Core/Empty/NetworkSceneChecker.cs.meta b/Assets/Mirror/Core/Empty/NetworkSceneChecker.cs.meta deleted file mode 100644 index b451655..0000000 --- a/Assets/Mirror/Core/Empty/NetworkSceneChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/Core/Empty/NetworkTransformBase.cs b/Assets/Mirror/Core/Empty/NetworkTransformBase.cs deleted file mode 100644 index 79e858f..0000000 --- a/Assets/Mirror/Core/Empty/NetworkTransformBase.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-10-24 diff --git a/Assets/Mirror/Core/Empty/NetworkVisibility.cs b/Assets/Mirror/Core/Empty/NetworkVisibility.cs deleted file mode 100644 index 3797620..0000000 --- a/Assets/Mirror/Core/Empty/NetworkVisibility.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-01-06 diff --git a/Assets/Mirror/Core/Empty/NetworkVisibility.cs.meta b/Assets/Mirror/Core/Empty/NetworkVisibility.cs.meta deleted file mode 100644 index f71b7be..0000000 --- a/Assets/Mirror/Core/Empty/NetworkVisibility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c08f1a030234d49d391d7223a8592f15 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/StringHash.cs b/Assets/Mirror/Core/Empty/StringHash.cs deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Core/Empty/StringHash.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Core/Empty/StringHash.cs.meta b/Assets/Mirror/Core/Empty/StringHash.cs.meta deleted file mode 100644 index 6198581..0000000 --- a/Assets/Mirror/Core/Empty/StringHash.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 733f020f9b76d453da841089579fd7a7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/SyncVar.cs b/Assets/Mirror/Core/Empty/SyncVar.cs deleted file mode 100644 index aaa3b9d..0000000 --- a/Assets/Mirror/Core/Empty/SyncVar.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-11-03 diff --git a/Assets/Mirror/Core/Empty/SyncVar.cs.meta b/Assets/Mirror/Core/Empty/SyncVar.cs.meta deleted file mode 100644 index fffb472..0000000 --- a/Assets/Mirror/Core/Empty/SyncVar.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5e87cb681af8459fbbb1f467e1c7632c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/SyncVarGameObject.cs b/Assets/Mirror/Core/Empty/SyncVarGameObject.cs deleted file mode 100644 index aaa3b9d..0000000 --- a/Assets/Mirror/Core/Empty/SyncVarGameObject.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-11-03 diff --git a/Assets/Mirror/Core/Empty/SyncVarGameObject.cs.meta b/Assets/Mirror/Core/Empty/SyncVarGameObject.cs.meta deleted file mode 100644 index 4e924f0..0000000 --- a/Assets/Mirror/Core/Empty/SyncVarGameObject.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 84da90dae05442e3a149753c9b25ae98 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs b/Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs deleted file mode 100644 index aaa3b9d..0000000 --- a/Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-11-03 diff --git a/Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs.meta b/Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs.meta deleted file mode 100644 index 0ceab50..0000000 --- a/Assets/Mirror/Core/Empty/SyncVarNetworkBehaviour.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c0fff77f1a624ba8ad6e4bdef6c14a8b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs b/Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs deleted file mode 100644 index aaa3b9d..0000000 --- a/Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-11-03 diff --git a/Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs.meta b/Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs.meta deleted file mode 100644 index 53271d4..0000000 --- a/Assets/Mirror/Core/Empty/SyncVarNetworkIdentity.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1f9a6d4d2741477999ad9588261870fe -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Core/HostMode.cs b/Assets/Mirror/Core/HostMode.cs index e5bb2c0..3054b3c 100644 --- a/Assets/Mirror/Core/HostMode.cs +++ b/Assets/Mirror/Core/HostMode.cs @@ -40,9 +40,5 @@ public static void InvokeOnConnected() //OnConnectedEvent?.Invoke(connection); ((LocalConnectionToServer)NetworkClient.connection).QueueConnectedEvent(); } - - // DEPRECATED 2023-01-28 - [Obsolete("ActivateHostScene did nothing, since identities all had .isClient set in NetworkServer.SpawnObjects.")] - public static void ActivateHostScene() {} } } diff --git a/Assets/Mirror/Core/InterestManagement.cs b/Assets/Mirror/Core/InterestManagement.cs index 8556831..88ead0f 100644 --- a/Assets/Mirror/Core/InterestManagement.cs +++ b/Assets/Mirror/Core/InterestManagement.cs @@ -1,5 +1,6 @@ // interest management component for custom solutions like // distance based, spatial hashing, raycast based, etc. + using System.Collections.Generic; using UnityEngine; @@ -7,36 +8,11 @@ namespace Mirror { [DisallowMultipleComponent] [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] - public abstract class InterestManagement : MonoBehaviour + public abstract class InterestManagement : InterestManagementBase { - // Awake configures InterestManagement in NetworkServer/Client - // Do NOT check for active server or client here. - // Awake must always set the static aoi references. - // make sure to call base.Awake when overwriting! - protected virtual void Awake() - { - if (NetworkServer.aoi == null) - { - NetworkServer.aoi = this; - } - else Debug.LogError($"Only one InterestManagement component allowed. {NetworkServer.aoi.GetType()} has been set up already."); - - if (NetworkClient.aoi == null) - { - NetworkClient.aoi = this; - } - else Debug.LogError($"Only one InterestManagement component allowed. {NetworkClient.aoi.GetType()} has been set up already."); - } - - [ServerCallback] - public virtual void Reset() {} - - // Callback used by the visibility system to determine if an observer - // (player) can see the NetworkIdentity. If this function returns true, - // the network connection will be added as an observer. - // conn: Network connection of a player. - // returns True if the player can see this object. - public abstract bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver); + // allocate newObservers helper HashSet + readonly HashSet newObservers = + new HashSet(); // rebuild observers for the given NetworkIdentity. // Server will automatically spawn/despawn added/removed ones. @@ -72,29 +48,99 @@ protected void RebuildAll() } } - // Callback used by the visibility system for objects on a host. - // Objects on a host (with a local client) cannot be disabled or - // destroyed when they are not visible to the local client. So this - // function is called to allow custom code to hide these objects. A - // typical implementation will disable renderer components on the - // object. This is only called on local clients on a host. - // => need the function in here and virtual so people can overwrite! - // => not everyone wants to hide renderers! - [ServerCallback] - public virtual void SetHostVisibility(NetworkIdentity identity, bool visible) + public override void Rebuild(NetworkIdentity identity, bool initialize) { - foreach (Renderer rend in identity.GetComponentsInChildren()) - rend.enabled = visible; - } + // clear newObservers hashset before using it + newObservers.Clear(); - /// Called on the server when a new networked object is spawned. - // (useful for 'only rebuild if changed' interest management algorithms) - [ServerCallback] - public virtual void OnSpawned(NetworkIdentity identity) {} + // not force hidden? + if (identity.visibility != Visibility.ForceHidden) + { + OnRebuildObservers(identity, newObservers); + } - /// Called on the server when a networked object is destroyed. - // (useful for 'only rebuild if changed' interest management algorithms) - [ServerCallback] - public virtual void OnDestroyed(NetworkIdentity identity) {} + // IMPORTANT: AFTER rebuilding add own player connection in any case + // to ensure player always sees himself no matter what. + // -> OnRebuildObservers might clear observers, so we need to add + // the player's own connection AFTER. 100% fail safe. + // -> fixes https://github.com/vis2k/Mirror/issues/692 where a + // player might teleport out of the ProximityChecker's cast, + // losing the own connection as observer. + if (identity.connectionToClient != null) + { + newObservers.Add(identity.connectionToClient); + } + + bool changed = false; + + // add all newObservers that aren't in .observers yet + foreach (NetworkConnectionToClient conn in newObservers) + { + // only add ready connections. + // otherwise the player might not be in the world yet or anymore + if (conn != null && conn.isReady) + { + if (initialize || !identity.observers.ContainsKey(conn.connectionId)) + { + // new observer + conn.AddToObserving(identity); + // Debug.Log($"New Observer for {gameObject} {conn}"); + changed = true; + } + } + } + + // remove all old .observers that aren't in newObservers anymore + foreach (NetworkConnectionToClient conn in identity.observers.Values) + { + if (!newObservers.Contains(conn)) + { + // removed observer + conn.RemoveFromObserving(identity, false); + // Debug.Log($"Removed Observer for {gameObject} {conn}"); + changed = true; + } + } + + // copy new observers to observers + if (changed) + { + identity.observers.Clear(); + foreach (NetworkConnectionToClient conn in newObservers) + { + if (conn != null && conn.isReady) + identity.observers.Add(conn.connectionId, conn); + } + } + + // special case for host mode: we use SetHostVisibility to hide + // NetworkIdentities that aren't in observer range from host. + // this is what games like Dota/Counter-Strike do too, where a host + // does NOT see all players by default. they are in memory, but + // hidden to the host player. + // + // this code is from UNET, it's a bit strange but it works: + // * it hides newly connected identities in host mode + // => that part was the intended behaviour + // * it hides ALL NetworkIdentities in host mode when the host + // connects but hasn't selected a character yet + // => this only works because we have no .localConnection != null + // check. at this stage, localConnection is null because + // StartHost starts the server first, then calls this code, + // then starts the client and sets .localConnection. so we can + // NOT add a null check without breaking host visibility here. + // * it hides ALL NetworkIdentities in server-only mode because + // observers never contain the 'null' .localConnection + // => that was not intended, but let's keep it as it is so we + // don't break anything in host mode. it's way easier than + // iterating all identities in a special function in StartHost. + if (initialize) + { + if (!newObservers.Contains(NetworkServer.localConnection)) + { + SetHostVisibility(identity, false); + } + } + } } } diff --git a/Assets/Mirror/Core/InterestManagementBase.cs b/Assets/Mirror/Core/InterestManagementBase.cs new file mode 100644 index 0000000..ec60d64 --- /dev/null +++ b/Assets/Mirror/Core/InterestManagementBase.cs @@ -0,0 +1,77 @@ +// interest management component for custom solutions like +// distance based, spatial hashing, raycast based, etc. +// low level base class allows for low level spatial hashing etc., which is 3-5x faster. +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] + public abstract class InterestManagementBase : MonoBehaviour + { + // initialize NetworkServer/Client .aoi. + // previously we did this in Awake(), but that's called for disabled + // components too. if we do it OnEnable(), then it's not set for + // disabled components. + protected virtual void OnEnable() + { + // do not check if == null or error if already set. + // users may enabled/disable components randomly, + // causing this to be called multiple times. + NetworkServer.aoi = this; + NetworkClient.aoi = this; + } + + [ServerCallback] + public virtual void ResetState() {} + + // Callback used by the visibility system to determine if an observer + // (player) can see the NetworkIdentity. If this function returns true, + // the network connection will be added as an observer. + // conn: Network connection of a player. + // returns True if the player can see this object. + public abstract bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver); + + + // Callback used by the visibility system for objects on a host. + // Objects on a host (with a local client) cannot be disabled or + // destroyed when they are not visible to the local client. So this + // function is called to allow custom code to hide these objects. A + // typical implementation will disable renderer components on the + // object. This is only called on local clients on a host. + // => need the function in here and virtual so people can overwrite! + // => not everyone wants to hide renderers! + [ServerCallback] + public virtual void SetHostVisibility(NetworkIdentity identity, bool visible) + { + foreach (Renderer rend in identity.GetComponentsInChildren()) + rend.enabled = visible; + } + + /// Called on the server when a new networked object is spawned. + // (useful for 'only rebuild if changed' interest management algorithms) + [ServerCallback] + public virtual void OnSpawned(NetworkIdentity identity) {} + + /// Called on the server when a networked object is destroyed. + // (useful for 'only rebuild if changed' interest management algorithms) + [ServerCallback] + public virtual void OnDestroyed(NetworkIdentity identity) {} + + public abstract void Rebuild(NetworkIdentity identity, bool initialize); + + /// Adds the specified connection to the observers of identity + protected void AddObserver(NetworkConnectionToClient connection, NetworkIdentity identity) + { + connection.AddToObserving(identity); + identity.observers.Add(connection.connectionId, connection); + } + + /// Removes the specified connection from the observers of identity + protected void RemoveObserver(NetworkConnectionToClient connection, NetworkIdentity identity) + { + connection.RemoveFromObserving(identity, false); + identity.observers.Remove(connection.connectionId); + } + } +} diff --git a/Assets/Mirror/Core/InterestManagementBase.cs.meta b/Assets/Mirror/Core/InterestManagementBase.cs.meta new file mode 100644 index 0000000..b2b5ad6 --- /dev/null +++ b/Assets/Mirror/Core/InterestManagementBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18bd2ffe65a444f3b13d59bdac7f2228 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/LagCompensation.meta b/Assets/Mirror/Core/LagCompensation.meta new file mode 100644 index 0000000..b5583ef --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d2656015ded44e83a24f4c4776bafd40 +timeCreated: 1687920405 \ No newline at end of file diff --git a/Assets/Mirror/Core/LagCompensation/Capture.cs b/Assets/Mirror/Core/LagCompensation/Capture.cs new file mode 100644 index 0000000..e4fdabe --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/Capture.cs @@ -0,0 +1,13 @@ +namespace Mirror +{ + public interface Capture + { + // server timestamp at time of capture. + double timestamp { get; set; } + + // optional gizmo drawing for visual debugging. + // history is only known on the server, which usually doesn't render. + // showing Gizmos in the Editor is enough. + void DrawGizmo(); + } +} diff --git a/Assets/Mirror/Core/LagCompensation/Capture.cs.meta b/Assets/Mirror/Core/LagCompensation/Capture.cs.meta new file mode 100644 index 0000000..d78c49f --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/Capture.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 347e831952e943a49095cadd39a5aeb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs new file mode 100644 index 0000000..29ebc2e --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs @@ -0,0 +1,139 @@ +// HistoryBounds keeps a bounding box of all the object's bounds in the past N seconds. +// useful to decide which objects to rollback, instead of rolling back all of them. +// https://www.youtube.com/watch?v=zrIY0eIyqmI (37:00) +// standalone C# implementation to be engine (and language) agnostic. + +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // FakeByte: gather bounds in smaller buckets. + // for example, bucket(t0,t1,t2), bucket(t3,t4,t5), ... + // instead of removing old bounds t0, t1, ... + // we remove a whole bucket every 3 times: bucket(t0,t1,t2) + // and when building total bounds, we encapsulate a few larger buckets + // instead of many smaller bounds. + // + // => a bucket is encapsulate(bounds0, bounds1, bounds2) so we don't + // need a custom struct, simply reuse bounds but remember that each + // entry includes N timestamps. + // + // => note that simply reducing capture interval is _not_ the same. + // we want to capture in detail in case players run in zig-zag. + // but still grow larger buckets internally. + public class HistoryBounds + { + // mischa: use MinMaxBounds to avoid Unity Bounds.Encapsulate conversions. + readonly int boundsPerBucket; + readonly Queue fullBuckets; + + // full bucket limit. older ones will be removed. + readonly int bucketLimit; + + // bucket in progress, contains 0..boundsPerBucket bounds encapsulated. + MinMaxBounds? currentBucket; + int currentBucketSize; + + // amount of total bounds, including bounds in full buckets + current + public int boundsCount { get; private set; } + + // total bounds encapsulating all of the bounds history. + // totalMinMax is used for internal calculations. + // public total is used for Unity representation. + MinMaxBounds totalMinMax; + public Bounds total + { + get + { + Bounds bounds = new Bounds(); + bounds.SetMinMax(totalMinMax.min, totalMinMax.max); + return bounds; + } + } + + public HistoryBounds(int boundsLimit, int boundsPerBucket) + { + // bucketLimit via '/' cuts off remainder. + // that's what we want, since we always have a 'currentBucket'. + this.boundsPerBucket = boundsPerBucket; + this.bucketLimit = (boundsLimit / boundsPerBucket); + + // initialize queue with maximum capacity to avoid runtime resizing + // capacity +1 because it makes the code easier if we insert first, and then remove. + fullBuckets = new Queue(bucketLimit + 1); + } + + // insert new bounds into history. calculates new total bounds. + // Queue.Dequeue() always has the oldest bounds. + public void Insert(Bounds bounds) + { + // convert to MinMax representation for faster .Encapsulate() + MinMaxBounds minmax = new MinMaxBounds + { + min = bounds.min, + max = bounds.max + }; + + // initialize 'total' if not initialized yet. + // we don't want to call (0,0).Encapsulate(bounds). + if (boundsCount == 0) + { + totalMinMax = minmax; + } + + // add to current bucket: + // either initialize new one, or encapsulate into existing one + if (currentBucket == null) + { + currentBucket = minmax; + } + else + { + currentBucket.Value.Encapsulate(minmax); + } + + // current bucket has one more bounds. + // total bounds increased as well. + currentBucketSize += 1; + boundsCount += 1; + + // always encapsulate into total immediately. + // this is free. + totalMinMax.Encapsulate(minmax); + + // current bucket full? + if (currentBucketSize == boundsPerBucket) + { + // move it to full buckets + fullBuckets.Enqueue(currentBucket.Value); + currentBucket = null; + currentBucketSize = 0; + + // full bucket capacity reached? + if (fullBuckets.Count > bucketLimit) + { + // remove oldest bucket + fullBuckets.Dequeue(); + boundsCount -= boundsPerBucket; + + // recompute total bounds + // instead of iterating N buckets, we iterate N / boundsPerBucket buckets. + // TODO technically we could reuse 'currentBucket' before clearing instead of encapsulating again + totalMinMax = minmax; + foreach (MinMaxBounds bucket in fullBuckets) + totalMinMax.Encapsulate(bucket); + } + } + } + + public void Reset() + { + fullBuckets.Clear(); + currentBucket = null; + currentBucketSize = 0; + boundsCount = 0; + totalMinMax = new MinMaxBounds(); + } + } +} diff --git a/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta new file mode 100644 index 0000000..5f908b0 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca9ea58b98a34f73801b162cd5de724e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensation.cs b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs new file mode 100644 index 0000000..ae37a3f --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs @@ -0,0 +1,144 @@ +// standalone lag compensation algorithm +// based on the Valve Networking Model: +// https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking +using System.Collections.Generic; + +namespace Mirror +{ + public static class LagCompensation + { + // history is of . + // Queue allows for fast 'remove first' and 'append last'. + // + // make sure to always insert in order. + // inserting out of order like [1,2,4,3] would cause issues. + // can't safeguard this because Queue doesn't have .Last access. + public static void Insert( + Queue> history, + int historyLimit, + double timestamp, + T capture) + where T : Capture + { + // make space according to history limit. + // do this before inserting, to avoid resizing past capacity. + if (history.Count >= historyLimit) + history.Dequeue(); + + // insert + history.Enqueue(new KeyValuePair(timestamp, capture)); + } + + // get the two snapshots closest to a given timestamp. + // those can be used to interpolate the exact snapshot at that time. + // if timestamp is newer than the newest history entry, then we extrapolate. + // 't' will be between 1 and 2, before is second last, after is last. + // callers should Lerp(before, after, t=1.5) to extrapolate the hit. + // see comments below for extrapolation. + public static bool Sample( + Queue> history, + double timestamp, // current server time + double interval, // capture interval + out T before, + out T after, + out double t) // interpolation factor + where T : Capture + { + before = default; + after = default; + t = 0; + + // can't sample an empty history + // interpolation needs at least one entry. + // extrapolation needs at least two entries. + // can't Lerp(A, A, 1.5). dist(A, A) * 1.5 is always 0. + if(history.Count < 2) { + return false; + } + + // older than oldest + if (timestamp < history.Peek().Key) { + return false; + } + + // iterate through the history + // TODO faster version: guess start index by how many 'intervals' we are behind. + // search around that area. + // should be O(1) most of the time, unless sampling was off. + KeyValuePair prev = new KeyValuePair(); + KeyValuePair prevPrev = new KeyValuePair(); + foreach(KeyValuePair entry in history) { + // exact match? + if (timestamp == entry.Key) { + before = entry.Value; + after = entry.Value; + t = Mathd.InverseLerp(before.timestamp, after.timestamp, timestamp); + return true; + } + + // did we check beyond timestamp? then return the previous two. + if (entry.Key > timestamp) { + before = prev.Value; + after = entry.Value; + t = Mathd.InverseLerp(before.timestamp, after.timestamp, timestamp); + return true; + } + + // remember the last two for extrapolation. + // Queue doesn't have access to .Last. + prevPrev = prev; + prev = entry; + } + + // newer than newest: extrapolate up to one interval. + // let's say we capture every 100 ms: + // 100, 200, 300, 400 + // and the server is at 499 + // if a client sends CmdFire at time 480, then there's no history entry. + // => adding the current entry every time would be too expensive. + // worst case we would capture at 401, 402, 403, 404, ... 100 times + // => not extrapolating isn't great. low latency clients would be + // punished by missing their targets since no entry at 'time' was found. + // => extrapolation is the best solution. make sure this works as + // expected and within limits. + if (prev.Key < timestamp && timestamp <= prev.Key + interval) { + // return the last two valid snapshots. + // can't just return (after, after) because we can't extrapolate + // if their distance is 0. + before = prevPrev.Value; + after = prev.Value; + + // InverseLerp will give [after, after+interval]. + // but we return [before, after, t]. + // so add +1 for the distance from before->after + t = 1 + Mathd.InverseLerp(after.timestamp, after.timestamp + interval, timestamp); + return true; + } + + return false; + } + + // never trust the client. + // we estimate when a message was sent. + // don't trust the client to tell us the time. + // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking + // Command Execution Time = Current Server Time - Packet Latency - Client View Interpolation + // => lag compensation demo estimation is off by only ~6ms + public static double EstimateTime(double serverTime, double rtt, double bufferTime) + { + // packet latency is one trip from client to server, so rtt / 2 + // client view interpolation is the snapshot interpolation buffer time + double latency = rtt / 2; + return serverTime - latency - bufferTime; + } + + // convenience function to draw all history gizmos. + // this should be called from OnDrawGizmos. + public static void DrawGizmos(Queue> history) + where T : Capture + { + foreach (KeyValuePair entry in history) + entry.Value.DrawGizmo(); + } + } +} diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta new file mode 100644 index 0000000..452ab21 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad53cc7d12144d0ba3a8b0a4515e5d17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs new file mode 100644 index 0000000..a7ec944 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs @@ -0,0 +1,19 @@ +// snapshot interpolation settings struct. +// can easily be exposed in Unity inspectors. +using System; +using UnityEngine; + +namespace Mirror +{ + // class so we can define defaults easily + [Serializable] + public class LagCompensationSettings + { + [Header("Buffering")] + [Tooltip("Keep this many past snapshots in the buffer. The larger this is, the further we can rewind into the past.\nMaximum rewind time := historyAmount * captureInterval")] + public int historyLimit = 6; + + [Tooltip("Capture state every 'captureInterval' seconds. Larger values will space out the captures more, which gives a longer history but with possible gaps inbetween.\nSmaller values will have fewer gaps, with shorter history.")] + public float captureInterval = 0.100f; // 100 ms + } +} diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta new file mode 100644 index 0000000..4f43a07 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa80bec245f94bf8a28ec78777992a1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs new file mode 100644 index 0000000..b1b4874 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs @@ -0,0 +1,73 @@ +// Unity's Bounds struct is represented as (center, extents). +// HistoryBounds make heavy use of .Encapsulate(), which has to convert +// Unity's (center, extents) to (min, max) every time, and then convert back. +// +// It's faster to use a (min, max) representation directly instead. +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + public struct MinMaxBounds: IEquatable + { + public Vector3 min; + public Vector3 max; + + // encapsulate a single point + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Encapsulate(Vector3 point) + { + min = Vector3.Min(this.min, point); + max = Vector3.Max(this.max, point); + } + + // encapsulate another bounds + public void Encapsulate(MinMaxBounds bounds) + { + Encapsulate(bounds.min); + Encapsulate(bounds.max); + } + + // convenience comparison with Unity's bounds, for unit tests etc. + public static bool operator ==(MinMaxBounds lhs, Bounds rhs) => + lhs.min == rhs.min && + lhs.max == rhs.max; + + public static bool operator !=(MinMaxBounds lhs, Bounds rhs) => + !(lhs == rhs); + + public override bool Equals(object obj) => + obj is MinMaxBounds other && + min == other.min && + max == other.max; + + public bool Equals(MinMaxBounds other) => + min.Equals(other.min) && max.Equals(other.max); + + public bool Equals(Bounds other) => + min.Equals(other.min) && max.Equals(other.max); + +#if UNITY_2021_3_OR_NEWER + // Unity 2019/2020 don't have HashCode.Combine yet. + // this is only to avoid reflection. without defining, it works too. + // default generated by rider + public override int GetHashCode() => HashCode.Combine(min, max); +#else + public override int GetHashCode() + { + // return HashCode.Combine(min, max); without using .Combine for older Unity versions + unchecked + { + int hash = 17; + hash = hash * 23 + min.GetHashCode(); + hash = hash * 23 + max.GetHashCode(); + return hash; + } + } +#endif + + // tostring + public override string ToString() => $"({min}, {max})"; + } +} diff --git a/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta new file mode 100644 index 0000000..3eeb073 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4372b1e1a1cc4c669cc7bf0925f59d29 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/LocalConnectionToClient.cs b/Assets/Mirror/Core/LocalConnectionToClient.cs index 67c9649..c41c6ae 100644 --- a/Assets/Mirror/Core/LocalConnectionToClient.cs +++ b/Assets/Mirror/Core/LocalConnectionToClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Mirror { @@ -8,18 +9,20 @@ public class LocalConnectionToClient : NetworkConnectionToClient { internal LocalConnectionToServer connectionToServer; + // packet queue + internal readonly Queue queue = new Queue(); + public LocalConnectionToClient() : base(LocalConnectionId) {} public override string address => "localhost"; - // Send stage two: serialized NetworkMessage as ArraySegment internal override void Send(ArraySegment segment, int channelId = Channels.Reliable) { - // get a writer to copy the message into since the segment is only - // valid until returning. - // => pooled writer will be returned to pool when dequeuing. - // => WriteBytes instead of WriteArraySegment because the latter - // includes a 4 bytes header. we just want to write raw. + // instead of invoking it directly, we enqueue and process next update. + // this way we can simulate a similar call flow as with remote clients. + // the closer we get to simulating host as remote, the better! + // both directions do this, so [Command] and [Rpc] behave the same way. + //Debug.Log($"Enqueue {BitConverter.ToString(segment.Array, segment.Offset, segment.Count)}"); NetworkWriterPooled writer = NetworkWriterPool.Get(); writer.WriteBytes(segment.Array, segment.Offset, segment.Count); @@ -29,6 +32,38 @@ internal override void Send(ArraySegment segment, int channelId = Channels // true because local connections never timeout internal override bool IsAlive(float timeout) => true; + // don't ping host client in host mode + protected override void UpdatePing() {} + + internal override void Update() + { + base.Update(); + + // process internal messages so they are applied at the correct time + while (queue.Count > 0) + { + // call receive on queued writer's content, return to pool + NetworkWriterPooled writer = queue.Dequeue(); + ArraySegment message = writer.ToArraySegment(); + + // OnTransportData assumes a proper batch with timestamp etc. + // let's make a proper batch and pass it to OnTransportData. + Batcher batcher = GetBatchForChannelId(Channels.Reliable); + batcher.AddMessage(message, NetworkTime.localTime); + + using (NetworkWriterPooled batchWriter = NetworkWriterPool.Get()) + { + // make a batch with our local time (double precision) + if (batcher.GetBatch(batchWriter)) + { + NetworkServer.OnTransportData(connectionId, batchWriter.ToArraySegment(), Channels.Reliable); + } + } + + NetworkWriterPool.Return(writer); + } + } + internal void DisconnectInternal() { // set not ready and handle clientscene disconnect in any case diff --git a/Assets/Mirror/Core/LocalConnectionToServer.cs b/Assets/Mirror/Core/LocalConnectionToServer.cs index 378ffdb..15669c7 100644 --- a/Assets/Mirror/Core/LocalConnectionToServer.cs +++ b/Assets/Mirror/Core/LocalConnectionToServer.cs @@ -13,8 +13,6 @@ public class LocalConnectionToServer : NetworkConnectionToServer // packet queue internal readonly Queue queue = new Queue(); - public override string address => "localhost"; - // see caller for comments on why we need this bool connectedEventPending; bool disconnectedEventPending; @@ -30,22 +28,15 @@ internal override void Send(ArraySegment segment, int channelId = Channels return; } - // OnTransportData assumes batching. - // so let's make a batch with proper timestamp prefix. - Batcher batcher = GetBatchForChannelId(channelId); - batcher.AddMessage(segment, NetworkTime.localTime); + // instead of invoking it directly, we enqueue and process next update. + // this way we can simulate a similar call flow as with remote clients. + // the closer we get to simulating host as remote, the better! + // both directions do this, so [Command] and [Rpc] behave the same way. - // flush it to the server's OnTransportData immediately. - // local connection to server always invokes immediately. - using (NetworkWriterPooled writer = NetworkWriterPool.Get()) - { - // make a batch with our local time (double precision) - if (batcher.GetBatch(writer)) - { - NetworkServer.OnTransportData(connectionId, writer.ToArraySegment(), channelId); - } - else Debug.LogError("Local connection failed to make batch. This should never happen."); - } + //Debug.Log($"Enqueue {BitConverter.ToString(segment.Array, segment.Offset, segment.Count)}"); + NetworkWriterPooled writer = NetworkWriterPool.Get(); + writer.WriteBytes(segment.Array, segment.Offset, segment.Count); + connectionToClient.queue.Enqueue(writer); } internal override void Update() diff --git a/Assets/Mirror/Core/Messages.cs b/Assets/Mirror/Core/Messages.cs index 6ba0bf0..62888c0 100644 --- a/Assets/Mirror/Core/Messages.cs +++ b/Assets/Mirror/Core/Messages.cs @@ -52,15 +52,6 @@ public struct RpcMessage : NetworkMessage public ArraySegment payload; } - // holds multiple buffered rpcs for the given connection. - // more efficient than sending one message per rpc. - public struct RpcBufferMessage : NetworkMessage - { - // payload contains multiple serialized RpcMessages. - // but without the message header. - public ArraySegment payload; - } - public struct SpawnMessage : NetworkMessage { // netId of new or existing object @@ -111,23 +102,39 @@ public struct EntityStateMessage : NetworkMessage public ArraySegment payload; } - // A client sends this message to the server - // to calculate RTT and synchronize time + // whoever wants to measure rtt, sends this to the other end. public struct NetworkPingMessage : NetworkMessage { - public double clientTime; + // local time is used to calculate round trip time, + // and to calculate the predicted time offset. + public double localTime; + + // predicted time is sent to compare the final error, for debugging only + public double predictedTimeAdjusted; - public NetworkPingMessage(double value) + public NetworkPingMessage(double localTime, double predictedTimeAdjusted) { - clientTime = value; + this.localTime = localTime; + this.predictedTimeAdjusted = predictedTimeAdjusted; } } - // The server responds with this message - // The client can use this to calculate RTT and sync time + // the other end responds with this message. + // we can use this to calculate rtt. public struct NetworkPongMessage : NetworkMessage { - public double clientTime; - public double serverTime; + // local time is used to calculate round trip time. + public double localTime; + + // predicted error is used to adjust the predicted timeline. + public double predictionErrorUnadjusted; + public double predictionErrorAdjusted; // for debug purposes + + public NetworkPongMessage(double localTime, double predictionErrorUnadjusted, double predictionErrorAdjusted) + { + this.localTime = localTime; + this.predictionErrorUnadjusted = predictionErrorUnadjusted; + this.predictionErrorAdjusted = predictionErrorAdjusted; + } } } diff --git a/Assets/Mirror/Core/Mirror.asmdef b/Assets/Mirror/Core/Mirror.asmdef index 59e32aa..2fa8d95 100644 --- a/Assets/Mirror/Core/Mirror.asmdef +++ b/Assets/Mirror/Core/Mirror.asmdef @@ -2,9 +2,7 @@ "name": "Mirror", "rootNamespace": "", "references": [ - "GUID:325984b52e4128546bc7558552f8b1d2", - "GUID:725ee7191c021de4dbf9269590ded755", - "GUID:6806a62c384838046a3c66c44f06d75f" + "GUID:325984b52e4128546bc7558552f8b1d2" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Mirror/Core/NetworkBehaviour.cs b/Assets/Mirror/Core/NetworkBehaviour.cs index 630d3af..52ca522 100644 --- a/Assets/Mirror/Core/NetworkBehaviour.cs +++ b/Assets/Mirror/Core/NetworkBehaviour.cs @@ -19,8 +19,8 @@ public enum SyncMode { Observers, Owner } public enum SyncDirection { ServerToClient, ClientToServer } /// Base class for networked components. + // [RequireComponent(typeof(NetworkIdentity))] disabled to allow child NetworkBehaviours [AddComponentMenu("")] - [RequireComponent(typeof(NetworkIdentity))] [HelpURL("https://mirror-networking.gitbook.io/docs/guides/networkbehaviour")] public abstract class NetworkBehaviour : MonoBehaviour { @@ -36,9 +36,14 @@ public abstract class NetworkBehaviour : MonoBehaviour /// sync interval for OnSerialize (in seconds) // hidden because NetworkBehaviourInspector shows it only if has OnSerialize. // [0,2] should be enough. anything >2s is too laggy anyway. + // + // NetworkServer & NetworkClient broadcast() are behind a sendInterval timer now. + // it makes sense to keep every component's syncInterval setting at '0' by default. + // otherwise, the overlapping timers could introduce unexpected latency. + // careful: default of '0.1' may [Tooltip("Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)")] [Range(0, 2)] - [HideInInspector] public float syncInterval = 0.1f; + [HideInInspector] public float syncInterval = 0; internal double lastSyncTime; /// True if this object is on the server and has been spawned. @@ -62,13 +67,11 @@ public abstract class NetworkBehaviour : MonoBehaviour // for example: main player & pets are owned. monsters & npcs aren't. public bool isOwned => netIdentity.isOwned; - // Deprecated 2022-10-13 - [Obsolete(".hasAuthority was renamed to .isOwned. This is easier to understand and prepares for SyncDirection, where there is a difference betwen isOwned and authority.")] - public bool hasAuthority => isOwned; - /// authority is true if we are allowed to modify this component's state. On server, it's true if SyncDirection is ServerToClient. On client, it's true if SyncDirection is ClientToServer and(!) if this object is owned by the client. - // on the client: if owned and if clientAuthority sync direction - // on the server: if serverAuthority sync direction + // on the client: if Client->Server SyncDirection and owned + // on the server: if Server->Client SyncDirection + // on the host: if Server->Client SyncDirection (= server owns it), or if Client->Server and owned (=host client owns it) + // in host mode: always true because either server or client always has authority, and host is both. // // for example, NetworkTransform: // client may modify position if ClientAuthority mode and owned @@ -79,10 +82,20 @@ public abstract class NetworkBehaviour : MonoBehaviour // // also note that this is a per-NetworkBehaviour flag. // another component may not be client authoritative, etc. - public bool authority => - isClient - ? syncDirection == SyncDirection.ClientToServer && isOwned - : syncDirection == SyncDirection.ServerToClient; + public bool authority + { + get + { + // host mode needs to be checked explicitly + if (isClient && isServer) return syncDirection == SyncDirection.ServerToClient || isOwned; + + // client-only + if (isClient) return syncDirection == SyncDirection.ClientToServer && isOwned; + + // server-only + return syncDirection == SyncDirection.ServerToClient; + } + } /// The unique network Id of this object (unique at runtime). public uint netId => netIdentity.netId; @@ -122,8 +135,9 @@ public abstract class NetworkBehaviour : MonoBehaviour // -> still supports dynamically sized types // // 64 bit mask, tracking up to 64 SyncVars. - protected ulong syncVarDirtyBits { get; private set; } - // 64 bit mask, tracking up to 64 sync collections (internal for tests). + // protected since NB child classes read this field in the weaver generated SerializeSyncVars method + protected ulong syncVarDirtyBits; + // 64 bit mask, tracking up to 64 sync collections. // internal for tests, field for faster access (instead of property) // TODO 64 SyncLists are too much. consider smaller mask later. internal ulong syncObjectDirtyBits; @@ -185,7 +199,7 @@ public bool IsDirty() => // only check time if bits were dirty. this is more expensive. NetworkTime.localTime - lastSyncTime >= syncInterval; - /// Clears all the dirty bits that were set by SetDirtyBits() + /// Clears all the dirty bits that were set by SetSyncVarDirtyBit() (formally SetDirtyBits) // automatically invoked when an update is sent for this object, but can // be called manually as well. public void ClearAllDirtyBits() @@ -288,15 +302,43 @@ protected void InitSyncObject(SyncObject syncObject) }; } + protected virtual void OnValidate() + { + // we now allow child NetworkBehaviours. + // we can not [RequireComponent(typeof(NetworkIdentity))] anymore. + // instead, we need to ensure a NetworkIdentity is somewhere in the + // parents. + // only run this in Editor. don't add more runtime overhead. + + // GetComponentInParent(includeInactive) is needed because Prefabs are not + // considered active, so this check requires to scan inactive. +#if UNITY_EDITOR +#if UNITY_2021_3_OR_NEWER // 2021 has GetComponentInParent(bool includeInactive = false) + if (GetComponent() == null && + GetComponentInParent(true) == null) + { + Debug.LogError($"{GetType()} on {name} requires a NetworkIdentity. Please add a NetworkIdentity component to {name} or it's parents.", this); + } +#elif UNITY_2020_3_OR_NEWER // 2020 only has GetComponentsInParent(bool includeInactive = false), we can use this too + NetworkIdentity[] parentsIds = GetComponentsInParent(true); + int parentIdsCount = parentsIds != null ? parentsIds.Length : 0; + if (GetComponent() == null && parentIdsCount == 0) + { + Debug.LogError($"{GetType()} on {name} requires a NetworkIdentity. Please add a NetworkIdentity component to {name} or it's parents.", this); + } +#endif +#endif + } + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions - protected void SendCommandInternal(string functionFullName, NetworkWriter writer, int channelId, bool requiresAuthority = true) + protected void SendCommandInternal(string functionFullName, int functionHashCode, NetworkWriter writer, int channelId, bool requiresAuthority = true) { // this was in Weaver before // NOTE: we could remove this later to allow calling Cmds on Server // to avoid Wrapper functions. a lot of people requested this. if (!NetworkClient.active) { - Debug.LogError($"Command Function {functionFullName} called on {name} without an active client.", gameObject); + Debug.LogError($"Command {functionFullName} called on {name} without an active client.", gameObject); return; } @@ -308,14 +350,15 @@ protected void SendCommandInternal(string functionFullName, NetworkWriter writer // or client may have been set NotReady intentionally, so // only warn if on the reliable channel. if (channelId == Channels.Reliable) - Debug.LogWarning($"Command Function {functionFullName} called on {name} while NetworkClient is not ready.\nThis may be ignored if client intentionally set NotReady.", gameObject); + Debug.LogWarning($"Command {functionFullName} called on {name} while NetworkClient is not ready.\nThis may be ignored if client intentionally set NotReady.", gameObject); return; } - // local players can always send commands, regardless of authority, other objects must have authority. + // local players can always send commands, regardless of authority, + // other objects must have authority. if (!(!requiresAuthority || isLocalPlayer || isOwned)) { - Debug.LogWarning($"Command Function {functionFullName} called on {name} without authority.", gameObject); + Debug.LogWarning($"Command {functionFullName} called on {name} without authority.", gameObject); return; } @@ -326,7 +369,7 @@ protected void SendCommandInternal(string functionFullName, NetworkWriter writer // => see also: https://github.com/vis2k/Mirror/issues/2629 if (NetworkClient.connection == null) { - Debug.LogError($"Command Function {functionFullName} called on {name} with no client running.", gameObject); + Debug.LogError($"Command {functionFullName} called on {name} with no client running.", gameObject); return; } @@ -336,7 +379,7 @@ protected void SendCommandInternal(string functionFullName, NetworkWriter writer netId = netId, componentIndex = ComponentIndex, // type+func so Inventory.RpcUse != Equipment.RpcUse - functionHash = (ushort)functionFullName.GetStableHashCode(), + functionHash = (ushort)functionHashCode, // segment to avoid reader allocations payload = writer.ToArraySegment() }; @@ -352,12 +395,12 @@ protected void SendCommandInternal(string functionFullName, NetworkWriter writer } // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions - protected void SendRPCInternal(string functionFullName, NetworkWriter writer, int channelId, bool includeOwner) + protected void SendRPCInternal(string functionFullName, int functionHashCode, NetworkWriter writer, int channelId, bool includeOwner) { // this was in Weaver before if (!NetworkServer.active) { - Debug.LogError($"RPC Function {functionFullName} called on Client.", gameObject); + Debug.LogError($"RPC Function {functionFullName} called without an active server.", gameObject); return; } @@ -374,7 +417,7 @@ protected void SendRPCInternal(string functionFullName, NetworkWriter writer, in netId = netId, componentIndex = ComponentIndex, // type+func so Inventory.RpcUse != Equipment.RpcUse - functionHash = (ushort)functionFullName.GetStableHashCode(), + functionHash = (ushort)functionHashCode, // segment to avoid reader allocations payload = writer.ToArraySegment() }; @@ -384,28 +427,29 @@ protected void SendRPCInternal(string functionFullName, NetworkWriter writer, in // NetworkServer.SendToReadyObservers(netIdentity, message, includeOwner, channelId); // safety check used to be in SendToReadyObservers. keep it for now. - if (netIdentity.observers != null && netIdentity.observers.Count > 0) + if (netIdentity.observers == null || netIdentity.observers.Count == 0) + return; + + // serialize the message only once + using (NetworkWriterPooled serialized = NetworkWriterPool.Get()) { - // serialize the message only once - using (NetworkWriterPooled serialized = NetworkWriterPool.Get()) - { - serialized.Write(message); + serialized.Write(message); - // add to every observer's connection's rpc buffer - foreach (NetworkConnectionToClient conn in netIdentity.observers.Values) + // send to every observer. + // batching buffers this automatically. + foreach (NetworkConnectionToClient conn in netIdentity.observers.Values) + { + bool isOwner = conn == netIdentity.connectionToClient; + if ((!isOwner || includeOwner) && conn.isReady) { - bool isOwner = conn == netIdentity.connectionToClient; - if ((!isOwner || includeOwner) && conn.isReady) - { - conn.BufferRpc(message, channelId); - } + conn.Send(message, channelId); } } } } // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions - protected void SendTargetRPCInternal(NetworkConnection conn, string functionFullName, NetworkWriter writer, int channelId) + protected void SendTargetRPCInternal(NetworkConnection conn, string functionFullName, int functionHashCode, NetworkWriter writer, int channelId) { if (!NetworkServer.active) { @@ -445,15 +489,14 @@ protected void SendTargetRPCInternal(NetworkConnection conn, string functionFull netId = netId, componentIndex = ComponentIndex, // type+func so Inventory.RpcUse != Equipment.RpcUse - functionHash = (ushort)functionFullName.GetStableHashCode(), + functionHash = (ushort)functionHashCode, // segment to avoid reader allocations payload = writer.ToArraySegment() }; - // serialize it to the connection's rpc buffer. - // send them all at once, instead of sending one message per rpc. - // conn.Send(message, channelId); - connToClient.BufferRpc(message, channelId); + // send it to the connection. + // batching buffers this automatically. + conn.Send(message, channelId); } // move the [SyncVar] generated property's .set into C# to avoid much IL @@ -643,7 +686,9 @@ protected void SetSyncVarGameObject(GameObject newGameObject, ref GameObject gam protected GameObject GetSyncVarGameObject(uint netId, ref GameObject gameObjectField) { // server always uses the field - if (isServer) + // if neither, fallback to original field + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3447 + if (isServer || !isClient) { return gameObjectField; } @@ -719,7 +764,6 @@ public static bool SyncVarNetworkIdentityEqual(NetworkIdentity newIdentity, uint // GeneratedSyncVarDeserialize(reader, ref health, null, reader.ReadInt()); // } // } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GeneratedSyncVarDeserialize(ref T field, Action OnChanged, T value) { T previous = field; @@ -777,7 +821,6 @@ public void GeneratedSyncVarDeserialize(ref T field, Action OnChanged, // GeneratedSyncVarDeserialize_GameObject(reader, ref target, OnChangedNB, ref ___targetNetId); // } // } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GeneratedSyncVarDeserialize_GameObject(ref GameObject field, Action OnChanged, NetworkReader reader, ref uint netIdField) { uint previousNetId = netIdField; @@ -840,7 +883,6 @@ public void GeneratedSyncVarDeserialize_GameObject(ref GameObject field, Action< // GeneratedSyncVarDeserialize_NetworkIdentity(reader, ref target, OnChangedNI, ref ___targetNetId); // } // } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GeneratedSyncVarDeserialize_NetworkIdentity(ref NetworkIdentity field, Action OnChanged, NetworkReader reader, ref uint netIdField) { uint previousNetId = netIdField; @@ -904,7 +946,6 @@ public void GeneratedSyncVarDeserialize_NetworkIdentity(ref NetworkIdentity fiel // GeneratedSyncVarDeserialize_NetworkBehaviour(reader, ref target, OnChangedNB, ref ___targetNetId); // } // } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GeneratedSyncVarDeserialize_NetworkBehaviour(ref T field, Action OnChanged, NetworkReader reader, ref NetworkBehaviourSyncVar netIdField) where T : NetworkBehaviour { @@ -951,7 +992,9 @@ protected void SetSyncVarNetworkIdentity(NetworkIdentity newIdentity, ref Networ protected NetworkIdentity GetSyncVarNetworkIdentity(uint netId, ref NetworkIdentity identityField) { // server always uses the field - if (isServer) + // if neither, fallback to original field + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3447 + if (isServer || !isClient) { return identityField; } @@ -1009,12 +1052,14 @@ protected void SetSyncVarNetworkBehaviour(T newBehaviour, ref T behaviourFiel // Debug.Log($"SetSyncVarNetworkBehaviour NetworkIdentity {GetType().Name} bit [{dirtyBit}] netIdField:{oldField}->{syncField}"); } - // helper function for [SyncVar] NetworkIdentities. + // helper function for [SyncVar] NetworkBehaviours. // -> ref GameObject as second argument makes OnDeserialize processing easier protected T GetSyncVarNetworkBehaviour(NetworkBehaviourSyncVar syncNetBehaviour, ref T behaviourField) where T : NetworkBehaviour { // server always uses the field - if (isServer) + // if neither, fallback to original field + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3447 + if (isServer || !isClient) { return behaviourField; } @@ -1025,6 +1070,15 @@ protected T GetSyncVarNetworkBehaviour(NetworkBehaviourSyncVar syncNetBehavio { return null; } + + // ensure componentIndex is in range. + // show explicit errors if something went wrong, instead of IndexOutOfRangeException. + // removing components at runtime isn't allowed, yet this happened in a project so we need to check for it. + if (syncNetBehaviour.componentIndex >= identity.NetworkBehaviours.Length) + { + Debug.LogError($"[SyncVar] {typeof(T)} on {name}'s {GetType()}: can't access {identity.name} NetworkBehaviour[{syncNetBehaviour.componentIndex}] because it only has {identity.NetworkBehaviours.Length} components.\nWas a NetworkBeahviour accidentally destroyed at runtime?"); + return null; + } behaviourField = identity.NetworkBehaviours[syncNetBehaviour.componentIndex] as T; return behaviourField; @@ -1066,7 +1120,6 @@ public virtual void OnDeserialize(NetworkReader reader, bool initialState) DeserializeSyncVars(reader, initialState); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] void SerializeSyncObjects(NetworkWriter writer, bool initialState) { // if initialState: write all SyncVars. @@ -1077,7 +1130,6 @@ void SerializeSyncObjects(NetworkWriter writer, bool initialState) SerializeObjectsDelta(writer); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] void DeserializeSyncObjects(NetworkReader reader, bool initialState) { if (initialState) @@ -1318,5 +1370,10 @@ public virtual void OnStartAuthority() {} /// Stop event, only called for objects the client has authority over. public virtual void OnStopAuthority() {} + + // Weaver injects this into inheriting classes to return true. + // allows runtime & tests to check if a type was weaved. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual bool Weaved() => false; } } diff --git a/Assets/Mirror/Core/NetworkClient.cs b/Assets/Mirror/Core/NetworkClient.cs index c94eea1..c8f0120 100644 --- a/Assets/Mirror/Core/NetworkClient.cs +++ b/Assets/Mirror/Core/NetworkClient.cs @@ -33,6 +33,15 @@ public static partial class NetworkClient public static float sendInterval => sendRate < int.MaxValue ? 1f / sendRate : 0; // for 30 Hz, that's 33ms static double lastSendTime; + // For security, it is recommended to disconnect a player if a networked + // action triggers an exception\nThis could prevent components being + // accessed in an undefined state, which may be an attack vector for + // exploits. + // + // However, some games may want to allow exceptions in order to not + // interrupt the player's experience. + public static bool exceptionsDisconnect = true; // security by default + // message handlers by messageId internal static readonly Dictionary handlers = new Dictionary(); @@ -59,10 +68,6 @@ public static partial class NetworkClient // NetworkClient state internal static ConnectState connectState = ConnectState.None; - /// IP address of the connection to server. - // empty if the client has not connected yet. - public static string serverIp => connection.address; - /// active is true while a client is connecting/connected either as standalone or as host client. // (= while the network is active) public static bool active => connectState == ConnectState.Connecting || @@ -78,10 +83,6 @@ public static partial class NetworkClient /// Check if client is connected (after connecting). public static bool isConnected => connectState == ConnectState.Connected; - // Deprecated 2022-12-12 - [Obsolete("NetworkClient.isHostClient was renamed to .activeHost to be more obvious")] - public static bool isHostClient => activeHost; - // OnConnected / OnDisconnected used to be NetworkMessages that were // invoked. this introduced a bug where external clients could send // Connected/Disconnected messages over the network causing undefined @@ -90,6 +91,7 @@ public static partial class NetworkClient public static Action OnConnectedEvent; public static Action OnDisconnectedEvent; public static Action OnErrorEvent; + public static Action OnTransportExceptionEvent; /// Registered spawnable prefabs by assetId. public static readonly Dictionary prefabs = @@ -111,15 +113,30 @@ public static partial class NetworkClient internal static readonly Dictionary spawnableObjects = new Dictionary(); - static Unbatcher unbatcher = new Unbatcher(); + internal static Unbatcher unbatcher = new Unbatcher(); // interest management component (optional) // only needed for SetHostVisibility - public static InterestManagement aoi; + public static InterestManagementBase aoi; // scene loading public static bool isLoadingScene; + // connection quality + // this is set by a virtual function in NetworkManager, + // which allows users to overwrite it with their own estimations. + public static ConnectionQuality connectionQuality = ConnectionQuality.ESTIMATING; + public static ConnectionQuality lastConnectionQuality = ConnectionQuality.ESTIMATING; + public static ConnectionQualityMethod connectionQualityMethod = ConnectionQualityMethod.Simple; + public static float connectionQualityInterval = 3; + static double lastConnectionQualityUpdate; + + /// + /// Invoked when connection quality changes. + /// First argument is the old quality, second argument is the new quality. + /// + public static event Action onConnectionQualityChanged; + // initialization ////////////////////////////////////////////////////// static void AddTransportHandlers() { @@ -134,6 +151,7 @@ static void AddTransportHandlers() Transport.active.OnClientDataReceived += OnTransportData; Transport.active.OnClientDisconnected += OnTransportDisconnected; Transport.active.OnClientError += OnTransportError; + Transport.active.OnClientTransportException += OnTransportException; } static void RemoveTransportHandlers() @@ -143,15 +161,31 @@ static void RemoveTransportHandlers() Transport.active.OnClientDataReceived -= OnTransportData; Transport.active.OnClientDisconnected -= OnTransportDisconnected; Transport.active.OnClientError -= OnTransportError; + Transport.active.OnClientTransportException -= OnTransportException; } // connect ///////////////////////////////////////////////////////////// // initialize is called before every connect static void Initialize(bool hostMode) { + // safety: ensure Weaving succeded. + // if it silently failed, we would get lots of 'writer not found' + // and other random errors at runtime instead. this is cleaner. + if (!WeaverFuse.Weaved()) + { + // if it failed, throw an exception to early exit all Connect calls. + throw new Exception("NetworkClient won't start because Weaving failed or didn't run."); + } + // Debug.Log($"Client Connect: {address}"); Debug.Assert(Transport.active != null, "There was no active transport when calling NetworkClient.Connect, If you are calling Connect manually then make sure to set 'Transport.active' first"); + // reset unbatcher in case any batches from last session remain. + // need to do this in Initialize() so it runs for the host as well. + // fixes host mode scene transition receiving data from previous scene. + // credits: BigBoxVR + unbatcher = new Unbatcher(); + // reset time interpolation on every new connect. // ensures last sessions' state is cleared before starting again. InitTimeInterpolation(); @@ -191,10 +225,6 @@ public static void ConnectHost() HostMode.SetupConnections(); } - // Deprecated 2022-12-12 - [Obsolete("NetworkClient.ConnectLocalServer was moved to HostMode.InvokeOnConnected")] - public static void ConnectLocalServer() => HostMode.InvokeOnConnected(); - // disconnect ////////////////////////////////////////////////////////// /// Disconnect from server. public static void Disconnect() @@ -231,13 +261,11 @@ static void OnTransportConnected() // reset network time stats NetworkTime.ResetStatics(); - // reset unbatcher in case any batches from last session remain. - unbatcher = new Unbatcher(); - // the handler may want to send messages to the client // thus we should set the connected state before calling the handler connectState = ConnectState.Connected; - NetworkTime.UpdateClient(); + // ping right away after connecting so client gets new time asap + NetworkTime.SendPing(); OnConnectedEvent?.Invoke(); } else Debug.LogError("Skipped Connect message handling because connection is null."); @@ -294,8 +322,14 @@ internal static void OnTransportData(ArraySegment data, int channelId) // always process all messages in the batch. if (!unbatcher.AddBatch(data)) { - Debug.LogWarning($"NetworkClient: failed to add batch, disconnecting."); - connection.Disconnect(); + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkClient: failed to add batch, disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkClient: failed to add batch."); + return; } @@ -310,38 +344,51 @@ internal static void OnTransportData(ArraySegment data, int channelId) // the next time. // => consider moving processing to NetworkEarlyUpdate. while (!isLoadingScene && - unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimestamp)) + unbatcher.GetNextMessage(out ArraySegment message, out double remoteTimestamp)) { - // enough to read at least header size? - if (reader.Remaining >= NetworkMessages.IdSize) + using (NetworkReaderPooled reader = NetworkReaderPool.Get(message)) { - // make remoteTimeStamp available to the user - connection.remoteTimeStamp = remoteTimestamp; + // enough to read at least header size? + if (reader.Remaining >= NetworkMessages.IdSize) + { + // make remoteTimeStamp available to the user + connection.remoteTimeStamp = remoteTimestamp; + + // handle message + if (!UnpackAndInvoke(reader, channelId)) + { + // warn, disconnect and return if failed + // -> warning because attackers might send random data + // -> messages in a batch aren't length prefixed. + // failing to read one would cause undefined + // behaviour for every message afterwards. + // so we need to disconnect. + // -> return to avoid the below unbatches.count error. + // we already disconnected and handled it. + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkClient: failed to unpack and invoke message. Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkClient: failed to unpack and invoke message."); - // handle message - if (!UnpackAndInvoke(reader, channelId)) + return; + } + } + // otherwise disconnect + else { - // warn, disconnect and return if failed - // -> warning because attackers might send random data - // -> messages in a batch aren't length prefixed. - // failing to read one would cause undefined - // behaviour for every message afterwards. - // so we need to disconnect. - // -> return to avoid the below unbatches.count error. - // we already disconnected and handled it. - Debug.LogWarning($"NetworkClient: failed to unpack and invoke message. Disconnecting."); - connection.Disconnect(); + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkClient: received Message was too short (messages should start with message id). Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning("NetworkClient: received Message was too short (messages should start with message id)"); return; } } - // otherwise disconnect - else - { - // WARNING, not error. can happen if attacker sends random data. - Debug.LogWarning($"NetworkClient: received Message was too short (messages should start with message id)"); - connection.Disconnect(); - return; - } } // if we weren't interrupted by a scene change, @@ -399,6 +446,7 @@ internal static void OnTransportDisconnected() // now that everything was handled, clear the connection. // previously this was done in Disconnect() already, but we still // need it for the above OnDisconnectedEvent. + connection?.Cleanup(); connection = null; // transport handlers are only added when connecting. @@ -415,6 +463,14 @@ static void OnTransportError(TransportError error, string reason) OnErrorEvent?.Invoke(error, reason); } + static void OnTransportException(Exception exception) + { + // transport errors will happen. logging a warning is enough. + // make sure the user does not panic. + Debug.LogWarning($"Client Transport Exception: {exception}. This is fine."); + OnTransportExceptionEvent?.Invoke(exception); + } + // send //////////////////////////////////////////////////////////////// /// Send a NetworkMessage to the server over the given channel. public static void Send(T message, int channelId = Channels.Reliable) @@ -455,6 +511,7 @@ internal static void RegisterMessageHandlers(bool hostMode) RegisterHandler(OnObjectDestroy); RegisterHandler(OnObjectHide); RegisterHandler(NetworkTime.OnClientPong, false); + RegisterHandler(NetworkTime.OnClientPing, false); RegisterHandler(OnSpawn); RegisterHandler(OnObjectSpawnStarted); RegisterHandler(OnObjectSpawnFinished); @@ -464,34 +521,65 @@ internal static void RegisterMessageHandlers(bool hostMode) // These handlers are the same for host and remote clients RegisterHandler(OnTimeSnapshotMessage); RegisterHandler(OnChangeOwner); - RegisterHandler(OnRPCBufferMessage); + RegisterHandler(OnRPCMessage); } /// Register a handler for a message type T. Most should require authentication. public static void RegisterHandler(Action handler, bool requireAuthentication = true) where T : struct, NetworkMessage { - ushort msgType = NetworkMessages.GetId(); + ushort msgType = NetworkMessageId.Id; if (handlers.ContainsKey(msgType)) { Debug.LogWarning($"NetworkClient.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); } + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + // we use the same WrapHandler function for server and client. // so let's wrap it to ignore the NetworkConnection parameter. // it's not needed on client. it's always NetworkClient.connection. void HandlerWrapped(NetworkConnection _, T value) => handler(value); - handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); } - /// Replace a handler for a particular message type. Should require authentication by default. - // RegisterHandler throws a warning (as it should) if a handler is assigned twice - // Use of ReplaceHandler makes it clear the user intended to replace the handler + /// Register a handler for a message type T. Most should require authentication. + // This version passes channelId to the handler. + public static void RegisterHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + if (handlers.ContainsKey(msgType)) + { + Debug.LogWarning($"NetworkClient.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); + } + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + void HandlerWrapped(NetworkConnection _, T value, int channelId) => handler(value, channelId); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); + } + + // Deprecated 2024-01-21 + [Obsolete("Use ReplaceHandler without the NetworkConnection parameter instead. This version is obsolete and will be removed soon.")] public static void ReplaceHandler(Action handler, bool requireAuthentication = true) where T : struct, NetworkMessage { - ushort msgType = NetworkMessages.GetId(); - handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication); + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + void HandlerWrapped(NetworkConnection _, T value) => handler(_, value); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); } /// Replace a handler for a particular message type. Should require authentication by default. @@ -500,7 +588,34 @@ public static void ReplaceHandler(Action handler, bool public static void ReplaceHandler(Action handler, bool requireAuthentication = true) where T : struct, NetworkMessage { - ReplaceHandler((NetworkConnection _, T value) => { handler(value); }, requireAuthentication); + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + void HandlerWrapped(NetworkConnection _, T value) => handler(value); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); + } + + /// Replace a handler for a particular message type. Should require authentication by default. This version passes channelId to the handler. + // RegisterHandler throws a warning (as it should) if a handler is assigned twice + // Use of ReplaceHandler makes it clear the user intended to replace the handler + public static void ReplaceHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + void HandlerWrapped(NetworkConnection _, T value, int channelId) => handler(value, channelId); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); } /// Unregister a message handler of type T. @@ -508,7 +623,7 @@ public static bool UnregisterHandler() where T : struct, NetworkMessage { // use int to minimize collisions - ushort msgType = NetworkMessages.GetId(); + ushort msgType = NetworkMessageId.Id; return handlers.Remove(msgType); } @@ -538,6 +653,9 @@ static void RegisterPrefabIdentity(NetworkIdentity prefab) return; } + // disallow child NetworkIdentities. + // TODO likely not necessary anymore due to the new check in + // NetworkIdentity.OnValidate. NetworkIdentity[] identities = prefab.GetComponentsInChildren(); if (identities.Length > 1) { @@ -1171,11 +1289,12 @@ public static void PrepareToSpawnSceneObjects() foreach (NetworkIdentity identity in allIdentities) { // add all unspawned NetworkIdentities to spawnable objects - // need to ensure it's not active yet because + // need to check netId to make sure object is not spawned + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3541 // PrepareToSpawnSceneObjects may be called multiple times in case // the ObjectSpawnStarted message is received multiple times. if (Utils.IsSceneObject(identity) && - !identity.gameObject.activeSelf) + identity.netId == 0) { if (spawnableObjects.TryGetValue(identity.sceneId, out NetworkIdentity existingIdentity)) { @@ -1271,7 +1390,7 @@ static void OnEntityStateMessage(EntityStateMessage message) using (NetworkReaderPooled reader = NetworkReaderPool.Get(message.payload)) identity.DeserializeClient(reader, false); } - else Debug.LogWarning($"Did not find target for sync message for {message.netId} . Note: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message."); + else Debug.LogWarning($"Did not find target for sync message for {message.netId}. Were all prefabs added to the NetworkManager's spawnable list?\nNote: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message."); } static void OnRPCMessage(RpcMessage message) @@ -1285,21 +1404,6 @@ static void OnRPCMessage(RpcMessage message) // Rpcs often can't be applied if interest management unspawned them } - static void OnRPCBufferMessage(RpcBufferMessage message) - { - // Debug.Log($"NetworkClient.OnRPCBufferMessage of {message.payload.Count} bytes"); - // parse all rpc messages from the buffer - using (NetworkReaderPooled reader = NetworkReaderPool.Get(message.payload)) - { - while (reader.Remaining > 0) - { - // read message without header - RpcMessage rpcMessage = reader.Read(); - OnRPCMessage(rpcMessage); - } - } - } - static void OnObjectHide(ObjectHideMessage message) => DestroyObject(message.netId); internal static void OnObjectDestroy(ObjectDestroyMessage message) => DestroyObject(message.netId); @@ -1449,9 +1553,6 @@ static void Broadcast() payload = writer.ToArraySegment() }; Send(message); - - // reset dirty bits so it's not resent next time. - identity.ClearDirtyComponentsDirtyBits(); } } } @@ -1480,12 +1581,6 @@ internal static void NetworkEarlyUpdate() internal static void NetworkLateUpdate() { // broadcast ClientToServer components while active - // note that Broadcast() runs every update. - // on clients with 120 Hz, this will run 120 times per second. - // however, Broadcast only checks .owned, which usually aren't many. - // - // we could use a .sendInterval, but it would also put a minimum - // limit to every component's sendInterval automatically. if (active) { // broadcast every sendInterval. @@ -1508,6 +1603,38 @@ internal static void NetworkLateUpdate() { Broadcast(); } + + UpdateConnectionQuality(); + } + + // Connection Quality ////////////////////////////////////////////////// + // uses 'pragmatic' version based on snapshot interpolation by default. + void UpdateConnectionQuality() + { + // only recalculate every few seconds + // we don't want to fire Good->Bad->Good->Bad dozens of times per second. + if (connectionQualityInterval > 0 && NetworkTime.time > lastConnectionQualityUpdate + connectionQualityInterval) + { + lastConnectionQualityUpdate = NetworkTime.time; + + switch (connectionQualityMethod) + { + case ConnectionQualityMethod.Simple: + connectionQuality = ConnectionQualityHeuristics.Simple(NetworkTime.rtt, NetworkTime.rttVariance); + break; + case ConnectionQualityMethod.Pragmatic: + connectionQuality = ConnectionQualityHeuristics.Pragmatic(initialBufferTime, bufferTime); + break; + } + + if (lastConnectionQuality != connectionQuality) + { + // Invoke the event before assigning the new value so + // the event handler can compare old and new values. + onConnectionQualityChanged?.Invoke(lastConnectionQuality, connectionQuality); + lastConnectionQuality = connectionQuality; + } + } } // update connections to flush out messages _after_ broadcast @@ -1570,7 +1697,7 @@ public static void DestroyAllClientObjects() // unspawned objects should be reset for reuse later. if (wasUnspawned) { - identity.Reset(); + identity.ResetState(); } // without unspawn handler, we need to disable/destroy. else @@ -1579,7 +1706,7 @@ public static void DestroyAllClientObjects() // they always stay in the scene, we don't destroy them. if (identity.sceneId != 0) { - identity.Reset(); + identity.ResetState(); identity.gameObject.SetActive(false); } // spawned objects are destroyed @@ -1615,7 +1742,7 @@ static void DestroyObject(uint netId) if (InvokeUnSpawnHandler(identity.assetId, identity.gameObject)) { // reset object after user's handler - identity.Reset(); + identity.ResetState(); } // otherwise fall back to default Destroy else if (identity.sceneId == 0) @@ -1629,7 +1756,7 @@ static void DestroyObject(uint netId) identity.gameObject.SetActive(false); spawnableObjects[identity.sceneId] = identity; // reset for scene objects - identity.Reset(); + identity.ResetState(); } // remove from dictionary no matter how it is unspawned @@ -1692,6 +1819,7 @@ public static void Shutdown() OnConnectedEvent = null; OnDisconnectedEvent = null; OnErrorEvent = null; + OnTransportExceptionEvent = null; } // GUI ///////////////////////////////////////////////////////////////// @@ -1702,7 +1830,7 @@ public static void OnGUI() // only if in world if (!ready) return; - GUILayout.BeginArea(new Rect(10, 5, 500, 50)); + GUILayout.BeginArea(new Rect(10, 5, 1020, 50)); GUILayout.BeginHorizontal("Box"); GUILayout.Label("Snapshot Interp.:"); @@ -1712,8 +1840,13 @@ public static void OnGUI() else GUI.color = Color.white; GUILayout.Box($"timeline: {localTimeline:F2}"); GUILayout.Box($"buffer: {snapshots.Count}"); + GUILayout.Box($"DriftEMA: {NetworkClient.driftEma.Value:F2}"); + GUILayout.Box($"DelTimeEMA: {NetworkClient.deliveryTimeEma.Value:F2}"); GUILayout.Box($"timescale: {localTimescale:F2}"); - GUILayout.Box($"BTM: {bufferTimeMultiplier:F2}"); + GUILayout.Box($"BTM: {NetworkClient.bufferTimeMultiplier:F2}"); // current dynamically adjusted multiplier + GUILayout.Box($"RTT: {NetworkTime.rtt * 1000:F0}ms"); + GUILayout.Box($"PredErrUNADJ: {NetworkTime.predictionErrorUnadjusted * 1000:F0}ms"); + GUILayout.Box($"PredErrADJ: {NetworkTime.predictionErrorAdjusted * 1000:F0}ms"); GUILayout.EndHorizontal(); GUILayout.EndArea(); diff --git a/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs b/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs index 060dae5..8d28859 100644 --- a/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs +++ b/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using UnityEngine; @@ -5,16 +6,21 @@ namespace Mirror { public static partial class NetworkClient { + // snapshot interpolation settings ///////////////////////////////////// // TODO expose the settings to the user later. // via NetMan or NetworkClientConfig or NetworkClient as component etc. + public static SnapshotInterpolationSettings snapshotSettings = new SnapshotInterpolationSettings(); - // decrease bufferTime at runtime to see the catchup effect. - // increase to see slowdown. - // 'double' so we can have very precise dynamic adjustment without rounding - [Header("Snapshot Interpolation: Buffering")] - [Tooltip("Local simulation is behind by sendInterval * multiplier seconds.\n\nThis guarantees that we always have enough snapshots in the buffer to mitigate lags & jitter.\n\nIncrease this if the simulation isn't smooth. By default, it should be around 2.")] - public static double bufferTimeMultiplier = 2; - public static double bufferTime => NetworkServer.sendInterval * bufferTimeMultiplier; + // snapshot interpolation runtime data ///////////////////////////////// + // buffer time is dynamically adjusted. + // store the current multiplier here, without touching the original in settings. + // this way we can easily reset to or compare with original where needed. + public static double bufferTimeMultiplier; + + // original buffer time based on the settings + // dynamically adjusted buffer time based on dynamically adjusted multiplier + public static double initialBufferTime => NetworkServer.sendInterval * snapshotSettings.bufferTimeMultiplier; + public static double bufferTime => NetworkServer.sendInterval * bufferTimeMultiplier; // public static SortedList snapshots = new SortedList(); @@ -33,25 +39,7 @@ public static partial class NetworkClient internal static double localTimescale = 1; // catchup ///////////////////////////////////////////////////////////// - // catchup thresholds in 'frames'. - // half a frame might be too aggressive. - [Header("Snapshot Interpolation: Catchup / Slowdown")] - [Tooltip("Slowdown begins when the local timeline is moving too fast towards remote time. Threshold is in frames worth of snapshots.\n\nThis needs to be negative.\n\nDon't modify unless you know what you are doing.")] - public static float catchupNegativeThreshold = -1; // careful, don't want to run out of snapshots - - [Tooltip("Catchup begins when the local timeline is moving too slow and getting too far away from remote time. Threshold is in frames worth of snapshots.\n\nThis needs to be positive.\n\nDon't modify unless you know what you are doing.")] - public static float catchupPositiveThreshold = 1; - - [Tooltip("Local timeline acceleration in % while catching up.")] - [Range(0, 1)] - public static double catchupSpeed = 0.01f; // 1% - - [Tooltip("Local timeline slowdown in % while slowing down.")] - [Range(0, 1)] - public static double slowdownSpeed = 0.01f; // 1% - [Tooltip("Catchup/Slowdown is adjusted over n-second exponential moving average.")] - public static int driftEmaDuration = 1; // shouldn't need to modify this, but expose it anyway // we use EMA to average the last second worth of snapshot time diffs. // manually averaging the last second worth of values with a for loop @@ -94,8 +82,7 @@ public static partial class NetworkClient static void InitTimeInterpolation() { // reset timeline, localTimescale & snapshots from last session (if any) - // Don't reset bufferTimeMultiplier here - whatever their network condition - // was when they disconnected, it won't have changed on immediate reconnect. + bufferTimeMultiplier = snapshotSettings.bufferTimeMultiplier; localTimeline = 0; localTimescale = 1; snapshots.Clear(); @@ -103,8 +90,8 @@ static void InitTimeInterpolation() // initialize EMA with 'emaDuration' seconds worth of history. // 1 second holds 'sendRate' worth of values. // multiplied by emaDuration gives n-seconds. - driftEma = new ExponentialMovingAverage(NetworkServer.sendRate * driftEmaDuration); - deliveryTimeEma = new ExponentialMovingAverage(NetworkServer.sendRate * deliveryTimeEmaDuration); + driftEma = new ExponentialMovingAverage(NetworkServer.sendRate * snapshotSettings.driftEmaDuration); + deliveryTimeEma = new ExponentialMovingAverage(NetworkServer.sendRate * snapshotSettings.deliveryTimeEmaDuration); } // server sends TimeSnapshotMessage every sendInterval. @@ -117,12 +104,8 @@ static void OnTimeSnapshotMessage(TimeSnapshotMessage _) // before calling OnDeserialize so components can use // NetworkTime.time and NetworkTime.timeStamp. -#if !UNITY_2020_3_OR_NEWER // Unity 2019 doesn't have Time.timeAsDouble yet OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, NetworkTime.localTime)); -#else - OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, Time.timeAsDouble)); -#endif } // see comments at the top of this file @@ -131,30 +114,31 @@ public static void OnTimeSnapshot(TimeSnapshot snap) // Debug.Log($"NetworkClient: OnTimeSnapshot @ {snap.remoteTime:F3}"); // (optional) dynamic adjustment - if (dynamicAdjustment) + if (snapshotSettings.dynamicAdjustment) { // set bufferTime on the fly. // shows in inspector for easier debugging :) bufferTimeMultiplier = SnapshotInterpolation.DynamicAdjustment( NetworkServer.sendInterval, deliveryTimeEma.StandardDeviation, - dynamicAdjustmentTolerance + snapshotSettings.dynamicAdjustmentTolerance ); } // insert into the buffer & initialize / adjust / catchup SnapshotInterpolation.InsertAndAdjust( snapshots, + snapshotSettings.bufferLimit, snap, ref localTimeline, ref localTimescale, NetworkServer.sendInterval, bufferTime, - catchupSpeed, - slowdownSpeed, + snapshotSettings.catchupSpeed, + snapshotSettings.slowdownSpeed, ref driftEma, - catchupNegativeThreshold, - catchupPositiveThreshold, + snapshotSettings.catchupNegativeThreshold, + snapshotSettings.catchupPositiveThreshold, ref deliveryTimeEma); // Debug.Log($"inserted TimeSnapshot remote={snap.remoteTime:F2} local={snap.localTime:F2} total={snapshots.Count}"); @@ -168,6 +152,9 @@ static void UpdateTimeInterpolation() if (snapshots.Count > 0) { // progress local timeline. + // NetworkTime uses unscaled time and ignores Time.timeScale. + // fixes Time.timeScale getting server & client time out of sync: + // https://github.com/MirrorNetworking/Mirror/issues/3409 SnapshotInterpolation.StepTime(Time.unscaledDeltaTime, ref localTimeline, localTimescale); // progress local interpolation. diff --git a/Assets/Mirror/Core/NetworkConnection.cs b/Assets/Mirror/Core/NetworkConnection.cs index 6b47abb..851beae 100644 --- a/Assets/Mirror/Core/NetworkConnection.cs +++ b/Assets/Mirror/Core/NetworkConnection.cs @@ -27,9 +27,6 @@ public abstract class NetworkConnection // state. public bool isReady; - /// IP address of the connection. Can be useful for game master IP bans etc. - public abstract string address { get; } - /// Last time a message was received for this connection. Includes system and user messages. public float lastMessageTime; @@ -94,41 +91,29 @@ protected Batcher GetBatchForChannelId(int channelId) return batch; } - // validate packet size before sending. show errors if too big/small. - // => it's best to check this here, we can't assume that all transports - // would check max size and show errors internally. best to do it - // in one place in Mirror. - // => it's important to log errors, so the user knows what went wrong. - protected static bool ValidatePacketSize(ArraySegment segment, int channelId) - { - int max = Transport.active.GetMaxPacketSize(channelId); - if (segment.Count > max) - { - Debug.LogError($"NetworkConnection.ValidatePacketSize: cannot send packet larger than {max} bytes, was {segment.Count} bytes"); - return false; - } - - if (segment.Count == 0) - { - // zero length packets getting into the packet queues are bad. - Debug.LogError("NetworkConnection.ValidatePacketSize: cannot send zero bytes"); - return false; - } - - // good size - return true; - } - // Send stage one: NetworkMessage /// Send a NetworkMessage to this connection over the given channel. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(T message, int channelId = Channels.Reliable) where T : struct, NetworkMessage { using (NetworkWriterPooled writer = NetworkWriterPool.Get()) { - // pack message and send allocation free + // pack message NetworkMessages.Pack(message, writer); + + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkConnection.Send: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + + // send allocation free NetworkDiagnostics.OnSend(message, channelId, writer.Position, 1); Send(writer.ToArraySegment(), channelId); } @@ -137,6 +122,7 @@ public void Send(T message, int channelId = Channels.Reliable) // Send stage two: serialized NetworkMessage as ArraySegment // internal because no one except Mirror should send bytes directly to // the client. they would be detected as a message. send messages instead. + // => make sure to validate message size before calling Send! [MethodImpl(MethodImplOptions.AggressiveInlining)] internal virtual void Send(ArraySegment segment, int channelId = Channels.Reliable) { @@ -162,7 +148,6 @@ internal virtual void Send(ArraySegment segment, int channelId = Channels. } // Send stage three: hand off to transport - [MethodImpl(MethodImplOptions.AggressiveInlining)] protected abstract void SendToTransport(ArraySegment segment, int channelId = Channels.Reliable); // flush batched messages at the end of every Update. @@ -179,21 +164,16 @@ internal virtual void Update() // make a batch with our local time (double precision) while (kvp.Value.GetBatch(writer)) { - // validate packet before handing the batch to the - // transport. this guarantees that we always stay - // within transport's max message size limit. - // => just in case transport forgets to check it - // => just in case mirror miscalulated it etc. + // message size is validated in Send, with test coverage. + // we can send directly without checking again. ArraySegment segment = writer.ToArraySegment(); - if (ValidatePacketSize(segment, kvp.Key)) - { - // send to transport - SendToTransport(segment, kvp.Key); - //UnityEngine.Debug.Log($"sending batch of {writer.Position} bytes for channel={kvp.Key} connId={connectionId}"); - - // reset writer for each new batch - writer.Position = 0; - } + + // send to transport + SendToTransport(segment, kvp.Key); + //UnityEngine.Debug.Log($"sending batch of {writer.Position} bytes for channel={kvp.Key} connId={connectionId}"); + + // reset writer for each new batch + writer.Position = 0; } } } @@ -222,6 +202,18 @@ internal virtual void Update() // then later the transport events will do the clean up. public abstract void Disconnect(); + // cleanup is called before the connection is removed. + // return any batches' pooled writers before the connection disappears. + // otherwise if a connection disappears before flushing, writers would + // never be returned to the pool. + public virtual void Cleanup() + { + foreach (Batcher batcher in batches.Values) + { + batcher.Clear(); + } + } + public override string ToString() => $"connection({connectionId})"; } } diff --git a/Assets/Mirror/Core/NetworkConnectionToClient.cs b/Assets/Mirror/Core/NetworkConnectionToClient.cs index e7c0bd0..361b00c 100644 --- a/Assets/Mirror/Core/NetworkConnectionToClient.cs +++ b/Assets/Mirror/Core/NetworkConnectionToClient.cs @@ -14,17 +14,12 @@ public class NetworkConnectionToClient : NetworkConnection readonly NetworkWriter reliableRpcs = new NetworkWriter(); readonly NetworkWriter unreliableRpcs = new NetworkWriter(); - public override string address => - Transport.active.ServerGetClientAddress(connectionId); + public virtual string address => Transport.active.ServerGetClientAddress(connectionId); /// NetworkIdentities that this connection can see // TODO move to server's NetworkConnectionToClient? public readonly HashSet observing = new HashSet(); - // Deprecated 2022-10-13 - [Obsolete(".clientOwnedObjects was renamed to .owned :)")] - public HashSet clientOwnedObjects => owned; - // unbatcher public Unbatcher unbatcher = new Unbatcher(); @@ -47,17 +42,25 @@ public class NetworkConnectionToClient : NetworkConnection // Snapshot Buffer size limit to avoid ever growing list memory consumption attacks from clients. public int snapshotBufferSizeLimit = 64; + // ping for rtt (round trip time) + // useful for statistics, lag compensation, etc. + double lastPingTime = 0; + internal ExponentialMovingAverage _rtt = new ExponentialMovingAverage(NetworkTime.PingWindowSize); + + /// Round trip time (in seconds) that it takes a message to go server->client->server. + public double rtt => _rtt.Value; + public NetworkConnectionToClient(int networkConnectionId) : base(networkConnectionId) { // initialize EMA with 'emaDuration' seconds worth of history. // 1 second holds 'sendRate' worth of values. // multiplied by emaDuration gives n-seconds. - driftEma = new ExponentialMovingAverage(NetworkServer.sendRate * NetworkClient.driftEmaDuration); - deliveryTimeEma = new ExponentialMovingAverage(NetworkServer.sendRate * NetworkClient.deliveryTimeEmaDuration); + driftEma = new ExponentialMovingAverage(NetworkServer.sendRate * NetworkClient.snapshotSettings.driftEmaDuration); + deliveryTimeEma = new ExponentialMovingAverage(NetworkServer.sendRate * NetworkClient.snapshotSettings.deliveryTimeEmaDuration); // buffer limit should be at least multiplier to have enough in there - snapshotBufferSizeLimit = Mathf.Max((int)NetworkClient.bufferTimeMultiplier, snapshotBufferSizeLimit); + snapshotBufferSizeLimit = Mathf.Max((int)NetworkClient.snapshotSettings.bufferTimeMultiplier, snapshotBufferSizeLimit); } public void OnTimeSnapshot(TimeSnapshot snapshot) @@ -66,14 +69,14 @@ public void OnTimeSnapshot(TimeSnapshot snapshot) if (snapshots.Count >= snapshotBufferSizeLimit) return; // (optional) dynamic adjustment - if (NetworkClient.dynamicAdjustment) + if (NetworkClient.snapshotSettings.dynamicAdjustment) { // set bufferTime on the fly. // shows in inspector for easier debugging :) bufferTimeMultiplier = SnapshotInterpolation.DynamicAdjustment( NetworkServer.sendInterval, deliveryTimeEma.StandardDeviation, - NetworkClient.dynamicAdjustmentTolerance + NetworkClient.snapshotSettings.dynamicAdjustmentTolerance ); // Debug.Log($"[Server]: {name} delivery std={serverDeliveryTimeEma.StandardDeviation} bufferTimeMult := {bufferTimeMultiplier} "); } @@ -81,16 +84,17 @@ public void OnTimeSnapshot(TimeSnapshot snapshot) // insert into the server buffer & initialize / adjust / catchup SnapshotInterpolation.InsertAndAdjust( snapshots, + NetworkClient.snapshotSettings.bufferLimit, snapshot, ref remoteTimeline, ref remoteTimescale, NetworkServer.sendInterval, bufferTime, - NetworkClient.catchupSpeed, - NetworkClient.slowdownSpeed, + NetworkClient.snapshotSettings.catchupSpeed, + NetworkClient.snapshotSettings.slowdownSpeed, ref driftEma, - NetworkClient.catchupNegativeThreshold, - NetworkClient.catchupPositiveThreshold, + NetworkClient.snapshotSettings.catchupNegativeThreshold, + NetworkClient.snapshotSettings.catchupPositiveThreshold, ref deliveryTimeEma ); } @@ -116,69 +120,24 @@ public void UpdateTimeInterpolation() protected override void SendToTransport(ArraySegment segment, int channelId = Channels.Reliable) => Transport.active.ServerSend(connectionId, segment, channelId); - void FlushRpcs(NetworkWriter buffer, int channelId) - { - if (buffer.Position > 0) - { - Send(new RpcBufferMessage{ payload = buffer }, channelId); - buffer.Position = 0; - } - } - - // helper for both channels - void BufferRpc(RpcMessage message, NetworkWriter buffer, int channelId, int maxMessageSize) - { - // calculate buffer limit. we can only fit so much into a message. - // max - message header - WriteArraySegment size header - batch header - int bufferLimit = maxMessageSize - NetworkMessages.IdSize - sizeof(int) - Batcher.HeaderSize; - - // remember previous valid position - int before = buffer.Position; - - // serialize the message without header - buffer.Write(message); - - // before we potentially flush out old messages, - // let's ensure this single message can even fit the limit. - // otherwise no point in flushing. - int messageSize = buffer.Position - before; - if (messageSize > bufferLimit) - { - Debug.LogWarning($"NetworkConnectionToClient: discarded RpcMesage for netId={message.netId} componentIndex={message.componentIndex} functionHash={message.functionHash} because it's larger than the rpc buffer limit of {bufferLimit} bytes for the channel: {channelId}"); - return; - } - - // too much to fit into max message size? - // then flush first, then write it again. - // (message + message header + 4 bytes WriteArraySegment header) - if (buffer.Position > bufferLimit) - { - buffer.Position = before; - FlushRpcs(buffer, channelId); // this resets position - buffer.Write(message); - } - } - - internal void BufferRpc(RpcMessage message, int channelId) + protected virtual void UpdatePing() { - int maxMessageSize = Transport.active.GetMaxPacketSize(channelId); - if (channelId == Channels.Reliable) + // localTime (double) instead of Time.time for accuracy over days + if (NetworkTime.localTime >= lastPingTime + NetworkTime.PingInterval) { - BufferRpc(message, reliableRpcs, Channels.Reliable, maxMessageSize); - } - else if (channelId == Channels.Unreliable) - { - BufferRpc(message, unreliableRpcs, Channels.Unreliable, maxMessageSize); + // TODO it would be safer for the server to store the last N + // messages' timestamp and only send a message number. + // This way client's can't just modify the timestamp. + // predictedTime parameter is 0 because the server doesn't predict. + NetworkPingMessage pingMessage = new NetworkPingMessage(NetworkTime.localTime, 0); + Send(pingMessage, Channels.Unreliable); + lastPingTime = NetworkTime.localTime; } } internal override void Update() { - // send rpc buffers - FlushRpcs(reliableRpcs, Channels.Reliable); - FlushRpcs(unreliableRpcs, Channels.Unreliable); - - // call base update to flush out batched messages + UpdatePing(); base.Update(); } @@ -245,7 +204,12 @@ internal void DestroyOwnedObjects() { if (netIdentity != null) { - NetworkServer.Destroy(netIdentity.gameObject); + // unspawn scene objects, destroy instantiated objects. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3538 + if (netIdentity.sceneId != 0) + NetworkServer.UnSpawn(netIdentity.gameObject); + else + NetworkServer.Destroy(netIdentity.gameObject); } } diff --git a/Assets/Mirror/Core/NetworkConnectionToServer.cs b/Assets/Mirror/Core/NetworkConnectionToServer.cs index 58e60e9..496813d 100644 --- a/Assets/Mirror/Core/NetworkConnectionToServer.cs +++ b/Assets/Mirror/Core/NetworkConnectionToServer.cs @@ -5,8 +5,6 @@ namespace Mirror { public class NetworkConnectionToServer : NetworkConnection { - public override string address => ""; - // Send stage three: hand off to transport [MethodImpl(MethodImplOptions.AggressiveInlining)] protected override void SendToTransport(ArraySegment segment, int channelId = Channels.Reliable) => diff --git a/Assets/Mirror/Core/NetworkIdentity.cs b/Assets/Mirror/Core/NetworkIdentity.cs index bd3f06f..aed8251 100644 --- a/Assets/Mirror/Core/NetworkIdentity.cs +++ b/Assets/Mirror/Core/NetworkIdentity.cs @@ -10,8 +10,8 @@ #if UNITY_2021_2_OR_NEWER using UnityEditor.SceneManagement; -#elif UNITY_2018_3_OR_NEWER - using UnityEditor.Experimental.SceneManagement; +#else +using UnityEditor.Experimental.SceneManagement; #endif #endif @@ -93,9 +93,8 @@ public sealed class NetworkIdentity : MonoBehaviour // for example: main player & pets are owned. monsters & npcs aren't. public bool isOwned { get; internal set; } - // Deprecated 2022-10-13 - [Obsolete(".hasAuthority was renamed to .isOwned. This is easier to understand and prepares for SyncDirection, where there is a difference betwen isOwned and authority.")] - public bool hasAuthority => isOwned; + // internal so NetworkManager can reset it from StopClient. + internal bool clientStarted; /// The set of network connections (players) that can see this object. public readonly Dictionary observers = @@ -115,7 +114,7 @@ public sealed class NetworkIdentity : MonoBehaviour // // it's also easier to work with for serialization etc. // serialized and visible in inspector for easier debugging - [SerializeField] uint _assetId; + [SerializeField, HideInInspector] uint _assetId; // The AssetId trick: // Ideally we would have a serialized 'Guid m_AssetId' but Unity can't @@ -198,10 +197,18 @@ internal set // ForceHidden = useful to hide monsters while they respawn etc. // ForceShown = useful to have score NetworkIdentities that always broadcast // to everyone etc. - // - // TODO rename to 'visibility' after removing .visibility some day! [Tooltip("Visibility can overwrite interest management. ForceHidden can be useful to hide monsters while they respawn. ForceShown can be useful for score NetworkIdentities that should always broadcast to everyone in the world.")] - public Visibility visible = Visibility.Default; + [FormerlySerializedAs("visible")] + public Visibility visibility = Visibility.Default; + + // Deprecated 2024-01-21 + [HideInInspector] + [Obsolete("Deprecated - Use .visibility instead. This will be removed soon.")] + public Visibility visible + { + get => visibility; + set => visibility = value; + } // broadcasting serializes all entities around a player for each player. // we don't want to serialize one entity twice in the same tick. @@ -292,9 +299,12 @@ internal static void ResetServerStatics() // BUT internal so tests can add them after creating the NetworkIdentity internal void InitializeNetworkBehaviours() { - // Get all NetworkBehaviours - // (never null. GetComponents returns [] if none found) - NetworkBehaviours = GetComponents(); + // Get all NetworkBehaviour components, including children. + // Some users need NetworkTransform on child bones, etc. + // => Deterministic: https://forum.unity.com/threads/getcomponentsinchildren.4582/#post-33983 + // => Never null. GetComponents returns [] if none found. + // => Include inactive. We need all child components. + NetworkBehaviours = GetComponentsInChildren(true); ValidateComponents(); // initialize each one @@ -347,18 +357,56 @@ void OnValidate() hasSpawned = false; #if UNITY_EDITOR + DisallowChildNetworkIdentities(); SetupIDs(); #endif } + // expose our AssetId Guid to uint mapping code in case projects need to map Guids to uint as well. + // this way their projects won't break if we change our mapping algorithm. + // needs to be available at runtime / builds, don't wrap in #if UNITY_EDITOR + public static uint AssetGuidToUint(Guid guid) => (uint)guid.GetHashCode(); // deterministic + #if UNITY_EDITOR + // child NetworkIdentities are not supported. + // Disallow them and show an error for the user to fix. + // This needs to work for Prefabs & Scene objects, so the previous check + // in NetworkClient.RegisterPrefab is not enough. + void DisallowChildNetworkIdentities() + { +#if UNITY_2020_3_OR_NEWER + NetworkIdentity[] identities = GetComponentsInChildren(true); +#else + NetworkIdentity[] identities = GetComponentsInChildren(); +#endif + if (identities.Length > 1) + { + // always log the next child component so it's easy to fix. + // if there are multiple, then after removing it'll log the next. + Debug.LogError($"'{name}' has another NetworkIdentity component on '{identities[1].name}'. There should only be one NetworkIdentity, and it must be on the root object. Please remove the other one.", this); + } + } + void AssignAssetID(string path) { // only set if not empty. fixes https://github.com/vis2k/Mirror/issues/2765 if (!string.IsNullOrWhiteSpace(path)) { + // if we generate the assetId then we MUST be sure to set dirty + // in order to save the prefab object properly. otherwise it + // would be regenerated every time we reopen the prefab. + // -> Undo.RecordObject is the new EditorUtility.SetDirty! + // -> we need to call it before changing. + // + // to verify this, duplicate a prefab and double click to open it. + // add a log message if "_assetId != before_". + // without RecordObject, it'll log every time because it's not saved. + Undo.RecordObject(this, "Assigned AssetId"); + + // uint before = _assetId; Guid guid = new Guid(AssetDatabase.AssetPathToGUID(path)); - assetId = (uint)guid.GetHashCode(); // deterministic + assetId = AssetGuidToUint(guid); + // if (_assetId != before) Debug.Log($"Assigned assetId={assetId} to {name}"); } } @@ -670,7 +718,6 @@ internal void OnStopServer() } } - bool clientStarted; internal void OnStartClient() { if (clientStarted) return; @@ -919,6 +966,19 @@ internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, Netw if (ownerDirty) ownerWriter.WriteBytes(segment.Array, segment.Offset, segment.Count); if (observersDirty) observersWriter.WriteBytes(segment.Array, segment.Offset, segment.Count); } + + // clear dirty bits for the components that we serialized. + // do not clear for _all_ components, only the ones that + // were dirty and had their syncInterval elapsed. + // + // we don't want to clear bits before the syncInterval + // was elapsed, as then they wouldn't be synced. + // + // only clear for delta, not for full (spawn messages). + // otherwise if a player joins, we serialize monster, + // and shouldn't clear dirty bits not yet synced to + // other players. + if (!initialState) comp.ClearAllDirtyBits(); } } } @@ -968,6 +1028,14 @@ internal void SerializeClient(NetworkWriter writer) // serialize into writer. // server always knows initialState, we never need to send it comp.Serialize(writer, false); + + // clear dirty bits for the components that we serialized. + // do not clear for _all_ components, only the ones that + // were dirty and had their syncInterval elapsed. + // + // we don't want to clear bits before the syncInterval + // was elapsed, as then they wouldn't be synced. + comp.ClearAllDirtyBits(); } } } @@ -1066,27 +1134,6 @@ internal NetworkIdentitySerialization GetServerSerializationAtTick(int tick) lastSerialization.ownerWriter, lastSerialization.observersWriter); - // clear dirty bits for the components that we serialized. - // previously we did this in NetworkServer.BroadcastToConnection - // for every connection, for every entity. - // but we only serialize each entity once, right here in this - // 'lastSerialization.tick != tick' scope. - // so only do it once. - // - // NOTE: not in Serializell as that should only do one - // thing: serialize data. - // - // - // NOTE: DO NOT clear ALL component's dirty bits, because - // components can have different syncIntervals and we - // don't want to reset dirty bits for the ones that were - // not synced yet. - // - // NOTE: this used to be very important to avoid ever growing - // SyncList changes if they had no observers, but we've - // added SyncObject.isRecording since. - ClearDirtyComponentsDirtyBits(); - // set tick lastSerialization.tick = tick; //Debug.Log($"{name} (netId={netId}) serialized for tick={tickTimeStamp}"); @@ -1096,23 +1143,6 @@ internal NetworkIdentitySerialization GetServerSerializationAtTick(int tick) return lastSerialization; } - // Clear only dirty component's dirty bits. ignores components which - // may be dirty but not ready to be synced yet (because of syncInterval) - // - // NOTE: this used to be very important to avoid ever - // growing SyncList changes if they had no observers, - // but we've added SyncObject.isRecording since. - internal void ClearDirtyComponentsDirtyBits() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - if (comp.IsDirty()) - { - comp.ClearAllDirtyBits(); - } - } - } - internal void AddObserver(NetworkConnectionToClient conn) { if (observers.ContainsKey(conn.connectionId)) @@ -1264,7 +1294,7 @@ public void RemoveClientAuthority() // the identity during destroy as people might want to be able to read // the members inside OnDestroy(), and we have no way of invoking reset // after OnDestroy is called. - internal void Reset() + internal void ResetState() { hasSpawned = false; clientStarted = false; diff --git a/Assets/Mirror/Core/NetworkLoop.cs b/Assets/Mirror/Core/NetworkLoop.cs index d341b4b..a9cd490 100644 --- a/Assets/Mirror/Core/NetworkLoop.cs +++ b/Assets/Mirror/Core/NetworkLoop.cs @@ -99,6 +99,15 @@ internal static bool AddToPlayerLoop(PlayerLoopSystem.UpdateFunction function, T //foreach (PlayerLoopSystem sys in playerLoop.subSystemList) // Debug.Log($" ->{sys.type}"); + // make sure the function wasn't added yet. + // with domain reload disabled, it would otherwise be added twice: + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3392 + if (Array.FindIndex(playerLoop.subSystemList, (s => s.updateDelegate == function)) != -1) + { + // loop contains the function, so return true. + return true; + } + // resize & expand subSystemList to fit one more entry int oldListLength = (playerLoop.subSystemList != null) ? playerLoop.subSystemList.Length : 0; Array.Resize(ref playerLoop.subSystemList, oldListLength + 1); @@ -174,6 +183,11 @@ static void RuntimeInitializeOnLoad() static void NetworkEarlyUpdate() { + // loop functions run in edit mode and in play mode. + // however, we only want to call NetworkServer/Client in play mode. + if (!Application.isPlaying) return; + + NetworkTime.EarlyUpdate(); //Debug.Log($"NetworkEarlyUpdate {Time.time}"); NetworkServer.NetworkEarlyUpdate(); NetworkClient.NetworkEarlyUpdate(); @@ -183,6 +197,10 @@ static void NetworkEarlyUpdate() static void NetworkLateUpdate() { + // loop functions run in edit mode and in play mode. + // however, we only want to call NetworkServer/Client in play mode. + if (!Application.isPlaying) return; + //Debug.Log($"NetworkLateUpdate {Time.time}"); // invoke event before mirror does its final late updating. OnLateUpdate?.Invoke(); diff --git a/Assets/Mirror/Core/NetworkManager.cs b/Assets/Mirror/Core/NetworkManager.cs index f24d8ce..ef21e6c 100644 --- a/Assets/Mirror/Core/NetworkManager.cs +++ b/Assets/Mirror/Core/NetworkManager.cs @@ -9,6 +9,7 @@ namespace Mirror { public enum PlayerSpawnMethod { Random, RoundRobin } public enum NetworkManagerMode { Offline, ServerOnly, ClientOnly, Host } + public enum HeadlessStartOptions { DoNothing, AutoStartServer, AutoStartClient } [DisallowMultipleComponent] [AddComponentMenu("Network/Network Manager")] @@ -28,32 +29,34 @@ public class NetworkManager : MonoBehaviour public bool runInBackground = true; /// Should the server auto-start when 'Server Build' is checked in build settings - [Header("Headless Builds")] - [Tooltip("Should the server auto-start when 'Server Build' is checked in build settings")] - [FormerlySerializedAs("startOnHeadless")] - public bool autoStartServerBuild = true; + [Header("Auto-Start Options")] - [Tooltip("Automatically connect the client in headless builds. Useful for CCU tests with bot clients.\n\nAddress may be passed as command line argument.\n\nMake sure that only 'autostartServer' or 'autoconnectClient' is enabled, not both!")] - public bool autoConnectClientBuild; + [Tooltip("Choose whether Server or Client should auto-start in headless builds")] + public HeadlessStartOptions headlessStartMode = HeadlessStartOptions.DoNothing; + + [Tooltip("Headless Start Mode in Editor\nwhen enabled, headless start mode will be used in editor as well.")] + public bool editorAutoStart; /// Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE. - [Tooltip("Server & Client send rate per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")] + [Tooltip("Server / Client send rate per second.\nUse 60-100Hz for fast paced games like Counter-Strike to minimize latency.\nUse around 30Hz for games like WoW to minimize computations.\nUse around 1-10Hz for slow paced games like EVE.")] [FormerlySerializedAs("serverTickRate")] - public int sendRate = 30; - - // Deprecated 2022-10-31 - [Obsolete("NetworkManager.serverTickRate was renamed to sendRate because that's what it configures for both server & client now.")] - public int serverTickRate => sendRate; + public int sendRate = 60; + + // Deprecated 2023-11-25 + // Using SerializeField and HideInInspector to self-correct for being + // replaced by headlessStartMode. This can be removed in the future. + // See OnValidate() for how we handle this. + [Obsolete("Deprecated - Use headlessStartMode instead.")] + [FormerlySerializedAs("autoStartServerBuild"), SerializeField, HideInInspector] + public bool autoStartServerBuild = true; - // tick rate is in Hz. - // convert to interval in seconds for convenience where needed. - // - // send interval is 1 / sendRate. - // but for tests we need a way to set it to exactly 0. - // 1 / int.max would not be exactly 0, so handel that manually. - // Deprecated 2022-10-06 - [Obsolete("NetworkManager.serverTickInterval was moved to NetworkServer.tickInterval for consistency.")] - public float serverTickInterval => NetworkServer.tickInterval; + // Deprecated 2023-11-25 + // Using SerializeField and HideInInspector to self-correct for being + // replaced by headlessStartMode. This can be removed in the future. + // See OnValidate() for how we handle this. + [Obsolete("Deprecated - Use headlessStartMode instead.")] + [FormerlySerializedAs("autoConnectClientBuild"), SerializeField, HideInInspector] + public bool autoConnectClientBuild; // client send rate follows server send rate to avoid errors for now /// Client Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE. @@ -88,6 +91,15 @@ public class NetworkManager : MonoBehaviour [Tooltip("Maximum number of concurrent connections.")] public int maxConnections = 100; + // Mirror global disconnect inactive option, independent of Transport. + // not all Transports do this properly, and it's easiest to configure this just once. + // this is very useful for some projects, keep it. + [Tooltip("When enabled, the server automatically disconnects inactive connections after the configured timeout.")] + public bool disconnectInactiveConnections; + + [Tooltip("Timeout in seconds for server to automatically disconnect inactive connections if 'disconnectInactiveConnections' is enabled.")] + public float disconnectInactiveTimeout = 60f; + [Header("Authentication")] [Tooltip("Authentication component attached to this object")] public NetworkAuthenticator authenticator; @@ -118,7 +130,23 @@ public class NetworkManager : MonoBehaviour public static List startPositions = new List(); public static int startPositionIndex; - [Header("Debug")] + [Header("Security")] + [Tooltip("For security, it is recommended to disconnect a player if a networked action triggers an exception\nThis could prevent components being accessed in an undefined state, which may be an attack vector for exploits.\nHowever, some games may want to allow exceptions in order to not interrupt the player's experience.")] + public bool exceptionsDisconnect = true; // security by default + + [Header("Snapshot Interpolation")] + public SnapshotInterpolationSettings snapshotSettings = new SnapshotInterpolationSettings(); + + [Header("Connection Quality")] + [Tooltip("Method to use for connection quality evaluation.\nSimple: based on rtt and jitter.\nPragmatic: based on snapshot interpolation adjustment.")] + public ConnectionQualityMethod evaluationMethod; + + [Tooltip("Interval in seconds to evaluate connection quality.\nSet to 0 to disable connection quality evaluation.")] + [Range(0, 60)] + [FormerlySerializedAs("connectionQualityInterval")] + public float evaluationInterval = 3; + + [Header("Interpolation UI - Requires Editor / Dev Build")] public bool timeInterpolationGui = false; /// The one and only NetworkManager @@ -150,6 +178,24 @@ public class NetworkManager : MonoBehaviour // virtual so that inheriting classes' OnValidate() can call base.OnValidate() too public virtual void OnValidate() { +#pragma warning disable 618 + // autoStartServerBuild and autoConnectClientBuild are now obsolete, but to avoid + // a breaking change we'll set headlessStartMode to what the user had set before. + // + // headlessStartMode defaults to DoNothing, so if the user had neither of these + // set, then it will remain as DoNothing, and if they set headlessStartMode to + // any selection in the inspector it won't get changed back. + if (autoStartServerBuild) + headlessStartMode = HeadlessStartOptions.AutoStartServer; + else if (autoConnectClientBuild) + headlessStartMode = HeadlessStartOptions.AutoStartClient; + + // Setting both to false here prevents this code from fighting with user + // selection in the inspector, and they're both SerialisedField's. + autoStartServerBuild = false; + autoConnectClientBuild = false; +#pragma warning restore 618 + // always >= 0 maxConnections = Mathf.Max(maxConnections, 0); @@ -162,7 +208,7 @@ public virtual void OnValidate() // This avoids the mysterious "Replacing existing prefab with assetId ... Old prefab 'Player', New prefab 'Player'" warning. if (playerPrefab != null && spawnPrefabs.Contains(playerPrefab)) { - Debug.LogWarning("NetworkManager - Player Prefab should not be added to Registered Spawnable Prefabs list...removed it."); + Debug.LogWarning("NetworkManager - Player Prefab doesn't need to be in Spawnable Prefabs list too. Removing it."); spawnPrefabs.Remove(playerPrefab); } } @@ -208,22 +254,26 @@ public virtual void Awake() // virtual so that inheriting classes' Start() can call base.Start() too public virtual void Start() { - // headless mode? then start the server - // can't do this in Awake because Awake is for initialization. - // some transports might not be ready until Start. + // Auto-start headless server or client. // - // (tick rate is applied in StartServer!) -#if UNITY_SERVER - if (autoStartServerBuild) - { - StartServer(); - } - // only start server or client, never both - else if(autoConnectClientBuild) + // We can't do this in Awake because Awake is for initialization + // and some transports might not be ready until Start. + // + // Auto-starting in Editor is useful for debugging, so that can + // be enabled with editorAutoStart. + if (Utils.IsHeadless()) { - StartClient(); + if (!Application.isEditor || editorAutoStart) + switch (headlessStartMode) + { + case HeadlessStartOptions.AutoStartServer: + StartServer(); + break; + case HeadlessStartOptions.AutoStartClient: + StartClient(); + break; + } } -#endif } // make sure to call base.Update() when overwriting @@ -238,6 +288,8 @@ public virtual void LateUpdate() UpdateScene(); } + //////////////////////////////////////////////////////////////////////// + // keep the online scene change check in a separate function. // only change scene if the requested online scene is not blank, and is not already loaded. bool IsServerOnlineSceneChangeNeeded() => @@ -245,10 +297,6 @@ bool IsServerOnlineSceneChangeNeeded() => !Utils.IsSceneActive(onlineScene) && onlineScene != offlineScene; - // Deprecated 2022-12-12 - [Obsolete("NetworkManager.IsSceneActive moved to Utils.IsSceneActive")] - public static bool IsSceneActive(string scene) => Utils.IsSceneActive(scene); - // NetworkManager exposes some NetworkServer/Client configuration. // we apply it every Update() in order to avoid two sources of truth. // fixes issues where NetworkServer.sendRate was never set because @@ -257,6 +305,9 @@ bool IsServerOnlineSceneChangeNeeded() => void ApplyConfiguration() { NetworkServer.tickRate = sendRate; + NetworkClient.snapshotSettings = snapshotSettings; + NetworkClient.connectionQualityInterval = evaluationInterval; + NetworkClient.connectionQualityMethod = evaluationMethod; } // full server setup code, without spawning objects yet @@ -265,6 +316,11 @@ void SetupServer() // Debug.Log("NetworkManager SetupServer"); InitializeSingleton(); + // apply settings before initializing anything + NetworkServer.disconnectInactiveConnections = disconnectInactiveConnections; + NetworkServer.disconnectInactiveTimeout = disconnectInactiveTimeout; + NetworkServer.exceptionsDisconnect = exceptionsDisconnect; + if (runInBackground) Application.runInBackground = true; @@ -341,6 +397,15 @@ void SetupClient() { InitializeSingleton(); +#pragma warning disable 618 + // Remove when OnConnectionQualityChanged is removed. + NetworkClient.onConnectionQualityChanged += OnConnectionQualityChanged; +#pragma warning restore 618 + + // apply settings before initializing anything + NetworkClient.exceptionsDisconnect = exceptionsDisconnect; + // NetworkClient.sendRate = clientSendRate; + if (runInBackground) Application.runInBackground = true; @@ -350,18 +415,25 @@ void SetupClient() authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated); } - // NetworkClient.sendRate = clientSendRate; } /// Starts the client, connects it to the server with networkAddress. public void StartClient() { + // Do checks and short circuits before setting anything up. + // If / when we retry, we won't have conflict issues. if (NetworkClient.active) { Debug.LogWarning("Client already started."); return; } + if (string.IsNullOrWhiteSpace(networkAddress)) + { + Debug.LogError("Must set the Network Address field in the manager"); + return; + } + mode = NetworkManagerMode.ClientOnly; SetupClient(); @@ -371,13 +443,6 @@ public void StartClient() RegisterClientMessages(); - if (string.IsNullOrWhiteSpace(networkAddress)) - { - Debug.LogError("Must set the Network Address field in the manager"); - return; - } - // Debug.Log($"NetworkManager StartClient address:{networkAddress}"); - NetworkClient.Connect(networkAddress); OnStartClient(); @@ -521,11 +586,9 @@ void FinishStartHost() // client will do things before the server is even fully started. //Debug.Log("StartHostClient called"); SetupClient(); - - networkAddress = "localhost"; RegisterClientMessages(); - // call OnConencted needs to be called AFTER RegisterClientMessages + // InvokeOnConnected needs to be called AFTER RegisterClientMessages // (https://github.com/vis2k/Mirror/pull/1249/) HostMode.InvokeOnConnected(); @@ -536,14 +599,6 @@ void FinishStartHost() public void StopHost() { OnStopHost(); - - // calling OnTransportDisconnected was needed to fix - // https://github.com/vis2k/Mirror/issues/1515 - // so that the host client receives a DisconnectMessage - // TODO reevaluate if this is still needed after all the disconnect - // fixes, and try to put this into LocalConnection.Disconnect! - NetworkServer.OnTransportDisconnected(NetworkConnection.LocalConnectionId); - StopClient(); StopServer(); } @@ -596,6 +651,12 @@ public void StopClient() if (mode == NetworkManagerMode.Offline) return; + // For Host client, call OnServerDisconnect before NetworkClient.Disconnect + // because we need NetworkServer.localConnection to not be null + // NetworkClient.Disconnect will set it null. + if (mode == NetworkManagerMode.Host) + OnServerDisconnect(NetworkServer.localConnection); + // ask client -> transport to disconnect. // handle voluntary and involuntary disconnects in OnClientDisconnect. // @@ -608,6 +669,11 @@ public void StopClient() // NetworkManager.OnClientDisconnect NetworkClient.Disconnect(); +#pragma warning disable 618 + // Remove when OnConnectionQualityChanged is removed. + NetworkClient.onConnectionQualityChanged -= OnConnectionQualityChanged; +#pragma warning restore 618 + // UNET invoked OnDisconnected cleanup immediately. // let's keep it for now, in case any projects depend on it. // TODO simply remove this in the future. @@ -644,10 +710,11 @@ public virtual void OnApplicationQuit() // useful for headless benchmark clients. public virtual void ConfigureHeadlessFrameRate() { -#if UNITY_SERVER - Application.targetFrameRate = sendRate; - // Debug.Log($"Server Tick Rate set to {Application.targetFrameRate} Hz."); -#endif + if (Utils.IsHeadless()) + { + Application.targetFrameRate = sendRate; + // Debug.Log($"Server Tick Rate set to {Application.targetFrameRate} Hz."); + } } bool InitializeSingleton() @@ -683,6 +750,20 @@ bool InitializeSingleton() // set active transport AFTER setting singleton. // so only if we didn't destroy ourselves. + + // This tries to avoid missing transport errors and more clearly tells user what to fix. + if (transport == null) + if (TryGetComponent(out Transport newTransport)) + { + Debug.LogWarning($"No Transport assigned to Network Manager - Using {newTransport} found on same object."); + transport = newTransport; + } + else + { + Debug.LogError("No Transport on Network Manager...add a transport and assign it."); + return false; + } + Transport.active = transport; return true; } @@ -692,6 +773,7 @@ void RegisterServerMessages() NetworkServer.OnConnectedEvent = OnServerConnectInternal; NetworkServer.OnDisconnectedEvent = OnServerDisconnect; NetworkServer.OnErrorEvent = OnServerError; + NetworkServer.OnTransportExceptionEvent = OnServerTransportException; NetworkServer.RegisterHandler(OnServerAddPlayerInternal); // Network Server initially registers its own handler for this, so we replace it here. @@ -703,7 +785,10 @@ void RegisterClientMessages() NetworkClient.OnConnectedEvent = OnClientConnectInternal; NetworkClient.OnDisconnectedEvent = OnClientDisconnectInternal; NetworkClient.OnErrorEvent = OnClientError; - NetworkClient.RegisterHandler(OnClientNotReadyMessageInternal); + NetworkClient.OnTransportExceptionEvent = OnClientTransportException; + + // Don't require authentication because server may send NotReadyMessage from ServerChangeScene + NetworkClient.RegisterHandler(OnClientNotReadyMessageInternal, false); NetworkClient.RegisterHandler(OnClientSceneInternal, false); if (playerPrefab != null) @@ -766,6 +851,14 @@ public virtual void ServerChangeScene(string newSceneName) return; } + // Throw error if called from client + // Allow changing scene while stopping the server + if (!NetworkServer.active && newSceneName != offlineScene) + { + Debug.LogError("ServerChangeScene can only be called on an active server."); + return; + } + // Debug.Log($"ServerChangeScene {newSceneName}"); NetworkServer.SetAllClientsNotReady(); networkSceneName = newSceneName; @@ -1267,7 +1360,7 @@ void OnClientSceneInternal(SceneMessage msg) } /// Called on the server when a new client connects. - public virtual void OnServerConnect(NetworkConnectionToClient conn) {} + public virtual void OnServerConnect(NetworkConnectionToClient conn) { } /// Called on the server when a client disconnects. // Called by NetworkServer.OnTransportDisconnect! @@ -1306,22 +1399,17 @@ public virtual void OnServerAddPlayer(NetworkConnectionToClient conn) NetworkServer.AddPlayerForConnection(conn, player); } - // Deprecated 2022-05-12 - [Obsolete("OnServerError(conn, Exception) was changed to OnServerError(conn, TransportError, string)")] - public virtual void OnServerError(NetworkConnectionToClient conn, Exception exception) {} /// Called on server when transport raises an exception. NetworkConnection may be null. - public virtual void OnServerError(NetworkConnectionToClient conn, TransportError error, string reason) - { -#pragma warning disable CS0618 - OnServerError(conn, new Exception(reason)); -#pragma warning restore CS0618 - } + public virtual void OnServerError(NetworkConnectionToClient conn, TransportError error, string reason) { } + + /// Called on server when transport raises an exception. NetworkConnection may be null. + public virtual void OnServerTransportException(NetworkConnectionToClient conn, Exception exception) { } /// Called from ServerChangeScene immediately before SceneManager.LoadSceneAsync is executed - public virtual void OnServerChangeScene(string newSceneName) {} + public virtual void OnServerChangeScene(string newSceneName) { } /// Called on server after a scene load with ServerChangeScene() is completed. - public virtual void OnServerSceneChanged(string sceneName) {} + public virtual void OnServerSceneChanged(string sceneName) { } /// Called on the client when connected to a server. By default it sets client as ready and adds a player. public virtual void OnClientConnect() @@ -1342,25 +1430,38 @@ public virtual void OnClientConnect() } /// Called on clients when disconnected from a server. - public virtual void OnClientDisconnect() {} + public virtual void OnClientDisconnect() { } - // Deprecated 2022-05-12 - [Obsolete("OnClientError(Exception) was changed to OnClientError(TransportError, string)")] - public virtual void OnClientError(Exception exception) {} - /// Called on client when transport raises an exception. - public virtual void OnClientError(TransportError error, string reason) + // Deprecated 2023-12-05 + /// Deprecated: NetworkClient handles this now. + [Obsolete("NetworkClient handles this now.")] + public virtual void CalculateConnectionQuality() { -#pragma warning disable CS0618 - OnClientError(new Exception(reason)); -#pragma warning restore CS0618 + // Moved to NetworkClient } + // Deprecated 2023-12-05 + /// Deprecated: NetworkClient handles this now. + [Obsolete("This will be removed. Subscribe to NetworkClient.onConnectionQualityChanged in your own code")] + public virtual void OnConnectionQualityChanged(ConnectionQuality previous, ConnectionQuality current) + { + // logging the change is very useful to track down user's lag reports. + // we want to include as much detail as possible for debugging. + //Debug.Log($"[Mirror] Connection Quality changed from {previous} to {current}:\n rtt={(NetworkTime.rtt * 1000):F1}ms\n rttVar={(NetworkTime.rttVariance * 1000):F1}ms\n bufferTime={(NetworkClient.bufferTime * 1000):F1}ms"); + } + + /// Called on client when transport raises an exception. + public virtual void OnClientError(TransportError error, string reason) { } + + /// Called on client when transport raises an exception. + public virtual void OnClientTransportException(Exception exception) { } + /// Called on clients when a servers tells the client it is no longer ready, e.g. when switching scenes. - public virtual void OnClientNotReady() {} + public virtual void OnClientNotReady() { } /// Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed // customHandling: indicates if scene loading will be handled through overrides - public virtual void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) {} + public virtual void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) { } /// 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 @@ -1385,28 +1486,30 @@ public virtual void OnClientSceneChanged() // from all versions, so users only need to implement this one case. /// This is invoked when a host is started. - public virtual void OnStartHost() {} + public virtual void OnStartHost() { } /// This is invoked when a server is started - including when a host is started. - public virtual void OnStartServer() {} + public virtual void OnStartServer() { } /// This is invoked when the client is started. - public virtual void OnStartClient() {} + public virtual void OnStartClient() { } /// This is called when a server is stopped - including when a host is stopped. - public virtual void OnStopServer() {} + public virtual void OnStopServer() { } /// This is called when a client is stopped. - public virtual void OnStopClient() {} + public virtual void OnStopClient() { } /// This is called when a host is stopped. - public virtual void OnStopHost() {} + public virtual void OnStopHost() { } +#if DEBUG // keep OnGUI even in builds. useful to debug snap interp. void OnGUI() { if (!timeInterpolationGui) return; NetworkClient.OnGUI(); } +#endif } } diff --git a/Assets/Mirror/Core/NetworkManagerHUD.cs b/Assets/Mirror/Core/NetworkManagerHUD.cs index 0a267fb..62a126b 100644 --- a/Assets/Mirror/Core/NetworkManagerHUD.cs +++ b/Assets/Mirror/Core/NetworkManagerHUD.cs @@ -1,5 +1,3 @@ -// vis2k: GUILayout instead of spacey += ...; removed Update hotkeys to avoid -// confusion if someone accidentally presses one. using UnityEngine; namespace Mirror @@ -23,26 +21,24 @@ void Awake() void OnGUI() { - GUILayout.BeginArea(new Rect(10 + offsetX, 40 + offsetY, 250, 9999)); + // If this width is changed, also change offsetX in GUIConsole::OnGUI + int width = 300; + + GUILayout.BeginArea(new Rect(10 + offsetX, 40 + offsetY, width, 9999)); + if (!NetworkClient.isConnected && !NetworkServer.active) - { StartButtons(); - } else - { StatusLabels(); - } - // client ready if (NetworkClient.isConnected && !NetworkClient.ready) { if (GUILayout.Button("Client Ready")) { + // client ready NetworkClient.Ready(); if (NetworkClient.localPlayer == null) - { NetworkClient.AddPlayer(); - } } } @@ -55,44 +51,55 @@ void StartButtons() { if (!NetworkClient.active) { - // Server + Client - if (Application.platform != RuntimePlatform.WebGLPlayer) +#if UNITY_WEBGL + // cant be a server in webgl build + if (GUILayout.Button("Single Player")) { - if (GUILayout.Button("Host (Server + Client)")) - { - manager.StartHost(); - } + NetworkServer.dontListen = true; + manager.StartHost(); } +#else + // Server + Client + if (GUILayout.Button("Host (Server + Client)")) + manager.StartHost(); +#endif - // Client + IP + // Client + IP (+ PORT) GUILayout.BeginHorizontal(); + if (GUILayout.Button("Client")) - { manager.StartClient(); - } - // This updates networkAddress every frame from the TextField + manager.networkAddress = GUILayout.TextField(manager.networkAddress); + // only show a port field if we have a port transport + // we can't have "IP:PORT" in the address field since this only + // works for IPV4:PORT. + // for IPV6:PORT it would be misleading since IPV6 contains ":": + // 2001:0db8:0000:0000:0000:ff00:0042:8329 + if (Transport.active is PortTransport portTransport) + { + // use TryParse in case someone tries to enter non-numeric characters + if (ushort.TryParse(GUILayout.TextField(portTransport.Port.ToString()), out ushort port)) + portTransport.Port = port; + } + GUILayout.EndHorizontal(); // Server Only - if (Application.platform == RuntimePlatform.WebGLPlayer) - { - // cant be a server in webgl build - GUILayout.Box("( WebGL cannot be server )"); - } - else - { - if (GUILayout.Button("Server Only")) manager.StartServer(); - } +#if UNITY_WEBGL + // cant be a server in webgl build + GUILayout.Box("( WebGL cannot be server )"); +#else + if (GUILayout.Button("Server Only")) + manager.StartServer(); +#endif } else { // Connecting GUILayout.Label($"Connecting to {manager.networkAddress}.."); if (GUILayout.Button("Cancel Connection Attempt")) - { manager.StopClient(); - } } } @@ -104,51 +111,51 @@ void StatusLabels() // Client: ... if (NetworkServer.active && NetworkClient.active) { + // host mode GUILayout.Label($"Host: running via {Transport.active}"); } - // server only else if (NetworkServer.active) { + // server only GUILayout.Label($"Server: running via {Transport.active}"); } - // client only else if (NetworkClient.isConnected) { + // client only GUILayout.Label($"Client: connected to {manager.networkAddress} via {Transport.active}"); } } void StopButtons() { - // stop host if host mode if (NetworkServer.active && NetworkClient.isConnected) { GUILayout.BeginHorizontal(); +#if UNITY_WEBGL + if (GUILayout.Button("Stop Single Player")) + manager.StopHost(); +#else + // stop host if host mode if (GUILayout.Button("Stop Host")) - { manager.StopHost(); - } + + // stop client if host mode, leaving server up if (GUILayout.Button("Stop Client")) - { manager.StopClient(); - } +#endif GUILayout.EndHorizontal(); } - // stop client if client-only else if (NetworkClient.isConnected) { + // stop client if client-only if (GUILayout.Button("Stop Client")) - { manager.StopClient(); - } } - // stop server if server-only else if (NetworkServer.active) { + // stop server if server-only if (GUILayout.Button("Stop Server")) - { manager.StopServer(); - } } } } diff --git a/Assets/Mirror/Core/NetworkMessages.cs b/Assets/Mirror/Core/NetworkMessages.cs index c53072e..7a70d94 100644 --- a/Assets/Mirror/Core/NetworkMessages.cs +++ b/Assets/Mirror/Core/NetworkMessages.cs @@ -1,9 +1,32 @@ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Text; using UnityEngine; namespace Mirror { + // for performance, we (ab)use c# generics to cache the message id in a static field + // this is significantly faster than doing the computation at runtime or looking up cached results via Dictionary + // generic classes have separate static fields per type specification + public static class NetworkMessageId where T : struct, NetworkMessage + { + // automated message id from type hash. + // platform independent via stable hashcode. + // => convenient so we don't need to track messageIds across projects + // => addons can work with each other without knowing their ids before + // => 2 bytes is enough to avoid collisions. + // registering a messageId twice will log a warning anyway. + public static readonly ushort Id = CalculateId(); + + // Gets the 32bit fnv1a hash + // To get it down to 16bit but still reduce hash collisions we cant just cast it to ushort + // Instead we take the highest 16bits of the 32bit hash and fold them with xor into the lower 16bits + // This will create a more uniform 16bit hash, the method is described in: + // http://www.isthe.com/chongo/tech/comp/fnv/ in section "Changing the FNV hash size - xor-folding" + static ushort CalculateId() => typeof(T).FullName.GetStableHashCode16(); + } + // message packing all in one place, instead of constructing headers in all // kinds of different places // @@ -14,27 +37,51 @@ public static class NetworkMessages // size of message id header in bytes public const int IdSize = sizeof(ushort); + // Id <> Type lookup for debugging, profiler, etc. + // important when debugging messageId errors! + public static readonly Dictionary Lookup = + new Dictionary(); + + // dump all types for debugging + public static void LogTypes() + { + StringBuilder builder = new StringBuilder(); + builder.AppendLine("NetworkMessageIds:"); + foreach (KeyValuePair kvp in Lookup) + { + builder.AppendLine($" Id={kvp.Key} = {kvp.Value}"); + } + Debug.Log(builder.ToString()); + } + // max message content size (without header) calculation for convenience // -> Transport.GetMaxPacketSize is the raw maximum // -> Every message gets serialized into <> - // -> Every serialized message get put into a batch with a header - public static int MaxContentSize + // -> Every serialized message get put into a batch with one timestamp per batch + // -> Every message in a batch has a varuint size header. + // use the worst case VarUInt size for the largest possible + // message size = int.max. + public static int MaxContentSize(int channelId) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Transport.active.GetMaxPacketSize() - - IdSize - - Batcher.HeaderSize; + // calculate the max possible size that can fit in a batch + int transportMax = Transport.active.GetMaxPacketSize(channelId); + return transportMax - IdSize - Batcher.MaxMessageOverhead(transportMax); } + // max message size which includes header + content. + public static int MaxMessageSize(int channelId) => + MaxContentSize(channelId) + IdSize; + // automated message id from type hash. // platform independent via stable hashcode. // => convenient so we don't need to track messageIds across projects // => addons can work with each other without knowing their ids before // => 2 bytes is enough to avoid collisions. // registering a messageId twice will log a warning anyway. + // keep this for convenience. easier to use than NetworkMessageId.Id. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort GetId() where T : struct, NetworkMessage => - (ushort)(typeof(T).FullName.GetStableHashCode()); + NetworkMessageId.Id; // pack message before sending // -> NetworkWriter passed as arg so that we can use .ToArraySegment @@ -43,13 +90,12 @@ public static ushort GetId() where T : struct, NetworkMessage => public static void Pack(T message, NetworkWriter writer) where T : struct, NetworkMessage { - writer.WriteUShort(GetId()); + writer.WriteUShort(NetworkMessageId.Id); writer.Write(message); } // read only the message id. // common function in case we ever change the header size. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool UnpackId(NetworkReader reader, out ushort messageId) { // read message type @@ -67,8 +113,7 @@ public static bool UnpackId(NetworkReader reader, out ushort messageId) // version for handlers with channelId // inline! only exists for 20-30 messages and they call it all the time. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static NetworkMessageDelegate WrapHandler(Action handler, bool requireAuthentication) + internal static NetworkMessageDelegate WrapHandler(Action handler, bool requireAuthentication, bool exceptionsDisconnect) where T : struct, NetworkMessage where C : NetworkConnection => (conn, reader, channelId) => @@ -93,7 +138,7 @@ internal static NetworkMessageDelegate WrapHandler(Action handl if (requireAuthentication && !conn.isAuthenticated) { // message requires authentication, but the connection was not authenticated - Debug.LogWarning($"Closing connection: {conn}. Received message {typeof(T)} that required authentication, but the user has not authenticated yet"); + Debug.LogWarning($"Disconnecting connection: {conn}. Received message {typeof(T)} that required authentication, but the user has not authenticated yet"); conn.Disconnect(); return; } @@ -106,9 +151,19 @@ internal static NetworkMessageDelegate WrapHandler(Action handl } catch (Exception exception) { - Debug.LogError($"Closed connection: {conn}. This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: {exception}"); - conn.Disconnect(); - return; + // should we disconnect on exceptions? + if (exceptionsDisconnect) + { + Debug.LogError($"Disconnecting connection: {conn} because reading a message of type {typeof(T)} caused an Exception. This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: {exception}"); + conn.Disconnect(); + return; + } + // otherwise log it but allow the connection to keep playing + else + { + Debug.LogError($"Caught an Exception when reading a message from: {conn} of type {typeof(T)}. Reason: {exception}"); + return; + } } finally { @@ -123,10 +178,19 @@ internal static NetworkMessageDelegate WrapHandler(Action handl // user implemented handler handler((C)conn, message, channelId); } - catch (Exception e) + catch (Exception exception) { - Debug.LogError($"Disconnecting connId={conn.connectionId} to prevent exploits from an Exception in MessageHandler: {e.GetType().Name} {e.Message}\n{e.StackTrace}"); - conn.Disconnect(); + // should we disconnect on exceptions? + if (exceptionsDisconnect) + { + Debug.LogError($"Disconnecting connection: {conn} because handling a message of type {typeof(T)} caused an Exception. This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: {exception}"); + conn.Disconnect(); + } + // otherwise log it but allow the connection to keep playing + else + { + Debug.LogError($"Caught an Exception when handling a message from: {conn} of type {typeof(T)}. Reason: {exception}"); + } } }; @@ -134,13 +198,13 @@ internal static NetworkMessageDelegate WrapHandler(Action handl // TODO obsolete this some day to always use the channelId version. // all handlers in this version are wrapped with 1 extra action. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static NetworkMessageDelegate WrapHandler(Action handler, bool requireAuthentication) + internal static NetworkMessageDelegate WrapHandler(Action handler, bool requireAuthentication, bool exceptionsDisconnect) where T : struct, NetworkMessage where C : NetworkConnection { // wrap action as channelId version, call original void Wrapped(C conn, T msg, int _) => handler(conn, msg); - return WrapHandler((Action)Wrapped, requireAuthentication); + return WrapHandler((Action)Wrapped, requireAuthentication, exceptionsDisconnect); } } } diff --git a/Assets/Mirror/Core/NetworkReader.cs b/Assets/Mirror/Core/NetworkReader.cs index bec63ce..82fb7cd 100644 --- a/Assets/Mirror/Core/NetworkReader.cs +++ b/Assets/Mirror/Core/NetworkReader.cs @@ -45,6 +45,18 @@ public class NetworkReader // this is safer. see test: ReadString_InvalidUTF8(). internal readonly UTF8Encoding encoding = new UTF8Encoding(false, true); + // while allocation free ReadArraySegment is encouraged, + // some functions can allocate a new byte[], List, Texture, etc. + // we should keep a reasonable allocation size limit: + // -> server won't accidentally allocate 2GB on a mobile device + // -> client won't allocate 2GB on server for ClientToServer [SyncVar]s + // -> unlike max string length of 64 KB, we need a larger limit here. + // large enough to not break existing projects, + // small enough to reasonably limit allocation attacks. + // -> we don't know the exact size of ReadList etc. because is + // managed. instead, this is considered a 'collection length' limit. + public const int AllocationLimit = 1024 * 1024 * 16; // 16 MB * sizeof(T) + public NetworkReader(ArraySegment segment) { buffer = segment; @@ -105,7 +117,6 @@ public void SetBuffer(byte[] bytes) // // Note: inlining ReadBlittable is enough. don't inline ReadInt etc. // we don't want ReadBlittable to be copied in place everywhere. - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal unsafe T ReadBlittable() where T : unmanaged { @@ -212,7 +223,6 @@ public ArraySegment ReadBytesSegment(int count) } /// Reads any data type that mirror supports. Uses weaver populated Reader(T).read - [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Read() { Func readerDelegate = Reader.read; diff --git a/Assets/Mirror/Core/NetworkReaderExtensions.cs b/Assets/Mirror/Core/NetworkReaderExtensions.cs index 8c340f0..4493be3 100644 --- a/Assets/Mirror/Core/NetworkReaderExtensions.cs +++ b/Assets/Mirror/Core/NetworkReaderExtensions.cs @@ -64,13 +64,11 @@ public static string ReadString(this NetworkReader reader) if (size == 0) return null; - int realSize = size - 1; + ushort realSize = (ushort)(size - 1); // make sure it's within limits to avoid allocation attacks etc. - if (realSize >= NetworkWriter.MaxStringLength) - { - throw new EndOfStreamException($"ReadString too long: {realSize}. Limit is: {NetworkWriter.MaxStringLength}"); - } + if (realSize > NetworkWriter.MaxStringLength) + throw new EndOfStreamException($"NetworkReader.ReadString - Value too long: {realSize} bytes. Limit is: {NetworkWriter.MaxStringLength} bytes"); ArraySegment data = reader.ReadBytesSegment(realSize); @@ -80,6 +78,22 @@ public static string ReadString(this NetworkReader reader) return reader.encoding.GetString(data.Array, data.Offset, data.Count); } + public static byte[] ReadBytes(this NetworkReader reader, int count) + { + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + if (count > NetworkReader.AllocationLimit) + { + // throw EndOfStream for consistency with ReadBlittable when out of data + throw new EndOfStreamException($"NetworkReader attempted to allocate {count} bytes, which is larger than the allowed limit of {NetworkReader.AllocationLimit} bytes."); + } + + byte[] bytes = new byte[count]; + reader.ReadBytes(bytes, count); + return bytes; + } + /// if count is invalid public static byte[] ReadBytesAndSize(this NetworkReader reader) { @@ -89,16 +103,9 @@ public static byte[] ReadBytesAndSize(this NetworkReader reader) // Use checked() to force it to throw OverflowException if data is invalid return count == 0 ? null : reader.ReadBytes(checked((int)(count - 1u))); } - - public static byte[] ReadBytes(this NetworkReader reader, int count) - { - byte[] bytes = new byte[count]; - reader.ReadBytes(bytes, count); - return bytes; - } - + // Reads ArraySegment and size header /// if count is invalid - public static ArraySegment ReadBytesAndSizeSegment(this NetworkReader reader) + public static ArraySegment ReadArraySegmentAndSize(this NetworkReader reader) { // count = 0 means the array was null // otherwise count - 1 is the length of the array @@ -131,14 +138,29 @@ public static ArraySegment ReadBytesAndSizeSegment(this NetworkReader read public static Quaternion ReadQuaternion(this NetworkReader reader) => reader.ReadBlittable(); public static Quaternion? ReadQuaternionNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); - public static Rect ReadRect(this NetworkReader reader) => reader.ReadBlittable(); - public static Rect? ReadRectNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + // Rect is a struct with properties instead of fields + public static Rect ReadRect(this NetworkReader reader) => new Rect(reader.ReadVector2(), reader.ReadVector2()); + public static Rect? ReadRectNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRect(reader) : default(Rect?); + + // Plane is a struct with properties instead of fields + public static Plane ReadPlane(this NetworkReader reader) => new Plane(reader.ReadVector3(), reader.ReadFloat()); + public static Plane? ReadPlaneNullable(this NetworkReader reader) => reader.ReadBool() ? ReadPlane(reader) : default(Plane?); - public static Plane ReadPlane(this NetworkReader reader) => reader.ReadBlittable(); - public static Plane? ReadPlaneNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + // Ray is a struct with properties instead of fields + public static Ray ReadRay(this NetworkReader reader) => new Ray(reader.ReadVector3(), reader.ReadVector3()); + public static Ray? ReadRayNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRay(reader) : default(Ray?); - public static Ray ReadRay(this NetworkReader reader) => reader.ReadBlittable(); - public static Ray? ReadRayNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + // LayerMask is a struct with properties instead of fields + public static LayerMask ReadLayerMask(this NetworkReader reader) + { + // LayerMask doesn't have a constructor that takes an initial value. + // 32 layers as a flags enum, max value of 496, we only need a UShort. + LayerMask layerMask = default; + layerMask.value = reader.ReadUShort(); + return layerMask; + } + + public static LayerMask? ReadLayerMaskNullable(this NetworkReader reader) => reader.ReadBool() ? ReadLayerMask(reader) : default(LayerMask?); public static Matrix4x4 ReadMatrix4x4(this NetworkReader reader) => reader.ReadBlittable(); public static Matrix4x4? ReadMatrix4x4Nullable(this NetworkReader reader) => reader.ReadBlittableNullable(); @@ -243,8 +265,19 @@ public static GameObject ReadGameObject(this NetworkReader reader) public static List ReadList(this NetworkReader reader) { int length = reader.ReadInt(); - if (length < 0) - return null; + + // 'null' is encoded as '-1' + if (length < 0) return null; + + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + if (length > NetworkReader.AllocationLimit) + { + // throw EndOfStream for consistency with ReadBlittable when out of data + throw new EndOfStreamException($"NetworkReader attempted to allocate a List<{typeof(T)}> {length} elements, which is larger than the allowed limit of {NetworkReader.AllocationLimit}."); + } + List result = new List(length); for (int i = 0; i < length; i++) { @@ -277,20 +310,22 @@ public static T[] ReadArray(this NetworkReader reader) { int length = reader.ReadInt(); - // we write -1 for null - if (length < 0) - return null; - - // todo throw an exception for other negative values (we never write them, likely to be attacker) + // 'null' is encoded as '-1' + if (length < 0) return null; - // this assumes that a reader for T reads at least 1 bytes - // we can't know the exact size of T because it could have a user created reader - // NOTE: don't add to length as it could overflow if value is int.max - if (length > reader.Remaining) + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + if (length > NetworkReader.AllocationLimit) { - throw new EndOfStreamException($"Received array that is too large: {length}"); + // throw EndOfStream for consistency with ReadBlittable when out of data + throw new EndOfStreamException($"NetworkReader attempted to allocate an Array<{typeof(T)}> with {length} elements, which is larger than the allowed limit of {NetworkReader.AllocationLimit}."); } + // we can't check if reader.Remaining < length, + // because we don't know sizeof(T) since it's a managed type. + // if (length > reader.Remaining) throw new EndOfStreamException($"Received array that is too large: {length}"); + T[] result = new T[length]; for (int i = 0; i < length; i++) { @@ -307,9 +342,6 @@ public static Uri ReadUri(this NetworkReader reader) public static Texture2D ReadTexture2D(this NetworkReader reader) { - // TODO allocation protection when sending textures to server. - // currently can allocate 32k x 32k x 4 byte = 3.8 GB - // support 'null' textures for [SyncVar]s etc. // https://github.com/vis2k/Mirror/issues/3144 short width = reader.ReadShort(); @@ -317,6 +349,19 @@ public static Texture2D ReadTexture2D(this NetworkReader reader) // read height short height = reader.ReadShort(); + + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + // log an error and return default. + // we don't want attackers to be able to trigger exceptions. + int totalSize = width * height; + if (totalSize > NetworkReader.AllocationLimit) + { + Debug.LogWarning($"NetworkReader attempted to allocate a Texture2D with total size (width * height) of {totalSize}, which is larger than the allowed limit of {NetworkReader.AllocationLimit}."); + return null; + } + Texture2D texture2D = new Texture2D(width, height); // read pixel content @@ -336,5 +381,8 @@ public static Sprite ReadSprite(this NetworkReader reader) // otherwise create a valid sprite return Sprite.Create(texture, reader.ReadRect(), reader.ReadVector2()); } + + public static DateTime ReadDateTime(this NetworkReader reader) => DateTime.FromOADate(reader.ReadDouble()); + public static DateTime? ReadDateTimeNullable(this NetworkReader reader) => reader.ReadBool() ? ReadDateTime(reader) : default(DateTime?); } } diff --git a/Assets/Mirror/Core/NetworkReaderPool.cs b/Assets/Mirror/Core/NetworkReaderPool.cs index 15708b7..f44adb8 100644 --- a/Assets/Mirror/Core/NetworkReaderPool.cs +++ b/Assets/Mirror/Core/NetworkReaderPool.cs @@ -17,8 +17,10 @@ public static class NetworkReaderPool 1000 ); + // expose count for testing + public static int Count => Pool.Count; + /// Get the next reader in the pool. If pool is empty, creates a new Reader - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static NetworkReaderPooled Get(byte[] bytes) { // grab from pool & set buffer @@ -28,7 +30,6 @@ public static NetworkReaderPooled Get(byte[] bytes) } /// Get the next reader in the pool. If pool is empty, creates a new Reader - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static NetworkReaderPooled Get(ArraySegment segment) { // grab from pool & set buffer diff --git a/Assets/Mirror/Core/NetworkServer.cs b/Assets/Mirror/Core/NetworkServer.cs index 8784fa2..51cc4ca 100644 --- a/Assets/Mirror/Core/NetworkServer.cs +++ b/Assets/Mirror/Core/NetworkServer.cs @@ -6,6 +6,16 @@ namespace Mirror { + public enum RemovePlayerOptions + { + /// Player Object remains active on server and clients. Only ownership is removed + KeepActive, + /// Player Object is unspawned on clients but remains on server + Unspawn, + /// Player Object is destroyed on server and clients + Destroy + } + /// NetworkServer handles remote connections and has a local connection for a local client. public static partial class NetworkServer { @@ -14,7 +24,7 @@ public static partial class NetworkServer /// Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE. // overwritten by NetworkManager (if any) - public static int tickRate = 30; + public static int tickRate = 60; // tick rate is in Hz. // convert to interval in seconds for convenience where needed. @@ -52,10 +62,6 @@ public static partial class NetworkServer // see also: https://github.com/vis2k/Mirror/pull/2595 public static bool dontListen; - // Deprecated 2022-12-12 - [Obsolete("NetworkServer.localClientActive was renamed to .activeHost to be more obvious")] - public static bool localClientActive => activeHost; - /// active checks if the server has been started either has standalone or as host server. public static bool active { get; internal set; } @@ -68,7 +74,22 @@ public static partial class NetworkServer // interest management component (optional) // by default, everyone observes everyone - public static InterestManagement aoi; + public static InterestManagementBase aoi; + + // For security, it is recommended to disconnect a player if a networked + // action triggers an exception\nThis could prevent components being + // accessed in an undefined state, which may be an attack vector for + // exploits. + // + // However, some games may want to allow exceptions in order to not + // interrupt the player's experience. + public static bool exceptionsDisconnect = true; // security by default + + // Mirror global disconnect inactive option, independent of Transport. + // not all Transports do this properly, and it's easiest to configure this just once. + // this is very useful for some projects, keep it. + public static bool disconnectInactiveConnections; + public static float disconnectInactiveTimeout = 60; // OnConnected / OnDisconnected used to be NetworkMessages that were // invoked. this introduced a bug where external clients could send @@ -78,6 +99,7 @@ public static partial class NetworkServer public static Action OnConnectedEvent; public static Action OnDisconnectedEvent; public static Action OnErrorEvent; + public static Action OnTransportExceptionEvent; // keep track of actual achieved tick rate. // might become lower under heavy load. @@ -106,7 +128,22 @@ public static void Listen(int maxConns) if (!dontListen) { Transport.active.ServerStart(); - //Debug.Log("Server started listening"); + + if (Transport.active is PortTransport portTransport) + { + if (Utils.IsHeadless()) + { +#if !UNITY_EDITOR + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"Server listening on port {portTransport.Port}"); + Console.ResetColor(); +#else + Debug.Log($"Server listening on port {portTransport.Port}"); +#endif + } + } + else + Debug.Log("Server started listening"); } active = true; @@ -119,6 +156,15 @@ static void Initialize() if (initialized) return; + // safety: ensure Weaving succeded. + // if it silently failed, we would get lots of 'writer not found' + // and other random errors at runtime instead. this is cleaner. + if (!WeaverFuse.Weaved()) + { + // if it failed, throw an exception to early exit all Listen calls. + throw new Exception("NetworkServer won't start because Weaving failed or didn't run."); + } + // Debug.Log($"NetworkServer Created version {Version.Current}"); //Make sure connections are cleared in case any old connections references exist from previous sessions @@ -126,7 +172,7 @@ static void Initialize() // reset Interest Management so that rebuild intervals // start at 0 when starting again. - if (aoi != null) aoi.Reset(); + if (aoi != null) aoi.ResetState(); // reset NetworkTime NetworkTime.ResetStatics(); @@ -149,6 +195,7 @@ static void AddTransportHandlers() Transport.active.OnServerDataReceived += OnTransportData; Transport.active.OnServerDisconnected += OnTransportDisconnected; Transport.active.OnServerError += OnTransportError; + Transport.active.OnServerTransportException += OnTransportException; } /// Shuts down the server and disconnects all clients @@ -189,7 +236,6 @@ public static void Shutdown() connections.Clear(); connectionsCopy.Clear(); handlers.Clear(); - newObservers.Clear(); // destroy all spawned objects, _then_ set inactive. // make sure .active is still true before calling this. @@ -209,8 +255,9 @@ public static void Shutdown() OnConnectedEvent = null; OnDisconnectedEvent = null; OnErrorEvent = null; + OnTransportExceptionEvent = null; - if (aoi != null) aoi.Reset(); + if (aoi != null) aoi.ResetState(); } static void RemoveTransportHandlers() @@ -232,21 +279,8 @@ static void CleanupSpawned() { if (identity != null) { - // scene object - if (identity.sceneId != 0) - { - // spawned scene objects are unspawned and reset. - // afterwards we disable them again. - // (they always stay in the scene, we don't destroy them) - DestroyObject(identity, DestroyMode.Reset); - identity.gameObject.SetActive(false); - } - // spawned prefabs - else - { - // spawned prefabs are unspawned and destroyed. - DestroyObject(identity, DestroyMode.Destroy); - } + // NetworkServer.Destroy resets if scene object, destroys if prefab. + Destroy(identity.gameObject); } } @@ -258,6 +292,7 @@ internal static void RegisterMessageHandlers() RegisterHandler(OnClientReadyMessage); RegisterHandler(OnCommandMessage); RegisterHandler(NetworkTime.OnServerPing, false); + RegisterHandler(NetworkTime.OnServerPong, false); RegisterHandler(OnEntityStateMessage, true); RegisterHandler(OnTimeSnapshotMessage, true); } @@ -280,7 +315,18 @@ static void OnCommandMessage(NetworkConnectionToClient conn, CommandMessage msg, // Ignore commands that may have been in flight before client received NotReadyMessage message. // Unreliable messages may be out of order, so don't spam warnings for those. if (channelId == Channels.Reliable) + { + // Attempt to identify the target object, component, and method to narrow down the cause of the error. + if (spawned.TryGetValue(msg.netId, out NetworkIdentity netIdentity)) + if (msg.componentIndex < netIdentity.NetworkBehaviours.Length && netIdentity.NetworkBehaviours[msg.componentIndex] is NetworkBehaviour component) + if (RemoteProcedureCalls.GetFunctionMethodName(msg.functionHash, out string methodName)) + { + Debug.LogWarning($"Command {methodName} received for {netIdentity.name} [netId={msg.netId}] component {component.name} [index={msg.componentIndex}] when client not ready.\nThis may be ignored if client intentionally set NotReady."); + return; + } + Debug.LogWarning("Command received while client is not ready.\nThis may be ignored if client intentionally set NotReady."); + } return; } @@ -291,7 +337,7 @@ static void OnCommandMessage(NetworkConnectionToClient conn, CommandMessage msg, // for example, NetworkTransform. // let's not spam the console for unreliable out of order messages. if (channelId == Channels.Reliable) - Debug.LogWarning($"Spawned object not found when handling Command message [netId={msg.netId}]"); + Debug.LogWarning($"Spawned object not found when handling Command message netId={msg.netId}"); return; } @@ -301,7 +347,15 @@ static void OnCommandMessage(NetworkConnectionToClient conn, CommandMessage msg, bool requiresAuthority = RemoteProcedureCalls.CommandRequiresAuthority(msg.functionHash); if (requiresAuthority && identity.connectionToClient != conn) { - Debug.LogWarning($"Command for object without authority [netId={msg.netId}]"); + // Attempt to identify the component and method to narrow down the cause of the error. + if (msg.componentIndex < identity.NetworkBehaviours.Length && identity.NetworkBehaviours[msg.componentIndex] is NetworkBehaviour component) + if (RemoteProcedureCalls.GetFunctionMethodName(msg.functionHash, out string methodName)) + { + Debug.LogWarning($"Command {methodName} received for {identity.name} [netId={msg.netId}] component {component.name} [index={msg.componentIndex}] without authority"); + return; + } + + Debug.LogWarning($"Command received for {identity.name} [netId={msg.netId}] without authority"); return; } @@ -330,17 +384,22 @@ static void OnEntityStateMessage(NetworkConnectionToClient connection, EntitySta // failure to deserialize disconnects to prevent exploits. if (!identity.DeserializeServer(reader)) { - Debug.LogWarning($"Server failed to deserialize client state for {identity.name} with netId={identity.netId}, Disconnecting."); - connection.Disconnect(); + if (exceptionsDisconnect) + { + Debug.LogError($"Server failed to deserialize client state for {identity.name} with netId={identity.netId}, Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"Server failed to deserialize client state for {identity.name} with netId={identity.netId}."); } } } - // an attacker may attempt to modify another connection's entity + // An attacker may attempt to modify another connection's entity + // This could also be a race condition of message in flight when + // RemoveClientAuthority is called, so not malicious. + // Don't disconnect, just log the warning. else - { - Debug.LogWarning($"Connection {connection.connectionId} attempted to modify {identity} which is not owned by the connection. Disconnecting the connection."); - connection.Disconnect(); - } + Debug.LogWarning($"EntityStateMessage from {connection} for {identity.name} without authority."); } // no warning. don't spam server logs. // else Debug.LogWarning($"Did not find target for sync message for {message.netId} . Note: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message."); @@ -360,12 +419,12 @@ static void OnTimeSnapshotMessage(NetworkConnectionToClient connection, TimeSnap // maybe we shouldn't allow timeline to deviate more than a certain %. // for now, this is only used for client authority movement. -#if !UNITY_2020_3_OR_NEWER // Unity 2019 doesn't have Time.timeAsDouble yet + // + // NetworkTime uses unscaled time and ignores Time.timeScale. + // fixes Time.timeScale getting server & client time out of sync: + // https://github.com/MirrorNetworking/Mirror/issues/3409 connection.OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, NetworkTime.localTime)); -#else - connection.OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, Time.timeAsDouble)); -#endif } // connections ///////////////////////////////////////////////////////// @@ -445,6 +504,18 @@ public static void SendToAll(T message, int channelId = Channels.Reliable, bo NetworkMessages.Pack(message, writer); ArraySegment segment = writer.ToArraySegment(); + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkServer.SendToAll: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + // filter and then send to all internet connections at once // -> makes code more complicated, but is HIGHLY worth it to // avoid allocations, allow for multicast, etc. @@ -491,6 +562,18 @@ static void SendToObservers(NetworkIdentity identity, T message, int channelI NetworkMessages.Pack(message, writer); ArraySegment segment = writer.ToArraySegment(); + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkServer.SendToObservers: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + foreach (NetworkConnectionToClient conn in identity.observers.Values) { conn.Send(segment, channelId); @@ -515,6 +598,18 @@ public static void SendToReadyObservers(NetworkIdentity identity, T message, NetworkMessages.Pack(message, writer); ArraySegment segment = writer.ToArraySegment(); + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkServer.SendToReadyObservers: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + int count = 0; foreach (NetworkConnectionToClient conn in identity.observers.Values) { @@ -635,8 +730,14 @@ internal static void OnTransportData(int connectionId, ArraySegment data, // always process all messages in the batch. if (!connection.unbatcher.AddBatch(data)) { - Debug.LogWarning($"NetworkServer: received Message was too short (messages should start with message id)"); - connection.Disconnect(); + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id). Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id)."); + return; } @@ -651,38 +752,52 @@ internal static void OnTransportData(int connectionId, ArraySegment data, // the next time. // => consider moving processing to NetworkEarlyUpdate. while (!isLoadingScene && - connection.unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimestamp)) + connection.unbatcher.GetNextMessage(out ArraySegment message, out double remoteTimestamp)) { - // enough to read at least header size? - if (reader.Remaining >= NetworkMessages.IdSize) + using (NetworkReaderPooled reader = NetworkReaderPool.Get(message)) { - // make remoteTimeStamp available to the user - connection.remoteTimeStamp = remoteTimestamp; - - // handle message - if (!UnpackAndInvoke(connection, reader, channelId)) + // enough to read at least header size? + if (reader.Remaining >= NetworkMessages.IdSize) { - // warn, disconnect and return if failed - // -> warning because attackers might send random data - // -> messages in a batch aren't length prefixed. - // failing to read one would cause undefined - // behaviour for every message afterwards. - // so we need to disconnect. - // -> return to avoid the below unbatches.count error. - // we already disconnected and handled it. - Debug.LogWarning($"NetworkServer: failed to unpack and invoke message. Disconnecting {connectionId}."); - connection.Disconnect(); + // make remoteTimeStamp available to the user + connection.remoteTimeStamp = remoteTimestamp; + + // handle message + if (!UnpackAndInvoke(connection, reader, channelId)) + { + // warn, disconnect and return if failed + // -> warning because attackers might send random data + // -> messages in a batch aren't length prefixed. + // failing to read one would cause undefined + // behaviour for every message afterwards. + // so we need to disconnect. + // -> return to avoid the below unbatches.count error. + // we already disconnected and handled it. + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkServer: failed to unpack and invoke message. Disconnecting {connectionId}."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkServer: failed to unpack and invoke message from connectionId:{connectionId}."); + + return; + } + } + // otherwise disconnect + else + { + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id). Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id)."); + return; } } - // otherwise disconnect - else - { - // WARNING, not error. can happen if attacker sends random data. - Debug.LogWarning($"NetworkServer: received Message was too short (messages should start with message id). Disconnecting {connectionId}"); - connection.Disconnect(); - return; - } } // if we weren't interrupted by a scene change, @@ -719,6 +834,7 @@ internal static void OnTransportDisconnected(int connectionId) // Debug.Log($"Server disconnect client:{connectionId}"); if (connections.TryGetValue(connectionId, out NetworkConnectionToClient conn)) { + conn.Cleanup(); RemoveConnection(connectionId); // Debug.Log($"Server lost client:{connectionId}"); @@ -748,6 +864,17 @@ static void OnTransportError(int connectionId, TransportError error, string reas OnErrorEvent?.Invoke(conn, error, reason); } + // transport errors are forwarded to high level + static void OnTransportException(int connectionId, Exception exception) + { + // transport errors will happen. logging a warning is enough. + // make sure the user does not panic. + Debug.LogWarning($"Server Transport Exception for connId={connectionId}: {exception}"); + // try get connection. passes null otherwise. + connections.TryGetValue(connectionId, out NetworkConnectionToClient conn); + OnTransportExceptionEvent?.Invoke(conn, exception); + } + /// Destroys all of the connection's owned objects on the server. // This is used when a client disconnects, to remove the players for // that client. This also destroys non-player objects that have client @@ -772,12 +899,16 @@ public static void DestroyPlayerForConnection(NetworkConnectionToClient conn) public static void RegisterHandler(Action handler, bool requireAuthentication = true) where T : struct, NetworkMessage { - ushort msgType = NetworkMessages.GetId(); + ushort msgType = NetworkMessageId.Id; if (handlers.ContainsKey(msgType)) { Debug.LogWarning($"NetworkServer.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); } - handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication); + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); } /// Register a handler for message type T. Most should require authentication. @@ -785,12 +916,16 @@ public static void RegisterHandler(Action handl public static void RegisterHandler(Action handler, bool requireAuthentication = true) where T : struct, NetworkMessage { - ushort msgType = NetworkMessages.GetId(); + ushort msgType = NetworkMessageId.Id; if (handlers.ContainsKey(msgType)) { Debug.LogWarning($"NetworkServer.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); } - handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication); + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); } /// Replace a handler for message type T. Most should require authentication. @@ -804,15 +939,31 @@ public static void ReplaceHandler(Action handler, bool requireAuthenticati public static void ReplaceHandler(Action handler, bool requireAuthentication = true) where T : struct, NetworkMessage { - ushort msgType = NetworkMessages.GetId(); - handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication); + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); + } + + /// Replace a handler for message type T. Most should require authentication. + public static void ReplaceHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); } /// Unregister a handler for a message type T. public static void UnregisterHandler() where T : struct, NetworkMessage { - ushort msgType = NetworkMessages.GetId(); + ushort msgType = NetworkMessageId.Id; handlers.Remove(msgType); } @@ -900,7 +1051,7 @@ public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameOb { if (!player.TryGetComponent(out NetworkIdentity identity)) { - Debug.LogWarning($"AddPlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}"); + Debug.LogWarning($"AddPlayer: player GameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}"); return false; } @@ -1008,18 +1159,37 @@ public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, Ga /// Removes the player object from the connection // destroyServerObject: Indicates whether the server object should be destroyed - public static void RemovePlayerForConnection(NetworkConnection conn, bool destroyServerObject) + // Deprecated 2024-06-06 + [Obsolete("Use RemovePlayerForConnection(NetworkConnectionToClient conn, RemovePlayerOptions removeOptions) instead")] + public static void RemovePlayerForConnection(NetworkConnectionToClient conn, bool destroyServerObject) { - if (conn.identity != null) + if (destroyServerObject) + RemovePlayerForConnection(conn, RemovePlayerOptions.Destroy); + else + RemovePlayerForConnection(conn, RemovePlayerOptions.Unspawn); + } + + /// Removes player object for the connection. Options to keep the object in play, unspawn it, or destroy it. + public static void RemovePlayerForConnection(NetworkConnectionToClient conn, RemovePlayerOptions removeOptions = RemovePlayerOptions.KeepActive) + { + if (conn.identity == null) return; + + switch (removeOptions) { - if (destroyServerObject) - Destroy(conn.identity.gameObject); - else + case RemovePlayerOptions.KeepActive: + conn.identity.connectionToClient = null; + conn.owned.Remove(conn.identity); + SendChangeOwnerMessage(conn.identity, conn); + break; + case RemovePlayerOptions.Unspawn: UnSpawn(conn.identity.gameObject); - - conn.identity = null; + break; + case RemovePlayerOptions.Destroy: + Destroy(conn.identity.gameObject); + break; } - //else Debug.Log($"Connection {conn} has no identity"); + + conn.identity = null; } // ready /////////////////////////////////////////////////////////////// @@ -1075,17 +1245,17 @@ static void SpawnObserversForConnection(NetworkConnectionToClient conn) // first! // ForceShown: add no matter what - if (identity.visible == Visibility.ForceShown) + if (identity.visibility == Visibility.ForceShown) { identity.AddObserver(conn); } // ForceHidden: don't show no matter what - else if (identity.visible == Visibility.ForceHidden) + else if (identity.visibility == Visibility.ForceHidden) { // do nothing } // default: legacy system / new system / no system support - else if (identity.visible == Visibility.Default) + else if (identity.visibility == Visibility.Default) { // aoi system if (aoi != null) @@ -1216,7 +1386,7 @@ internal static void SendChangeOwnerMessage(NetworkIdentity identity, NetworkCon { netId = identity.netId, isOwner = identity.connectionToClient == conn, - isLocalPlayer = conn.identity == identity + isLocalPlayer = (conn.identity == identity && identity.connectionToClient == conn) }); } @@ -1369,7 +1539,7 @@ static void SpawnObject(GameObject obj, NetworkConnection ownerConnection) // https://github.com/MirrorNetworking/Mirror/pull/3205 if (spawned.ContainsKey(identity.netId)) { - Debug.LogWarning($"{identity} with netId={identity.netId} was already spawned.", identity.gameObject); + Debug.LogWarning($"{identity.name} [netId={identity.netId}] was already spawned.", identity.gameObject); return; } @@ -1380,6 +1550,10 @@ static void SpawnObject(GameObject obj, NetworkConnection ownerConnection) if (ownerConnection is LocalConnectionToClient) identity.isOwned = true; + // NetworkServer.Unspawn sets object as inactive. + // NetworkServer.Spawn needs to set them active again in case they were previously unspawned / inactive. + identity.gameObject.SetActive(true); + // only call OnStartServer if not spawned yet. // check used to be in NetworkIdentity. may not be necessary anymore. if (!identity.isServer && identity.netId == 0) @@ -1425,37 +1599,28 @@ static void SpawnObject(GameObject obj, NetworkConnection ownerConnection) // Unlike when calling NetworkServer.Destroy(), on the server the object // will NOT be destroyed. This allows the server to re-use the object, // even spawn it again later. - public static void UnSpawn(GameObject obj) => DestroyObject(obj, DestroyMode.Reset); - - // destroy ///////////////////////////////////////////////////////////// - // sometimes we want to GameObject.Destroy it. - // sometimes we want to just unspawn on clients and .Reset() it on server. - // => 'bool destroy' isn't obvious enough. it's really destroy OR reset! - enum DestroyMode { Destroy, Reset } + public static void UnSpawn(GameObject obj) + { + // Debug.Log($"DestroyObject instance:{identity.netId}"); - /// Destroys this object and corresponding objects on all clients. - // In some cases it is useful to remove an object but not delete it on - // the server. For that, use NetworkServer.UnSpawn() instead of - // NetworkServer.Destroy(). - public static void Destroy(GameObject obj) => DestroyObject(obj, DestroyMode.Destroy); + // NetworkServer.Unspawn should only be called on server or host. + // on client, show a warning to explain what it does. + if (!active) + { + Debug.LogWarning("NetworkServer.Unspawn() called without an active server. Servers can only destroy while active, clients can only ask the server to destroy (for example, with a [Command]), after which the server may decide to destroy the object and broadcast the change to all clients."); + return; + } - static void DestroyObject(GameObject obj, DestroyMode mode) - { if (obj == null) { - Debug.Log("NetworkServer DestroyObject is null"); + Debug.Log("NetworkServer.Unspawn(): object is null"); return; } - if (GetNetworkIdentity(obj, out NetworkIdentity identity)) + if (!GetNetworkIdentity(obj, out NetworkIdentity identity)) { - DestroyObject(identity, mode); + return; } - } - - static void DestroyObject(NetworkIdentity identity, DestroyMode mode) - { - // Debug.Log($"DestroyObject instance:{identity.netId}"); // only call OnRebuildObservers while active, // not while shutting down @@ -1507,38 +1672,62 @@ static void DestroyObject(NetworkIdentity identity, DestroyMode mode) // we are on the server. call OnStopServer. identity.OnStopServer(); - // are we supposed to GameObject.Destroy() it completely? - if (mode == DestroyMode.Destroy) + // finally reset the state and deactivate it + identity.ResetState(); + identity.gameObject.SetActive(false); + } + + // destroy ///////////////////////////////////////////////////////////// + /// Destroys this object and corresponding objects on all clients. + // In some cases it is useful to remove an object but not delete it on + // the server. For that, use NetworkServer.UnSpawn() instead of + // NetworkServer.Destroy(). + public static void Destroy(GameObject obj) + { + // NetworkServer.Destroy should only be called on server or host. + // on client, show a warning to explain what it does. + if (!active) + { + Debug.LogWarning("NetworkServer.Destroy() called without an active server. Servers can only destroy while active, clients can only ask the server to destroy (for example, with a [Command]), after which the server may decide to destroy the object and broadcast the change to all clients."); + return; + } + + if (obj == null) + { + Debug.Log("NetworkServer.Destroy(): object is null"); + return; + } + + // first, we unspawn it on clients and server + UnSpawn(obj); + + // additionally, if it's a prefab then we destroy it completely. + // we never destroy scene objects on server or on client, since once + // they are gone, they are gone forever and can't be instantiate again. + // for example, server may Destroy() a scene object and once a match + // restarts, the scene objects would be gone from the new match. + if (GetNetworkIdentity(obj, out NetworkIdentity identity) && + identity.sceneId == 0) { identity.destroyCalled = true; // Destroy if application is running if (Application.isPlaying) { - UnityEngine.Object.Destroy(identity.gameObject); + UnityEngine.Object.Destroy(obj); } // Destroy can't be used in Editor during tests. use DestroyImmediate. else { - GameObject.DestroyImmediate(identity.gameObject); + GameObject.DestroyImmediate(obj); } } - // otherwise simply .Reset() and set inactive again - else if (mode == DestroyMode.Reset) - { - identity.Reset(); - } } // interest management ///////////////////////////////////////////////// // Helper function to add all server connections as observers. // This is used if none of the components provides their own // OnRebuildObservers function. - // allocate newObservers helper HashSet only once - // internal for tests - internal static readonly HashSet newObservers = - new HashSet(); - // rebuild observers default method (no AOI) - adds all connections static void RebuildObserversDefault(NetworkIdentity identity, bool initialize) { @@ -1547,10 +1736,15 @@ static void RebuildObserversDefault(NetworkIdentity identity, bool initialize) if (initialize) { // not force hidden? - if (identity.visible != Visibility.ForceHidden) + if (identity.visibility != Visibility.ForceHidden) { AddAllReadyServerConnectionsToObservers(identity); } + else if (identity.connectionToClient != null) + { + // force hidden, but add owner connection + identity.AddObserver(identity.connectionToClient); + } } } @@ -1590,113 +1784,17 @@ public static void RebuildObservers(NetworkIdentity identity, bool initialize) { // if there is no interest management system, // or if 'force shown' then add all connections - if (aoi == null || identity.visible == Visibility.ForceShown) + if (aoi == null || identity.visibility == Visibility.ForceShown) { RebuildObserversDefault(identity, initialize); } // otherwise let interest management system rebuild else { - RebuildObserversCustom(identity, initialize); + aoi.Rebuild(identity, initialize); } } - // rebuild observers via interest management system - static void RebuildObserversCustom(NetworkIdentity identity, bool initialize) - { - // clear newObservers hashset before using it - newObservers.Clear(); - - // not force hidden? - if (identity.visible != Visibility.ForceHidden) - { - aoi.OnRebuildObservers(identity, newObservers); - } - - // IMPORTANT: AFTER rebuilding add own player connection in any case - // to ensure player always sees himself no matter what. - // -> OnRebuildObservers might clear observers, so we need to add - // the player's own connection AFTER. 100% fail safe. - // -> fixes https://github.com/vis2k/Mirror/issues/692 where a - // player might teleport out of the ProximityChecker's cast, - // losing the own connection as observer. - if (identity.connectionToClient != null) - { - newObservers.Add(identity.connectionToClient); - } - - bool changed = false; - - // add all newObservers that aren't in .observers yet - foreach (NetworkConnectionToClient conn in newObservers) - { - // only add ready connections. - // otherwise the player might not be in the world yet or anymore - if (conn != null && conn.isReady) - { - if (initialize || !identity.observers.ContainsKey(conn.connectionId)) - { - // new observer - conn.AddToObserving(identity); - // Debug.Log($"New Observer for {gameObject} {conn}"); - changed = true; - } - } - } - - // remove all old .observers that aren't in newObservers anymore - foreach (NetworkConnectionToClient conn in identity.observers.Values) - { - if (!newObservers.Contains(conn)) - { - // removed observer - conn.RemoveFromObserving(identity, false); - // Debug.Log($"Removed Observer for {gameObject} {conn}"); - changed = true; - } - } - - // copy new observers to observers - if (changed) - { - identity.observers.Clear(); - foreach (NetworkConnectionToClient conn in newObservers) - { - if (conn != null && conn.isReady) - identity.observers.Add(conn.connectionId, conn); - } - } - - // special case for host mode: we use SetHostVisibility to hide - // NetworkIdentities that aren't in observer range from host. - // this is what games like Dota/Counter-Strike do too, where a host - // does NOT see all players by default. they are in memory, but - // hidden to the host player. - // - // this code is from UNET, it's a bit strange but it works: - // * it hides newly connected identities in host mode - // => that part was the intended behaviour - // * it hides ALL NetworkIdentities in host mode when the host - // connects but hasn't selected a character yet - // => this only works because we have no .localConnection != null - // check. at this stage, localConnection is null because - // StartHost starts the server first, then calls this code, - // then starts the client and sets .localConnection. so we can - // NOT add a null check without breaking host visibility here. - // * it hides ALL NetworkIdentities in server-only mode because - // observers never contain the 'null' .localConnection - // => that was not intended, but let's keep it as it is so we - // don't break anything in host mode. it's way easier than - // iterating all identities in a special function in StartHost. - if (initialize) - { - if (!newObservers.Contains(localConnection)) - { - if (aoi != null) - aoi.SetHostVisibility(identity, false); - } - } - } // broadcasting //////////////////////////////////////////////////////// // helper function to get the right serialization for a connection @@ -1762,6 +1860,21 @@ static void BroadcastToConnection(NetworkConnectionToClient connection) } } + // helper function to check a connection for inactivity and disconnect if necessary + // returns true if disconnected + static bool DisconnectIfInactive(NetworkConnectionToClient connection) + { + // check for inactivity + if (disconnectInactiveConnections && + !connection.IsAlive(disconnectInactiveTimeout)) + { + Debug.LogWarning($"Disconnecting {connection} for inactivity!"); + connection.Disconnect(); + return true; + } + return false; + } + // NetworkLateUpdate called after any Update/FixedUpdate/LateUpdate // (we add this to the UnityEngine in NetworkLoop) // internal for tests @@ -1784,6 +1897,10 @@ static void Broadcast() // go through all connections foreach (NetworkConnectionToClient connection in connectionsCopy) { + // check for inactivity. disconnects if necessary. + if (DisconnectIfInactive(connection)) + continue; + // has this connection joined the world yet? // for each READY connection: // pull in UpdateVarsMessage for each entity it observes @@ -1877,16 +1994,9 @@ internal static void NetworkLateUpdate() // also important for syncInterval=0 components like // NetworkTransform, so they can sync on same interval as time // snapshots _but_ not every single tick. - if (!Application.isPlaying || -#if !UNITY_2020_3_OR_NEWER - // Unity 2019 doesn't have Time.timeAsDouble yet - AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime)) -#else - AccurateInterval.Elapsed(Time.timeAsDouble, sendInterval, ref lastSendTime)) -#endif - { + // Unity 2019 doesn't have Time.timeAsDouble yet + if (!Application.isPlaying || AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime)) Broadcast(); - } } // process all outgoing messages after updating the world @@ -1916,11 +2026,5 @@ internal static void NetworkLateUpdate() fullUpdateDuration.End(); } } - - // calls OnStartClient for all SERVER objects in host mode once. - // client doesn't get spawn messages for those, so need to call manually. - // Deprecated 2022-12-12 - [Obsolete("NetworkServer.ActivateHostScene was moved to HostMode.ActivateHostScene")] - public static void ActivateHostScene() => HostMode.ActivateHostScene(); } } diff --git a/Assets/Mirror/Core/NetworkTime.cs b/Assets/Mirror/Core/NetworkTime.cs index 04edc62..6319970 100644 --- a/Assets/Mirror/Core/NetworkTime.cs +++ b/Assets/Mirror/Core/NetworkTime.cs @@ -4,6 +4,7 @@ // // however, some of the old NetworkTime code remains for ping time (rtt). // some users may still be using that. +using System; using System.Runtime.CompilerServices; using UnityEngine; #if !UNITY_2020_3_OR_NEWER @@ -15,30 +16,38 @@ namespace Mirror /// Synchronizes server time to clients. public static class NetworkTime { - /// Ping message frequency, used to calculate network time and RTT - public static float PingFrequency = 2; + /// Ping message interval, used to calculate latency / RTT and predicted time. + // 2s was enough to get a good average RTT. + // for prediction, we want to react to latency changes more rapidly. + const float DefaultPingInterval = 0.1f; // for resets + public static float PingInterval = DefaultPingInterval; /// Average out the last few results from Ping - public static int PingWindowSize = 10; + // const because it's used immediately in _rtt constructor. + public const int PingWindowSize = 50; // average over 50 * 100ms = 5s static double lastPingTime; - static ExponentialMovingAverage _rtt = new ExponentialMovingAverage(10); + static ExponentialMovingAverage _rtt = new ExponentialMovingAverage(PingWindowSize); /// Returns double precision clock time _in this system_, unaffected by the network. #if UNITY_2020_3_OR_NEWER public static double localTime { + // NetworkTime uses unscaled time and ignores Time.timeScale. + // fixes Time.timeScale getting server & client time out of sync: + // https://github.com/MirrorNetworking/Mirror/issues/3409 [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Time.timeAsDouble; + get => Time.unscaledTimeAsDouble; } #else // need stopwatch for older Unity versions, but it's quite slow. - // CAREFUL: unlike Time.time, this is not a FRAME time. - // it changes during the frame too. + // CAREFUL: unlike Time.time, the stopwatch time is not a FRAME time. + // it changes during the frame, so we have an extra step to "cache" it in EarlyUpdate. static readonly Stopwatch stopwatch = new Stopwatch(); static NetworkTime() => stopwatch.Start(); - public static double localTime => stopwatch.Elapsed.TotalSeconds; + static double localFrameTime; + public static double localTime => localFrameTime; #endif /// The time in seconds since the server started. @@ -61,6 +70,49 @@ public static double time : NetworkClient.localTimeline; } + // prediction ////////////////////////////////////////////////////////// + // NetworkTime.time is server time, behind by bufferTime. + // for prediction, we want server time, ahead by latency. + // so that client inputs at predictedTime=2 arrive on server at time=2. + // the more accurate this is, the more closesly will corrections be + // be applied and the less jitter we will see. + // + // we'll use a two step process to calculate predicted time: + // 1. move snapshot interpolated time to server time, without being behind by bufferTime + // 2. constantly send this time to server (included in ping message) + // server replies with how far off it was. + // client averages that offset and applies it to predictedTime to get ever closer. + // + // this is also very easy to test & verify: + // - add LatencySimulation with 50ms latency + // - log predictionError on server in OnServerPing, see if it gets closer to 0 + // + // credits: FakeByte, imer, NinjaKickja, mischa + // const because it's used immediately in _predictionError constructor. + + static int PredictionErrorWindowSize = 20; // average over 20 * 100ms = 2s + static ExponentialMovingAverage _predictionErrorUnadjusted = new ExponentialMovingAverage(PredictionErrorWindowSize); + public static double predictionErrorUnadjusted => _predictionErrorUnadjusted.Value; + public static double predictionErrorAdjusted { get; private set; } // for debugging + + /// Predicted timeline in order for client inputs to be timestamped with the exact time when they will most likely arrive on the server. This is the basis for all prediction like PredictedRigidbody. + // on client, this is based on localTime (aka Time.time) instead of the snapshot interpolated timeline. + // this gives much better and immediately accurate results. + // -> snapshot interpolation timeline tries to emulate a server timeline without hard offset corrections. + // -> predictedTime does have hard offset corrections, so might as well use Time.time directly for this. + // + // note that predictedTime over unreliable is enough! + // even with reliable components, it gives better results than if we were + // to implemented predictedTime over reliable channel. + public static double predictedTime + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => NetworkServer.active + ? localTime // server always uses it's own timeline + : localTime + predictionErrorUnadjusted; // add the offset that the server told us we are off by + } + //////////////////////////////////////////////////////////////////////// + /// Clock difference in seconds between the client and the server. Always 0 on server. // original implementation used 'client - server' time. keep it this way. // TODO obsolete later. people shouldn't worry about this. @@ -69,12 +121,15 @@ public static double time /// Round trip time (in seconds) that it takes a message to go client->server->client. public static double rtt => _rtt.Value; + /// Round trip time variance aka jitter, in seconds. + // "rttVariance" instead of "rttVar" for consistency with older versions. + public static double rttVariance => _rtt.Variance; + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload [RuntimeInitializeOnLoadMethod] public static void ResetStatics() { - PingFrequency = 2; - PingWindowSize = 10; + PingInterval = DefaultPingInterval; lastPingTime = 0; _rtt = new ExponentialMovingAverage(PingWindowSize); #if !UNITY_2020_3_OR_NEWER @@ -85,36 +140,104 @@ public static void ResetStatics() internal static void UpdateClient() { // localTime (double) instead of Time.time for accuracy over days - if (localTime - lastPingTime >= PingFrequency) - { - NetworkPingMessage pingMessage = new NetworkPingMessage(localTime); - NetworkClient.Send(pingMessage, Channels.Unreliable); - lastPingTime = localTime; - } + if (localTime >= lastPingTime + PingInterval) + SendPing(); } + // Separate method so we can call it from NetworkClient directly. + internal static void SendPing() + { + // send raw predicted time without the offset applied yet. + // we then apply the offset to it after. + NetworkPingMessage pingMessage = new NetworkPingMessage + ( + localTime, + predictedTime + ); + NetworkClient.Send(pingMessage, Channels.Unreliable); + lastPingTime = localTime; + } + + // client rtt calculation ////////////////////////////////////////////// // executed at the server when we receive a ping message // reply with a pong containing the time from the client // and time from the server internal static void OnServerPing(NetworkConnectionToClient conn, NetworkPingMessage message) { - // Debug.Log($"OnPingServerMessage conn:{conn}"); + // calculate the prediction offset that the client needs to apply to unadjusted time to reach server time. + // this will be sent back to client for corrections. + double unadjustedError = localTime - message.localTime; + + // to see how well the client's final prediction worked, compare with adjusted time. + // this is purely for debugging. + // >0 means: server is ... seconds ahead of client's prediction (good if small) + // <0 means: server is ... seconds behind client's prediction. + // in other words, client is predicting too far ahead (not good) + double adjustedError = localTime - message.predictedTimeAdjusted; + // Debug.Log($"[Server] unadjustedError:{(unadjustedError*1000):F1}ms adjustedError:{(adjustedError*1000):F1}ms"); + + // Debug.Log($"OnServerPing conn:{conn}"); NetworkPongMessage pongMessage = new NetworkPongMessage - { - clientTime = message.clientTime, - serverTime = localTime - }; + ( + message.localTime, + unadjustedError, + adjustedError + ); conn.Send(pongMessage, Channels.Unreliable); } // Executed at the client when we receive a Pong message // find out how long it took since we sent the Ping - // and update time offset + // and update time offset & prediction offset. internal static void OnClientPong(NetworkPongMessage message) { + // prevent attackers from sending timestamps which are in the future + if (message.localTime > localTime) return; + // how long did this message take to come back - double newRtt = localTime - message.clientTime; + double newRtt = localTime - message.localTime; _rtt.Add(newRtt); + + // feed unadjusted prediction error into our exponential moving average + // store adjusted prediction error for debug / GUI purposes + _predictionErrorUnadjusted.Add(message.predictionErrorUnadjusted); + predictionErrorAdjusted = message.predictionErrorAdjusted; + // Debug.Log($"[Client] predictionError avg={(_predictionErrorUnadjusted.Value*1000):F1} ms"); + } + + // server rtt calculation ////////////////////////////////////////////// + // Executed at the client when we receive a ping message from the server. + // in other words, this is for server sided ping + rtt calculation. + // reply with a pong containing the time from the server + internal static void OnClientPing(NetworkPingMessage message) + { + // Debug.Log($"OnClientPing conn:{conn}"); + NetworkPongMessage pongMessage = new NetworkPongMessage + ( + message.localTime, + 0, 0 // server doesn't predict + ); + NetworkClient.Send(pongMessage, Channels.Unreliable); + } + + // Executed at the server when we receive a Pong message back. + // find out how long it took since we sent the Ping + // and update time offset + internal static void OnServerPong(NetworkConnectionToClient conn, NetworkPongMessage message) + { + // prevent attackers from sending timestamps which are in the future + if (message.localTime > localTime) return; + + // how long did this message take to come back + double newRtt = localTime - message.localTime; + conn._rtt.Add(newRtt); + } + + internal static void EarlyUpdate() + { +#if !UNITY_2020_3_OR_NEWER + localFrameTime = stopwatch.Elapsed.TotalSeconds; +#endif } } } diff --git a/Assets/Mirror/Core/NetworkWriter.cs b/Assets/Mirror/Core/NetworkWriter.cs index 18bbad6..7ecf126 100644 --- a/Assets/Mirror/Core/NetworkWriter.cs +++ b/Assets/Mirror/Core/NetworkWriter.cs @@ -9,12 +9,14 @@ namespace Mirror /// Network Writer for most simple types like floats, ints, buffers, structs, etc. Use NetworkWriterPool.GetReader() to avoid allocations. public class NetworkWriter { - public const int MaxStringLength = 1024 * 32; - public const int DefaultCapacity = 1500; + // the limit of ushort is so we can write string size prefix as only 2 bytes. + // -1 so we can still encode 'null' into it too. + public const ushort MaxStringLength = ushort.MaxValue - 1; // create writer immediately with it's own buffer so no one can mess with it and so that we can resize it. // note: BinaryWriter allocates too much, so we only use a MemoryStream // => 1500 bytes by default because on average, most packets will be <= MTU + public const int DefaultCapacity = 1500; internal byte[] buffer = new byte[DefaultCapacity]; /// Next position to write to the buffer @@ -57,7 +59,6 @@ internal void EnsureCapacity(int value) /// Copies buffer until 'Position' to a new array. // Try to use ToArraySegment instead to avoid allocations! - [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte[] ToArray() { byte[] data = new byte[Position]; @@ -121,7 +122,6 @@ public static implicit operator ArraySegment(NetworkWriter w) => // // Note: inlining WriteBlittable is enough. don't inline WriteInt etc. // we don't want WriteBlittable to be copied in place everywhere. - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal unsafe void WriteBlittable(T value) where T : unmanaged { @@ -219,7 +219,6 @@ public unsafe bool WriteBytes(byte* ptr, int offset, int size) } /// Writes any type that mirror supports. Uses weaver populated Writer(T).write. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(T value) { Action writeDelegate = Writer.write; diff --git a/Assets/Mirror/Core/NetworkWriterExtensions.cs b/Assets/Mirror/Core/NetworkWriterExtensions.cs index d55a7be..fef9f61 100644 --- a/Assets/Mirror/Core/NetworkWriterExtensions.cs +++ b/Assets/Mirror/Core/NetworkWriterExtensions.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using UnityEngine; namespace Mirror @@ -44,25 +43,7 @@ public static class NetworkWriterExtensions public static void WriteFloat(this NetworkWriter writer, float value) => writer.WriteBlittable(value); public static void WriteFloatNullable(this NetworkWriter writer, float? value) => writer.WriteBlittableNullable(value); - [StructLayout(LayoutKind.Explicit)] - internal struct UIntDouble - { - [FieldOffset(0)] - public double doubleValue; - - [FieldOffset(0)] - public ulong longValue; - } - - public static void WriteDouble(this NetworkWriter writer, double value) - { - // DEBUG: try to find the exact value that fails. - //UIntDouble convert = new UIntDouble{doubleValue = value}; - //Debug.Log($"=> NetworkWriter.WriteDouble: {value} => 0x{convert.longValue:X8}"); - - - writer.WriteBlittable(value); - } + public static void WriteDouble(this NetworkWriter writer, double value) => writer.WriteBlittable(value); public static void WriteDoubleNullable(this NetworkWriter writer, double? value) => writer.WriteBlittableNullable(value); public static void WriteDecimal(this NetworkWriter writer, decimal value) => writer.WriteBlittable(value); @@ -89,9 +70,9 @@ public static void WriteString(this NetworkWriter writer, string value) // reserve 2 bytes for header after we know how much was written. int written = writer.encoding.GetBytes(value, 0, value.Length, writer.buffer, writer.Position + 2); - // check if within max size - if (written >= NetworkWriter.MaxStringLength) - throw new IndexOutOfRangeException($"NetworkWriter.Write(string) too long: {written}. Limit: {NetworkWriter.MaxStringLength}"); + // check if within max size, otherwise Reader can't read it. + if (written > NetworkWriter.MaxStringLength) + throw new IndexOutOfRangeException($"NetworkWriter.WriteString - Value too long: {written} bytes. Limit: {NetworkWriter.MaxStringLength} bytes"); // .Position is unchanged, so fill in the size header now. // we already ensured that max size fits into ushort.max-1. @@ -101,14 +82,8 @@ public static void WriteString(this NetworkWriter writer, string value) writer.Position += written; } - public static void WriteBytesAndSizeSegment(this NetworkWriter writer, ArraySegment buffer) - { - writer.WriteBytesAndSize(buffer.Array, buffer.Offset, buffer.Count); - } - // Weaver needs a write function with just one byte[] parameter // (we don't name it .Write(byte[]) because it's really a WriteBytesAndSize since we write size / null info too) - public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer) { // buffer might be null, so we can't use .Length in that case @@ -117,7 +92,6 @@ public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer) // for byte arrays with dynamic size, where the reader doesn't know how many will come // (like an inventory with different items etc.) - public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer, int offset, int count) { // null is supported because [SyncVar]s might be structs with null byte[] arrays @@ -132,6 +106,13 @@ public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer, i writer.WriteBytes(buffer, offset, count); } + // writes ArraySegment of byte (most common type) and size header + public static void WriteArraySegmentAndSize(this NetworkWriter writer, ArraySegment segment) + { + writer.WriteBytesAndSize(segment.Array, segment.Offset, segment.Count); + } + + // writes ArraySegment of any type, and size header public static void WriteArraySegment(this NetworkWriter writer, ArraySegment segment) { int length = segment.Count; @@ -166,14 +147,57 @@ public static void WriteArraySegment(this NetworkWriter writer, ArraySegment< public static void WriteQuaternion(this NetworkWriter writer, Quaternion value) => writer.WriteBlittable(value); public static void WriteQuaternionNullable(this NetworkWriter writer, Quaternion? value) => writer.WriteBlittableNullable(value); - public static void WriteRect(this NetworkWriter writer, Rect value) => writer.WriteBlittable(value); - public static void WriteRectNullable(this NetworkWriter writer, Rect? value) => writer.WriteBlittableNullable(value); + // Rect is a struct with properties instead of fields + public static void WriteRect(this NetworkWriter writer, Rect value) + { + writer.WriteVector2(value.position); + writer.WriteVector2(value.size); + } + public static void WriteRectNullable(this NetworkWriter writer, Rect? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteRect(value.Value); + } - public static void WritePlane(this NetworkWriter writer, Plane value) => writer.WriteBlittable(value); - public static void WritePlaneNullable(this NetworkWriter writer, Plane? value) => writer.WriteBlittableNullable(value); + // Plane is a struct with properties instead of fields + public static void WritePlane(this NetworkWriter writer, Plane value) + { + writer.WriteVector3(value.normal); + writer.WriteFloat(value.distance); + } + public static void WritePlaneNullable(this NetworkWriter writer, Plane? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WritePlane(value.Value); + } + + // Ray is a struct with properties instead of fields + public static void WriteRay(this NetworkWriter writer, Ray value) + { + writer.WriteVector3(value.origin); + writer.WriteVector3(value.direction); + } + public static void WriteRayNullable(this NetworkWriter writer, Ray? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteRay(value.Value); + } - public static void WriteRay(this NetworkWriter writer, Ray value) => writer.WriteBlittable(value); - public static void WriteRayNullable(this NetworkWriter writer, Ray? value) => writer.WriteBlittableNullable(value); + // LayerMask is a struct with properties instead of fields + public static void WriteLayerMask(this NetworkWriter writer, LayerMask layerMask) + { + // 32 layers as a flags enum, max value of 496, we only need a UShort. + writer.WriteUShort((ushort)layerMask.value); + } + public static void WriteLayerMaskNullable(this NetworkWriter writer, LayerMask? layerMask) + { + writer.WriteBool(layerMask.HasValue); + if (layerMask.HasValue) + writer.WriteLayerMask(layerMask.Value); + } public static void WriteMatrix4x4(this NetworkWriter writer, Matrix4x4 value) => writer.WriteBlittable(value); public static void WriteMatrix4x4Nullable(this NetworkWriter writer, Matrix4x4? value) => writer.WriteBlittableNullable(value); @@ -228,6 +252,22 @@ public static void WriteNetworkBehaviour(this NetworkWriter writer, NetworkBehav writer.WriteUInt(0); return; } + + // users might try to use unspawned / prefab NetworkBehaviours in + // rpcs/cmds/syncvars/messages. they would be null on the other + // end, and it might not be obvious why. let's make it obvious. + // https://github.com/vis2k/Mirror/issues/2060 + // and more recently https://github.com/MirrorNetworking/Mirror/issues/3399 + // + // => warning (instead of exception) because we also use a warning + // when writing an unspawned NetworkIdentity + if (value.netId == 0) + { + Debug.LogWarning($"Attempted to serialize unspawned NetworkBehaviour: of type {value.GetType()} on GameObject {value.name}. Prefabs and unspawned GameObjects would always be null on the other side. Please spawn it before using it in [SyncVar]s/Rpcs/Cmds/NetworkMessages etc."); + writer.WriteUInt(0); + return; + } + writer.WriteUInt(value.netId); writer.WriteByte(value.ComponentIndex); } @@ -245,7 +285,9 @@ public static void WriteTransform(this NetworkWriter writer, Transform value) } else { - Debug.LogWarning($"NetworkWriter {value} has no NetworkIdentity"); + // if users attempt to pass a transform without NetworkIdentity + // to a [Command] or [SyncVar], it should show an obvious warning. + Debug.LogWarning($"Attempted to sync a Transform ({value}) which isn't networked. Transforms without a NetworkIdentity component can't be synced."); writer.WriteUInt(0); } } @@ -260,7 +302,7 @@ public static void WriteGameObject(this NetworkWriter writer, GameObject value) // warn if the GameObject doesn't have a NetworkIdentity, if (!value.TryGetComponent(out NetworkIdentity identity)) - Debug.LogWarning($"NetworkWriter {value} has no NetworkIdentity"); + Debug.LogWarning($"Attempted to sync a GameObject ({value}) which isn't networked. GameObject without a NetworkIdentity component can't be synced."); // serialize the correct amount of data in any case to make sure // that the other end can read the expected amount of data too. @@ -273,11 +315,17 @@ public static void WriteGameObject(this NetworkWriter writer, GameObject value) // note that Weaver/Writers/GenerateWriter() handles this manually. public static void WriteList(this NetworkWriter writer, List list) { + // 'null' is encoded as '-1' if (list is null) { writer.WriteInt(-1); return; } + + // check if within max size, otherwise Reader can't read it. + if (list.Count > NetworkReader.AllocationLimit) + throw new IndexOutOfRangeException($"NetworkWriter.WriteList - List<{typeof(T)}> too big: {list.Count} elements. Limit: {NetworkReader.AllocationLimit}"); + writer.WriteInt(list.Count); for (int i = 0; i < list.Count; i++) writer.Write(list[i]); @@ -304,11 +352,17 @@ public static void WriteHashSet(this NetworkWriter writer, HashSet hashSet public static void WriteArray(this NetworkWriter writer, T[] array) { + // 'null' is encoded as '-1' if (array is null) { writer.WriteInt(-1); return; } + + // check if within max size, otherwise Reader can't read it. + if (array.Length > NetworkReader.AllocationLimit) + throw new IndexOutOfRangeException($"NetworkWriter.WriteArray - Array<{typeof(T)}> too big: {array.Length} elements. Limit: {NetworkReader.AllocationLimit}"); + writer.WriteInt(array.Length); for (int i = 0; i < array.Length; i++) writer.Write(array[i]); @@ -333,6 +387,11 @@ public static void WriteTexture2D(this NetworkWriter writer, Texture2D texture2D return; } + // check if within max size, otherwise Reader can't read it. + int totalSize = texture2D.width * texture2D.height; + if (totalSize > NetworkReader.AllocationLimit) + throw new IndexOutOfRangeException($"NetworkWriter.WriteTexture2D - Texture2D total size (width*height) too big: {totalSize}. Limit: {NetworkReader.AllocationLimit}"); + // write dimensions first so reader can create the texture with size // 32k x 32k short is more than enough writer.WriteShort((short)texture2D.width); @@ -355,5 +414,17 @@ public static void WriteSprite(this NetworkWriter writer, Sprite sprite) writer.WriteRect(sprite.rect); writer.WriteVector2(sprite.pivot); } + + public static void WriteDateTime(this NetworkWriter writer, DateTime dateTime) + { + writer.WriteDouble(dateTime.ToOADate()); + } + + public static void WriteDateTimeNullable(this NetworkWriter writer, DateTime? dateTime) + { + writer.WriteBool(dateTime.HasValue); + if (dateTime.HasValue) + writer.WriteDouble(dateTime.Value.ToOADate()); + } } } diff --git a/Assets/Mirror/Core/NetworkWriterPool.cs b/Assets/Mirror/Core/NetworkWriterPool.cs index 693517f..23f6026 100644 --- a/Assets/Mirror/Core/NetworkWriterPool.cs +++ b/Assets/Mirror/Core/NetworkWriterPool.cs @@ -18,8 +18,10 @@ public static class NetworkWriterPool 1000 ); + // expose count for testing + public static int Count => Pool.Count; + /// Get a writer from the pool. Creates new one if pool is empty. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static NetworkWriterPooled Get() { // grab from pool & reset position diff --git a/Assets/Mirror/Core/PortTransport.cs b/Assets/Mirror/Core/PortTransport.cs new file mode 100644 index 0000000..19a7dfd --- /dev/null +++ b/Assets/Mirror/Core/PortTransport.cs @@ -0,0 +1,13 @@ +// convenience interface for transports which use a port. +// useful for cases where someone wants to 'just set the port' independent of +// which transport it is. +// +// note that not all transports have ports, but most do. + +namespace Mirror +{ + public interface PortTransport + { + ushort Port { get; set; } + } +} diff --git a/Assets/Mirror/Core/PortTransport.cs.meta b/Assets/Mirror/Core/PortTransport.cs.meta new file mode 100644 index 0000000..3f96d30 --- /dev/null +++ b/Assets/Mirror/Core/PortTransport.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7c7c2820d7974cb28c7bfe9aae890a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Prediction.meta b/Assets/Mirror/Core/Prediction.meta new file mode 100644 index 0000000..83fb83b --- /dev/null +++ b/Assets/Mirror/Core/Prediction.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7e8e801f9c7f4b858d9a6c162e64ca84 +timeCreated: 1694005962 \ No newline at end of file diff --git a/Assets/Mirror/Core/Prediction/Prediction.cs b/Assets/Mirror/Core/Prediction/Prediction.cs new file mode 100644 index 0000000..d669945 --- /dev/null +++ b/Assets/Mirror/Core/Prediction/Prediction.cs @@ -0,0 +1,195 @@ +// standalone, easy to test algorithms for prediction +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // prediction may capture Rigidbody3D/2D/etc. state + // have a common interface. + public interface PredictedState + { + double timestamp { get; } + + // use Vector3 for both Rigidbody3D and Rigidbody2D, that's fine + Vector3 position { get; set; } + Vector3 positionDelta { get; set; } + + Quaternion rotation { get; set; } + Quaternion rotationDelta { get; set; } + + Vector3 velocity { get; set; } + Vector3 velocityDelta { get; set; } + + Vector3 angularVelocity { get; set; } + Vector3 angularVelocityDelta { get; set; } + } + + public static class Prediction + { + // get the two states closest to a given timestamp. + // those can be used to interpolate the exact state at that time. + // => RingBuffer: see prediction_ringbuffer_2 branch, but it's slower! + public static bool Sample( + SortedList history, + double timestamp, // current server time + out T before, + out T after, + out int afterIndex, + out double t) // interpolation factor + { + before = default; + after = default; + t = 0; + afterIndex = -1; + + // can't sample an empty history + // interpolation needs at least two entries. + // can't Lerp(A, A, 1.5). dist(A, A) * 1.5 is always 0. + if (history.Count < 2) { + return false; + } + + // older than oldest + if (timestamp < history.Keys[0]) { + return false; + } + + // iterate through the history + // TODO this needs to be faster than O(N) + // search around that area. + // should be O(1) most of the time, unless sampling was off. + int index = 0; // manually count when iterating. easier than for-int loop. + KeyValuePair prev = new KeyValuePair(); + + // SortedList foreach iteration allocates a LOT. use for-int instead. + // foreach (KeyValuePair entry in history) { + for (int i = 0; i < history.Count; ++i) + { + double key = history.Keys[i]; + T value = history.Values[i]; + + // exact match? + if (timestamp == key) + { + before = value; + after = value; + afterIndex = index; + t = Mathd.InverseLerp(key, key, timestamp); + return true; + } + + // did we check beyond timestamp? then return the previous two. + if (key > timestamp) + { + before = prev.Value; + after = value; + afterIndex = index; + t = Mathd.InverseLerp(prev.Key, key, timestamp); + return true; + } + + // remember the last + prev = new KeyValuePair(key, value); + index += 1; + } + + return false; + } + + // inserts a server state into the client's history. + // readjust the deltas of the states after the inserted one. + // returns the corrected final position. + // => RingBuffer: see prediction_ringbuffer_2 branch, but it's slower! + public static T CorrectHistory( + SortedList history, + int stateHistoryLimit, + T corrected, // corrected state with timestamp + T before, // state in history before the correction + T after, // state in history after the correction + int afterIndex) // index of the 'after' value so we don't need to find it again here + where T: PredictedState + { + // respect the limit + // TODO unit test to check if it respects max size + if (history.Count >= stateHistoryLimit) + { + history.RemoveAt(0); + afterIndex -= 1; // we removed the first value so all indices are off by one now + } + + // PERFORMANCE OPTIMIZATION: avoid O(N) insertion, only readjust all values after. + // the end result is the same since after.delta and after.position are both recalculated. + // it's technically not correct if we were to reconstruct final position from 0..after..end but + // we never do, we only ever iterate from after..end! + // + // insert the corrected state into the history, or overwrite if already exists + // SortedList insertions are O(N)! + // history[corrected.timestamp] = corrected; + // afterIndex += 1; // we inserted the corrected value before the previous index + + // the entry behind the inserted one still has the delta from (before, after). + // we need to correct it to (corrected, after). + // + // for example: + // before: (t=1.0, delta=10, position=10) + // after: (t=3.0, delta=20, position=30) + // + // then we insert: + // corrected: (t=2.5, delta=__, position=25) + // + // previous delta was from t=1.0 to t=3.0 => 2.0 + // inserted delta is from t=2.5 to t=3.0 => 0.5 + // multiplier is 0.5 / 2.0 = 0.25 + // multiply 'after.delta(20)' by 0.25 to get the new 'after.delta(5) + // + // so the new history is: + // before: (t=1.0, delta=10, position=10) + // corrected: (t=2.5, delta=__, position=25) + // after: (t=3.0, delta= 5, position=__) + // + // so when we apply the correction, the new after.position would be: + // corrected.position(25) + after.delta(5) = 30 + // + double previousDeltaTime = after.timestamp - before.timestamp; // 3.0 - 1.0 = 2.0 + double correctedDeltaTime = after.timestamp - corrected.timestamp; // 3.0 - 2.5 = 0.5 + + // fix multiplier becoming NaN if previousDeltaTime is 0: + // double multiplier = correctedDeltaTime / previousDeltaTime; + double multiplier = previousDeltaTime != 0 ? correctedDeltaTime / previousDeltaTime : 0; // 0.5 / 2.0 = 0.25 + + // recalculate 'after.delta' with the multiplier + after.positionDelta = Vector3.Lerp(Vector3.zero, after.positionDelta, (float)multiplier); + after.velocityDelta = Vector3.Lerp(Vector3.zero, after.velocityDelta, (float)multiplier); + after.angularVelocityDelta = Vector3.Lerp(Vector3.zero, after.angularVelocityDelta, (float)multiplier); + // Quaternions always need to be normalized in order to be a valid rotation after operations + after.rotationDelta = Quaternion.Slerp(Quaternion.identity, after.rotationDelta, (float)multiplier).normalized; + + // changes aren't saved until we overwrite them in the history + history[after.timestamp] = after; + + // second step: readjust all absolute values by rewinding client's delta moves on top of it. + T last = corrected; + for (int i = afterIndex; i < history.Count; ++i) + { + double key = history.Keys[i]; + T value = history.Values[i]; + + // correct absolute position based on last + delta. + value.position = last.position + value.positionDelta; + value.velocity = last.velocity + value.velocityDelta; + value.angularVelocity = last.angularVelocity + value.angularVelocityDelta; + // Quaternions always need to be normalized in order to be a valid rotation after operations + value.rotation = (value.rotationDelta * last.rotation).normalized; // quaternions add delta by multiplying in this order + + // save the corrected entry into history. + history[key] = value; + + // save last + last = value; + } + + // third step: return the final recomputed state. + return last; + } + } +} diff --git a/Assets/Mirror/Core/Prediction/Prediction.cs.meta b/Assets/Mirror/Core/Prediction/Prediction.cs.meta new file mode 100644 index 0000000..196bd46 --- /dev/null +++ b/Assets/Mirror/Core/Prediction/Prediction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 216d494d910445ea8a7acc7c889212d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/RemoteCalls.cs b/Assets/Mirror/Core/RemoteCalls.cs index ffae3a0..5dbe52f 100644 --- a/Assets/Mirror/Core/RemoteCalls.cs +++ b/Assets/Mirror/Core/RemoteCalls.cs @@ -30,6 +30,8 @@ public bool AreEqual(Type componentType, RemoteCallType remoteCallType, RemoteCa /// Used to help manage remote calls for NetworkBehaviours public static class RemoteProcedureCalls { + public const string InvokeRpcPrefix = "InvokeUserCode_"; + // one lookup for all remote calls. // allows us to easily add more remote call types without duplicating code. // note: do not clear those with [RuntimeInitializeOnLoad] @@ -99,6 +101,17 @@ public static void RegisterRpc(Type componentType, string functionFullName, Remo internal static void RemoveDelegate(ushort hash) => remoteCallDelegates.Remove(hash); + internal static bool GetFunctionMethodName(ushort functionHash, out string methodName) + { + if (remoteCallDelegates.TryGetValue(functionHash, out Invoker invoker)) + { + methodName = invoker.function.GetMethodName().Replace(InvokeRpcPrefix, ""); + return true; + } + methodName = ""; + return false; + } + // note: no need to throw an error if not found. // an attacker might just try to call a cmd with an rpc's hash etc. // returning false is enough. diff --git a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs index d96e10a..2d1a2fc 100644 --- a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs +++ b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs @@ -35,13 +35,13 @@ public static double Timescale( double drift, // how far we are off from bufferTime double catchupSpeed, // in % [0,1] double slowdownSpeed, // in % [0,1] - double catchupNegativeThreshold, // in % of sendInteral (careful, we may run out of snapshots) - double catchupPositiveThreshold) // in % of sendInterval) + double absoluteCatchupNegativeThreshold, // in seconds (careful, we may run out of snapshots) + double absoluteCatchupPositiveThreshold) // in seconds { // if the drift time is too large, it means we are behind more time. // so we need to speed up the timescale. // note the threshold should be sendInterval * catchupThreshold. - if (drift > catchupPositiveThreshold) + if (drift > absoluteCatchupPositiveThreshold) { // localTimeline += 0.001; // too simple, this would ping pong return 1 + catchupSpeed; // n% faster @@ -50,7 +50,7 @@ public static double Timescale( // if the drift time is too small, it means we are ahead of time. // so we need to slow down the timescale. // note the threshold should be sendInterval * catchupThreshold. - if (drift < catchupNegativeThreshold) + if (drift < absoluteCatchupNegativeThreshold) { // localTimeline -= 0.001; // too simple, this would ping pong return 1 - slowdownSpeed; // n% slower @@ -88,12 +88,18 @@ public static double DynamicAdjustment( // extra function so we can use it for both cases: // NetworkClient global timeline insertions & adjustments via Insert. // NetworkBehaviour local insertion without any time adjustments. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool InsertIfNotExists( SortedList buffer, // snapshot buffer + int bufferLimit, // don't grow infinitely T snapshot) // the newly received snapshot where T : Snapshot { + // slow clients may not be able to process incoming snapshots fast enough. + // infinitely growing snapshots would make it even worse. + // for example, run NetworkRigidbodyBenchmark while deep profiling client. + // the client just grows and reallocates the buffer forever. + if (buffer.Count >= bufferLimit) return false; + // SortedList does not allow duplicates. // we don't need to check ContainsKey (which is expensive). // simply add and compare count before/after for the return value. @@ -106,10 +112,37 @@ public static bool InsertIfNotExists( return buffer.Count > before; } + // clamp timeline for cases where it gets too far behind. + // for example, a client app may go into the background and get updated + // with 1hz for a while. by the time it's back it's at least 30 frames + // behind, possibly more if the transport also queues up. In this + // scenario, at 1% catch up it took around 20+ seconds to finally catch + // up. For these kinds of scenarios it will be better to snap / clamp. + // + // to reproduce, try snapshot interpolation demo and press the button to + // simulate the client timeline at multiple seconds behind. it'll take + // a long time to catch up if the timeline is a long time behind. + public static double TimelineClamp( + double localTimeline, + double bufferTime, + double latestRemoteTime) + { + // we want local timeline to always be 'bufferTime' behind remote. + double targetTime = latestRemoteTime - bufferTime; + + // we define a boundary of 'bufferTime' around the target time. + // this is where catchup / slowdown will happen. + // outside of the area, we clamp. + double lowerBound = targetTime - bufferTime; // how far behind we can get + double upperBound = targetTime + bufferTime; // how far ahead we can get + return Mathd.Clamp(localTimeline, lowerBound, upperBound); + } + // call this for every received snapshot. // adds / inserts it to the list & initializes local time if needed. public static void InsertAndAdjust( SortedList buffer, // snapshot buffer + int bufferLimit, // don't grow infinitely T snapshot, // the newly received snapshot ref double localTimeline, // local interpolation time based on server time ref double localTimescale, // timeline multiplier to apply catchup / slowdown over time @@ -141,7 +174,7 @@ public static void InsertAndAdjust( // note that insert may be called twice for the same key. // by default, this would throw. // need to handle it silently. - if (InsertIfNotExists(buffer, snapshot)) + if (InsertIfNotExists(buffer, bufferLimit, snapshot)) { // dynamic buffer adjustment needs delivery interval jitter if (buffer.Count >= 2) @@ -158,7 +191,7 @@ public static void InsertAndAdjust( // // in practice, scramble is rare and won't make much difference double previousLocalTime = buffer.Values[buffer.Count - 2].localTime; - double lastestLocalTime = buffer.Values[buffer.Count - 1].localTime; + double lastestLocalTime = buffer.Values[buffer.Count - 1].localTime; // this is the delivery time since last snapshot double localDeliveryTime = lastestLocalTime - previousLocalTime; @@ -178,7 +211,12 @@ public static void InsertAndAdjust( // snapshots may arrive out of order, we can not use last-timeline. // we need to use the inserted snapshot's time - timeline. double latestRemoteTime = snapshot.remoteTime; - double timeDiff = latestRemoteTime - localTimeline; + + // ensure timeline stays within a reasonable bound behind/ahead. + localTimeline = TimelineClamp(localTimeline, bufferTime, latestRemoteTime); + + // calculate timediff after localTimeline override changes + double timeDiff = latestRemoteTime - localTimeline; // next, calculate average of a few seconds worth of timediffs. // this gives smoother results. @@ -196,6 +234,11 @@ public static void InsertAndAdjust( // than we sould have access to in our buffer :) driftEma.Add(timeDiff); + // timescale depends on driftEma. + // driftEma only changes when inserting. + // therefore timescale only needs to be calculated when inserting. + // saves CPU cycles in Update. + // next up, calculate how far we are currently away from bufferTime double drift = driftEma.Value - bufferTime; @@ -235,7 +278,7 @@ public static void Sample( for (int i = 0; i < buffer.Count - 1; ++i) { // is local time between these two? - T first = buffer.Values[i]; + T first = buffer.Values[i]; T second = buffer.Values[i + 1]; if (localTimeline >= first.remoteTime && localTimeline <= second.remoteTime) @@ -308,7 +351,7 @@ public static void StepInterpolation( // save from/to fromSnapshot = buffer.Values[from]; - toSnapshot = buffer.Values[to]; + toSnapshot = buffer.Values[to]; // remove older snapshots that we definitely don't need anymore. // after(!) using the indices. diff --git a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs new file mode 100644 index 0000000..74feae4 --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs @@ -0,0 +1,70 @@ +// snapshot interpolation settings struct. +// can easily be exposed in Unity inspectors. +using System; +using UnityEngine; + +namespace Mirror +{ + // class so we can define defaults easily + [Serializable] + public class SnapshotInterpolationSettings + { + // decrease bufferTime at runtime to see the catchup effect. + // increase to see slowdown. + // 'double' so we can have very precise dynamic adjustment without rounding + [Header("Buffering")] + [Tooltip("Local simulation is behind by sendInterval * multiplier seconds.\n\nThis guarantees that we always have enough snapshots in the buffer to mitigate lags & jitter.\n\nIncrease this if the simulation isn't smooth. By default, it should be around 2.")] + public double bufferTimeMultiplier = 2; + + [Tooltip("If a client can't process snapshots fast enough, don't store too many.")] + public int bufferLimit = 32; + + // catchup ///////////////////////////////////////////////////////////// + // catchup thresholds in 'frames'. + // half a frame might be too aggressive. + [Header("Catchup / Slowdown")] + [Tooltip("Slowdown begins when the local timeline is moving too fast towards remote time. Threshold is in frames worth of snapshots.\n\nThis needs to be negative.\n\nDon't modify unless you know what you are doing.")] + public float catchupNegativeThreshold = -1; // careful, don't want to run out of snapshots + + [Tooltip("Catchup begins when the local timeline is moving too slow and getting too far away from remote time. Threshold is in frames worth of snapshots.\n\nThis needs to be positive.\n\nDon't modify unless you know what you are doing.")] + public float catchupPositiveThreshold = 1; + + [Tooltip("Local timeline acceleration in % while catching up.")] + [Range(0, 1)] + public double catchupSpeed = 0.02f; // see snap interp demo. 1% is too slow. + + [Tooltip("Local timeline slowdown in % while slowing down.")] + [Range(0, 1)] + public double slowdownSpeed = 0.04f; // slow down a little faster so we don't encounter empty buffer (= jitter) + + [Tooltip("Catchup/Slowdown is adjusted over n-second exponential moving average.")] + public int driftEmaDuration = 1; // shouldn't need to modify this, but expose it anyway + + // dynamic buffer time adjustment ////////////////////////////////////// + // dynamically adjusts bufferTimeMultiplier for smooth results. + // to understand how this works, try this manually: + // + // - disable dynamic adjustment + // - set jitter = 0.2 (20% is a lot!) + // - notice some stuttering + // - disable interpolation to see just how much jitter this really is(!) + // - enable interpolation again + // - manually increase bufferTimeMultiplier to 3-4 + // ... the cube slows down (blue) until it's smooth + // - with dynamic adjustment enabled, it will set 4 automatically + // ... the cube slows down (blue) until it's smooth as well + // + // note that 20% jitter is extreme. + // for this to be perfectly smooth, set the safety tolerance to '2'. + // but realistically this is not necessary, and '1' is enough. + [Header("Dynamic Adjustment")] + [Tooltip("Automatically adjust bufferTimeMultiplier for smooth results.\nSets a low multiplier on stable connections, and a high multiplier on jittery connections.")] + public bool dynamicAdjustment = true; + + [Tooltip("Safety buffer that is always added to the dynamic bufferTimeMultiplier adjustment.")] + public float dynamicAdjustmentTolerance = 1; // 1 is realistically just fine, 2 is very very safe even for 20% jitter. can be half a frame too. (see above comments) + + [Tooltip("Dynamic adjustment is computed over n-second exponential moving average standard deviation.")] + public int deliveryTimeEmaDuration = 2; // 1-2s recommended to capture average delivery time + } +} diff --git a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta new file mode 100644 index 0000000..5cc16e4 --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f955b76b7956417088c03992b3622dc9 +timeCreated: 1678507210 \ No newline at end of file diff --git a/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta b/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta index 72fd450..5e37981 100644 --- a/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta +++ b/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta @@ -1,3 +1,11 @@ fileFormatVersion: 2 guid: afe2b5ed49634971a2aec720ad74e5cd -timeCreated: 1666288442 \ No newline at end of file +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/SyncDictionary.cs b/Assets/Mirror/Core/SyncDictionary.cs index fc404d8..3cf73f5 100644 --- a/Assets/Mirror/Core/SyncDictionary.cs +++ b/Assets/Mirror/Core/SyncDictionary.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; @@ -5,13 +6,39 @@ namespace Mirror { public class SyncIDictionary : SyncObject, IDictionary, IReadOnlyDictionary { - public delegate void SyncDictionaryChanged(Operation op, TKey key, TValue item); + /// This is called after the item is added with TKey + public Action OnAdd; + + /// This is called after the item is changed with TKey. TValue is the OLD item + public Action OnSet; + + /// This is called after the item is removed with TKey. TValue is the OLD item + public Action OnRemove; + + /// + /// This is called for all changes to the Dictionary. + /// For OP_ADD, TValue is the NEW value of the entry. + /// For OP_SET and OP_REMOVE, TValue is the OLD value of the entry. + /// For OP_CLEAR, both TKey and TValue are default. + /// + public Action OnChange; + + /// This is called before the data is cleared + public Action OnClear; + + // Deprecated 2024-03-22 + [Obsolete("Use individual Actions, which pass OLD values where appropriate, instead.")] + public Action Callback; protected readonly IDictionary objects; + public SyncIDictionary(IDictionary objects) + { + this.objects = objects; + } + public int Count => objects.Count; public bool IsReadOnly => !IsWritable(); - public event SyncDictionaryChanged Callback; public enum Operation : byte { @@ -30,7 +57,7 @@ struct Change // list of changes. // -> insert/delete/clear is only ONE change - // -> changing the same slot 10x caues 10 changes. + // -> changing the same slot 10x causes 10 changes. // -> note that this grows until next sync(!) // TODO Dictionary to avoid ever growing changes / redundant changes! readonly List changes = new List(); @@ -41,13 +68,6 @@ struct Change // so we need to skip them int changesAhead; - public override void Reset() - { - changes.Clear(); - changesAhead = 0; - objects.Clear(); - } - public ICollection Keys => objects.Keys; public ICollection Values => objects.Values; @@ -56,38 +76,6 @@ public override void Reset() IEnumerable IReadOnlyDictionary.Values => objects.Values; - // throw away all the changes - // this should be called after a successful sync - public override void ClearChanges() => changes.Clear(); - - public SyncIDictionary(IDictionary objects) - { - this.objects = objects; - } - - void AddOperation(Operation op, TKey key, TValue item, bool checkAccess) - { - if (checkAccess && IsReadOnly) - { - throw new System.InvalidOperationException("SyncDictionaries can only be modified by the owner."); - } - - Change change = new Change - { - operation = op, - key = key, - item = item - }; - - if (IsRecording()) - { - changes.Add(change); - OnDirty?.Invoke(); - } - - Callback?.Invoke(op, key, item); - } - public override void OnSerializeAll(NetworkWriter writer) { // if init, write the full list content @@ -119,11 +107,13 @@ public override void OnSerializeDelta(NetworkWriter writer) switch (change.operation) { case Operation.OP_ADD: - case Operation.OP_REMOVE: case Operation.OP_SET: writer.Write(change.key); writer.Write(change.item); break; + case Operation.OP_REMOVE: + writer.Write(change.key); + break; case Operation.OP_CLEAR: break; } @@ -177,15 +167,15 @@ public override void OnDeserializeDelta(NetworkReader reader) // ClientToServer needs to set dirty in server OnDeserialize. // no access check: server OnDeserialize can always // write, even for ClientToServer (for broadcasting). - if (ContainsKey(key)) + if (objects.TryGetValue(key, out TValue oldItem)) { - objects[key] = item; // assign after ContainsKey check - AddOperation(Operation.OP_SET, key, item, false); + objects[key] = item; // assign after TryGetValue + AddOperation(Operation.OP_SET, key, item, oldItem, false); } else { - objects[key] = item; // assign after ContainsKey check - AddOperation(Operation.OP_ADD, key, item, false); + objects[key] = item; // assign after TryGetValue + AddOperation(Operation.OP_ADD, key, item, default, false); } } break; @@ -193,27 +183,29 @@ public override void OnDeserializeDelta(NetworkReader reader) case Operation.OP_CLEAR: if (apply) { - objects.Clear(); // add dirty + changes. // ClientToServer needs to set dirty in server OnDeserialize. // no access check: server OnDeserialize can always // write, even for ClientToServer (for broadcasting). - AddOperation(Operation.OP_CLEAR, default, default, false); + AddOperation(Operation.OP_CLEAR, default, default, default, false); + // clear after invoking the callback so users can iterate the dictionary + // and take appropriate action on the items before they are wiped. + objects.Clear(); } break; case Operation.OP_REMOVE: key = reader.Read(); - item = reader.Read(); if (apply) { - if (objects.Remove(key)) + if (objects.TryGetValue(key, out TValue oldItem)) { // add dirty + changes. // ClientToServer needs to set dirty in server OnDeserialize. // no access check: server OnDeserialize can always // write, even for ClientToServer (for broadcasting). - AddOperation(Operation.OP_REMOVE, key, item, false); + objects.Remove(key); + AddOperation(Operation.OP_REMOVE, key, oldItem, oldItem, false); } } break; @@ -227,22 +219,15 @@ public override void OnDeserializeDelta(NetworkReader reader) } } - public void Clear() - { - objects.Clear(); - AddOperation(Operation.OP_CLEAR, default, default, true); - } - - public bool ContainsKey(TKey key) => objects.ContainsKey(key); + // throw away all the changes + // this should be called after a successful sync + public override void ClearChanges() => changes.Clear(); - public bool Remove(TKey key) + public override void Reset() { - if (objects.TryGetValue(key, out TValue item) && objects.Remove(key)) - { - AddOperation(Operation.OP_REMOVE, key, item, true); - return true; - } - return false; + changes.Clear(); + changesAhead = 0; + objects.Clear(); } public TValue this[TKey i] @@ -252,42 +237,31 @@ public TValue this[TKey i] { if (ContainsKey(i)) { + TValue oldItem = objects[i]; objects[i] = value; - AddOperation(Operation.OP_SET, i, value, true); + AddOperation(Operation.OP_SET, i, value, oldItem, true); } else { objects[i] = value; - AddOperation(Operation.OP_ADD, i, value, true); + AddOperation(Operation.OP_ADD, i, value, default, true); } } } public bool TryGetValue(TKey key, out TValue value) => objects.TryGetValue(key, out value); - public void Add(TKey key, TValue value) - { - objects.Add(key, value); - AddOperation(Operation.OP_ADD, key, value, true); - } - - public void Add(KeyValuePair item) => Add(item.Key, item.Value); + public bool ContainsKey(TKey key) => objects.ContainsKey(key); - public bool Contains(KeyValuePair item) - { - return TryGetValue(item.Key, out TValue val) && EqualityComparer.Default.Equals(val, item.Value); - } + public bool Contains(KeyValuePair item) => TryGetValue(item.Key, out TValue val) && EqualityComparer.Default.Equals(val, item.Value); public void CopyTo(KeyValuePair[] array, int arrayIndex) { if (arrayIndex < 0 || arrayIndex > array.Length) - { throw new System.ArgumentOutOfRangeException(nameof(arrayIndex), "Array Index Out of Range"); - } + if (array.Length - arrayIndex < Count) - { throw new System.ArgumentException("The number of items in the SyncDictionary is greater than the available space from arrayIndex to the end of the destination array"); - } int i = arrayIndex; foreach (KeyValuePair item in objects) @@ -297,14 +271,82 @@ public void CopyTo(KeyValuePair[] array, int arrayIndex) } } + public void Add(KeyValuePair item) => Add(item.Key, item.Value); + + public void Add(TKey key, TValue value) + { + objects.Add(key, value); + AddOperation(Operation.OP_ADD, key, value, default, true); + } + + public bool Remove(TKey key) + { + if (objects.TryGetValue(key, out TValue oldItem) && objects.Remove(key)) + { + AddOperation(Operation.OP_REMOVE, key, oldItem, oldItem, true); + return true; + } + return false; + } + public bool Remove(KeyValuePair item) { bool result = objects.Remove(item.Key); if (result) + AddOperation(Operation.OP_REMOVE, item.Key, item.Value, item.Value, true); + + return result; + } + + public void Clear() + { + AddOperation(Operation.OP_CLEAR, default, default, default, true); + // clear after invoking the callback so users can iterate the dictionary + // and take appropriate action on the items before they are wiped. + objects.Clear(); + } + + void AddOperation(Operation op, TKey key, TValue item, TValue oldItem, bool checkAccess) + { + if (checkAccess && IsReadOnly) + throw new InvalidOperationException("SyncDictionaries can only be modified by the owner."); + + Change change = new Change + { + operation = op, + key = key, + item = item + }; + + if (IsRecording()) { - AddOperation(Operation.OP_REMOVE, item.Key, item.Value, true); + changes.Add(change); + OnDirty?.Invoke(); } - return result; + + switch (op) + { + case Operation.OP_ADD: + OnAdd?.Invoke(key); + OnChange?.Invoke(op, key, item); + break; + case Operation.OP_SET: + OnSet?.Invoke(key, oldItem); + OnChange?.Invoke(op, key, oldItem); + break; + case Operation.OP_REMOVE: + OnRemove?.Invoke(key, oldItem); + OnChange?.Invoke(op, key, oldItem); + break; + case Operation.OP_CLEAR: + OnClear?.Invoke(); + OnChange?.Invoke(op, default, default); + break; + } + +#pragma warning disable CS0618 // Type or member is obsolete + Callback?.Invoke(op, key, item); +#pragma warning restore CS0618 // Type or member is obsolete } public IEnumerator> GetEnumerator() => objects.GetEnumerator(); @@ -314,9 +356,9 @@ public bool Remove(KeyValuePair item) public class SyncDictionary : SyncIDictionary { - public SyncDictionary() : base(new Dictionary()) {} - public SyncDictionary(IEqualityComparer eq) : base(new Dictionary(eq)) {} - public SyncDictionary(IDictionary d) : base(new Dictionary(d)) {} + public SyncDictionary() : base(new Dictionary()) { } + public SyncDictionary(IEqualityComparer eq) : base(new Dictionary(eq)) { } + public SyncDictionary(IDictionary d) : base(new Dictionary(d)) { } public new Dictionary.ValueCollection Values => ((Dictionary)objects).Values; public new Dictionary.KeyCollection Keys => ((Dictionary)objects).Keys; public new Dictionary.Enumerator GetEnumerator() => ((Dictionary)objects).GetEnumerator(); diff --git a/Assets/Mirror/Core/SyncList.cs b/Assets/Mirror/Core/SyncList.cs index 8b70eed..6f4952e 100644 --- a/Assets/Mirror/Core/SyncList.cs +++ b/Assets/Mirror/Core/SyncList.cs @@ -6,24 +6,48 @@ namespace Mirror { public class SyncList : SyncObject, IList, IReadOnlyList { - public delegate void SyncListChanged(Operation op, int itemIndex, T oldItem, T newItem); - - readonly IList objects; - readonly IEqualityComparer comparer; - - public int Count => objects.Count; - public bool IsReadOnly => !IsWritable(); - public event SyncListChanged Callback; - public enum Operation : byte { OP_ADD, - OP_CLEAR, + OP_SET, OP_INSERT, OP_REMOVEAT, - OP_SET + OP_CLEAR } + /// This is called after the item is added with index + public Action OnAdd; + + /// This is called after the item is inserted with inedx + public Action OnInsert; + + /// This is called after the item is set with index and OLD Value + public Action OnSet; + + /// This is called after the item is removed with index and OLD Value + public Action OnRemove; + + /// + /// This is called for all changes to the List. + /// For OP_ADD and OP_INSERT, T is the NEW value of the entry. + /// For OP_SET and OP_REMOVE, T is the OLD value of the entry. + /// For OP_CLEAR, T is default. + /// + public Action OnChange; + + /// This is called before the list is cleared so the list can be iterated + public Action OnClear; + + // Deprecated 2024-03-23 + [Obsolete("Use individual Actions, which pass OLD values where appropriate, instead.")] + public Action Callback; + + readonly IList objects; + readonly IEqualityComparer comparer; + + public int Count => objects.Count; + public bool IsReadOnly => !IsWritable(); + struct Change { internal Operation operation; @@ -43,7 +67,7 @@ struct Change // so we need to skip them int changesAhead; - public SyncList() : this(EqualityComparer.Default) {} + public SyncList() : this(EqualityComparer.Default) { } public SyncList(IEqualityComparer comparer) { @@ -71,9 +95,7 @@ public override void Reset() void AddOperation(Operation op, int itemIndex, T oldItem, T newItem, bool checkAccess) { if (checkAccess && IsReadOnly) - { throw new InvalidOperationException("Synclists can only be modified by the owner."); - } Change change = new Change { @@ -88,7 +110,33 @@ void AddOperation(Operation op, int itemIndex, T oldItem, T newItem, bool checkA OnDirty?.Invoke(); } + switch (op) + { + case Operation.OP_ADD: + OnAdd?.Invoke(itemIndex); + OnChange?.Invoke(op, itemIndex, newItem); + break; + case Operation.OP_INSERT: + OnInsert?.Invoke(itemIndex); + OnChange?.Invoke(op, itemIndex, newItem); + break; + case Operation.OP_SET: + OnSet?.Invoke(itemIndex, oldItem); + OnChange?.Invoke(op, itemIndex, oldItem); + break; + case Operation.OP_REMOVEAT: + OnRemove?.Invoke(itemIndex, oldItem); + OnChange?.Invoke(op, itemIndex, oldItem); + break; + case Operation.OP_CLEAR: + OnClear?.Invoke(); + OnChange?.Invoke(op, itemIndex, default); + break; + } + +#pragma warning disable CS0618 // Type or member is obsolete Callback?.Invoke(op, itemIndex, oldItem, newItem); +#pragma warning restore CS0618 // Type or member is obsolete } public override void OnSerializeAll(NetworkWriter writer) @@ -195,12 +243,14 @@ public override void OnDeserializeDelta(NetworkReader reader) case Operation.OP_CLEAR: if (apply) { - objects.Clear(); // add dirty + changes. // ClientToServer needs to set dirty in server OnDeserialize. // no access check: server OnDeserialize can always // write, even for ClientToServer (for broadcasting). AddOperation(Operation.OP_CLEAR, 0, default, default, false); + // clear after invoking the callback so users can iterate the list + // and take appropriate action on the items before they are wiped. + objects.Clear(); } break; @@ -265,15 +315,15 @@ public void Add(T item) public void AddRange(IEnumerable range) { foreach (T entry in range) - { Add(entry); - } } public void Clear() { - objects.Clear(); AddOperation(Operation.OP_CLEAR, 0, default, default, true); + // clear after invoking the callback so users can iterate the list + // and take appropriate action on the items before they are wiped. + objects.Clear(); } public bool Contains(T item) => IndexOf(item) >= 0; @@ -331,9 +381,8 @@ public bool Remove(T item) int index = IndexOf(item); bool result = index >= 0; if (result) - { RemoveAt(index); - } + return result; } @@ -352,9 +401,7 @@ public int RemoveAll(Predicate match) toRemove.Add(objects[i]); foreach (T entry in toRemove) - { Remove(entry); - } return toRemove.Count; } @@ -393,6 +440,7 @@ public struct Enumerator : IEnumerator { readonly SyncList list; int index; + public T Current { get; private set; } public Enumerator(SyncList list) @@ -405,16 +453,15 @@ public Enumerator(SyncList list) public bool MoveNext() { if (++index >= list.Count) - { return false; - } + Current = list[index]; return true; } public void Reset() => index = -1; object IEnumerator.Current => Current; - public void Dispose() {} + public void Dispose() { } } } } diff --git a/Assets/Mirror/Core/SyncSet.cs b/Assets/Mirror/Core/SyncSet.cs index 13d4302..3d19b0e 100644 --- a/Assets/Mirror/Core/SyncSet.cs +++ b/Assets/Mirror/Core/SyncSet.cs @@ -6,19 +6,37 @@ namespace Mirror { public class SyncSet : SyncObject, ISet { - public delegate void SyncSetChanged(Operation op, T item); + /// This is called after the item is added. T is the new item. + public Action OnAdd; + + /// This is called after the item is removed. T is the OLD item + public Action OnRemove; + + /// + /// This is called for all changes to the Set. + /// For OP_ADD, T is the NEW value of the entry. + /// For OP_REMOVE, T is the OLD value of the entry. + /// For OP_CLEAR, T is default. + /// + public Action OnChange; + + /// This is called BEFORE the data is cleared + public Action OnClear; + + // Deprecated 2024-03-22 + [Obsolete("Use individual Actions, which pass OLD value where appropriate, instead.")] + public Action Callback; protected readonly ISet objects; public int Count => objects.Count; public bool IsReadOnly => !IsWritable(); - public event SyncSetChanged Callback; public enum Operation : byte { OP_ADD, - OP_CLEAR, - OP_REMOVE + OP_REMOVE, + OP_CLEAR } struct Change @@ -56,18 +74,36 @@ public override void Reset() // this should be called after a successful sync public override void ClearChanges() => changes.Clear(); - void AddOperation(Operation op, T item, bool checkAccess) + void AddOperation(Operation op, T oldItem, T newItem, bool checkAccess) { if (checkAccess && IsReadOnly) - { throw new InvalidOperationException("SyncSets can only be modified by the owner."); - } - Change change = new Change + Change change = default; + switch (op) { - operation = op, - item = item - }; + case Operation.OP_ADD: + change = new Change + { + operation = op, + item = newItem + }; + break; + case Operation.OP_REMOVE: + change = new Change + { + operation = op, + item = oldItem + }; + break; + case Operation.OP_CLEAR: + change = new Change + { + operation = op, + item = default + }; + break; + } if (IsRecording()) { @@ -75,10 +111,33 @@ void AddOperation(Operation op, T item, bool checkAccess) OnDirty?.Invoke(); } - Callback?.Invoke(op, item); + switch (op) + { + case Operation.OP_ADD: + OnAdd?.Invoke(newItem); + OnChange?.Invoke(op, newItem); +#pragma warning disable CS0618 // Type or member is obsolete + Callback?.Invoke(op, newItem); +#pragma warning restore CS0618 // Type or member is obsolete + break; + case Operation.OP_REMOVE: + OnRemove?.Invoke(oldItem); + OnChange?.Invoke(op, oldItem); +#pragma warning disable CS0618 // Type or member is obsolete + Callback?.Invoke(op, oldItem); +#pragma warning restore CS0618 // Type or member is obsolete + break; + case Operation.OP_CLEAR: + OnClear?.Invoke(); + OnChange?.Invoke(op, default); +#pragma warning disable CS0618 // Type or member is obsolete + Callback?.Invoke(op, default); +#pragma warning restore CS0618 // Type or member is obsolete + break; + } } - void AddOperation(Operation op, bool checkAccess) => AddOperation(op, default, checkAccess); + void AddOperation(Operation op, bool checkAccess) => AddOperation(op, default, default, checkAccess); public override void OnSerializeAll(NetworkWriter writer) { @@ -86,9 +145,7 @@ public override void OnSerializeAll(NetworkWriter writer) writer.WriteUInt((uint)objects.Count); foreach (T obj in objects) - { writer.Write(obj); - } // all changes have been applied already // thus the client will need to skip all the pending changes @@ -112,13 +169,11 @@ public override void OnSerializeDelta(NetworkWriter writer) case Operation.OP_ADD: writer.Write(change.item); break; - - case Operation.OP_CLEAR: - break; - case Operation.OP_REMOVE: writer.Write(change.item); break; + case Operation.OP_CLEAR: + break; } } } @@ -154,45 +209,48 @@ public override void OnDeserializeDelta(NetworkReader reader) // apply the operation only if it is a new change // that we have not applied yet bool apply = changesAhead == 0; - T item = default; + T oldItem = default; + T newItem = default; switch (operation) { case Operation.OP_ADD: - item = reader.Read(); + newItem = reader.Read(); if (apply) { - objects.Add(item); + objects.Add(newItem); // add dirty + changes. // ClientToServer needs to set dirty in server OnDeserialize. // no access check: server OnDeserialize can always // write, even for ClientToServer (for broadcasting). - AddOperation(Operation.OP_ADD, item, false); + AddOperation(Operation.OP_ADD, default, newItem, false); } break; - case Operation.OP_CLEAR: + case Operation.OP_REMOVE: + oldItem = reader.Read(); if (apply) { - objects.Clear(); + objects.Remove(oldItem); // add dirty + changes. // ClientToServer needs to set dirty in server OnDeserialize. // no access check: server OnDeserialize can always // write, even for ClientToServer (for broadcasting). - AddOperation(Operation.OP_CLEAR, false); + AddOperation(Operation.OP_REMOVE, oldItem, default, false); } break; - case Operation.OP_REMOVE: - item = reader.Read(); + case Operation.OP_CLEAR: if (apply) { - objects.Remove(item); // add dirty + changes. // ClientToServer needs to set dirty in server OnDeserialize. // no access check: server OnDeserialize can always // write, even for ClientToServer (for broadcasting). - AddOperation(Operation.OP_REMOVE, item, false); + AddOperation(Operation.OP_CLEAR, false); + // clear after invoking the callback so users can iterate the set + // and take appropriate action on the items before they are wiped. + objects.Clear(); } break; } @@ -209,7 +267,7 @@ public bool Add(T item) { if (objects.Add(item)) { - AddOperation(Operation.OP_ADD, item, true); + AddOperation(Operation.OP_ADD, default, item, true); return true; } return false; @@ -218,15 +276,15 @@ public bool Add(T item) void ICollection.Add(T item) { if (objects.Add(item)) - { - AddOperation(Operation.OP_ADD, item, true); - } + AddOperation(Operation.OP_ADD, default, item, true); } public void Clear() { - objects.Clear(); AddOperation(Operation.OP_CLEAR, true); + // clear after invoking the callback so users can iterate the set + // and take appropriate action on the items before they are wiped. + objects.Clear(); } public bool Contains(T item) => objects.Contains(item); @@ -237,7 +295,7 @@ public bool Remove(T item) { if (objects.Remove(item)) { - AddOperation(Operation.OP_REMOVE, item, true); + AddOperation(Operation.OP_REMOVE, item, default, true); return true; } return false; @@ -257,17 +315,13 @@ public void ExceptWith(IEnumerable other) // remove every element in other from this foreach (T element in other) - { Remove(element); - } } public void IntersectWith(IEnumerable other) { if (other is ISet otherSet) - { IntersectWithSet(otherSet); - } else { HashSet otherAsSet = new HashSet(other); @@ -280,12 +334,8 @@ void IntersectWithSet(ISet otherSet) List elements = new List(objects); foreach (T element in elements) - { if (!otherSet.Contains(element)) - { Remove(element); - } - } } public bool IsProperSubsetOf(IEnumerable other) => objects.IsProperSubsetOf(other); @@ -304,38 +354,26 @@ void IntersectWithSet(ISet otherSet) public void SymmetricExceptWith(IEnumerable other) { if (other == this) - { Clear(); - } else - { foreach (T element in other) - { if (!Remove(element)) - { Add(element); - } - } - } } // custom implementation so we can do our own Clear/Add/Remove for delta public void UnionWith(IEnumerable other) { if (other != this) - { foreach (T element in other) - { Add(element); - } - } } } public class SyncHashSet : SyncSet { - public SyncHashSet() : this(EqualityComparer.Default) {} - public SyncHashSet(IEqualityComparer comparer) : base(new HashSet(comparer ?? EqualityComparer.Default)) {} + public SyncHashSet() : this(EqualityComparer.Default) { } + public SyncHashSet(IEqualityComparer comparer) : base(new HashSet(comparer ?? EqualityComparer.Default)) { } // allocation free enumerator public new HashSet.Enumerator GetEnumerator() => ((HashSet)objects).GetEnumerator(); @@ -343,8 +381,8 @@ public SyncHashSet(IEqualityComparer comparer) : base(new HashSet(comparer public class SyncSortedSet : SyncSet { - public SyncSortedSet() : this(Comparer.Default) {} - public SyncSortedSet(IComparer comparer) : base(new SortedSet(comparer ?? Comparer.Default)) {} + public SyncSortedSet() : this(Comparer.Default) { } + public SyncSortedSet(IComparer comparer) : base(new SortedSet(comparer ?? Comparer.Default)) { } // allocation free enumerator public new SortedSet.Enumerator GetEnumerator() => ((SortedSet)objects).GetEnumerator(); diff --git a/Assets/Mirror/Editor/Empty.meta b/Assets/Mirror/Core/Threading.meta similarity index 77% rename from Assets/Mirror/Editor/Empty.meta rename to Assets/Mirror/Core/Threading.meta index ee87976..037993e 100644 --- a/Assets/Mirror/Editor/Empty.meta +++ b/Assets/Mirror/Core/Threading.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 62c8dc5bb12bbc6428bb66ccbac57000 +guid: 752fcafbee1ec45c9a43c0cf65da39de folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs new file mode 100644 index 0000000..c0bc926 --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs @@ -0,0 +1,45 @@ +// API consistent with Microsoft's ObjectPool. +// thread safe. +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public static class ConcurrentNetworkWriterPool + { + // initial capacity to avoid allocations in the first few frames + // 1000 * 1200 bytes = around 1 MB. + public const int InitialCapacity = 1000; + + + // reuse ConcurrentPool + // we still wrap it in NetworkWriterPool.Get/Recycle so we can reset the + // position before reusing. + // this is also more consistent with NetworkReaderPool where we need to + // assign the internal buffer before reusing. + static readonly ConcurrentPool pool = + new ConcurrentPool( + // new object function + () => new ConcurrentNetworkWriterPooled(), + // initial capacity to avoid allocations in the first few frames + // 1000 * 1200 bytes = around 1 MB. + InitialCapacity + ); + + // pool size access for debugging & tests + public static int Count => pool.Count; + + public static ConcurrentNetworkWriterPooled Get() + { + // grab from pool & reset position + ConcurrentNetworkWriterPooled writer = pool.Get(); + writer.Position = 0; + return writer; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Return(ConcurrentNetworkWriterPooled writer) + { + pool.Return(writer); + } + } +} diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta new file mode 100644 index 0000000..e973dad --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fdf46e334f52400c854c9732f6fcf005 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs new file mode 100644 index 0000000..ccb1e47 --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs @@ -0,0 +1,11 @@ +using System; + +namespace Mirror +{ + /// Pooled (not threadsafe) NetworkWriter used from Concurrent pool (thread safe). Automatically returned to concurrent pool when using 'using' + // TODO make sealed again after removing obsolete NetworkWriterPooled! + public class ConcurrentNetworkWriterPooled : NetworkWriter, IDisposable + { + public void Dispose() => ConcurrentNetworkWriterPool.Return(this); + } +} diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta new file mode 100644 index 0000000..52a333e --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9163d963b36b4e389318f312bfd8e488 +timeCreated: 1691485295 \ No newline at end of file diff --git a/Assets/Mirror/Core/Threading/ConcurrentPool.cs b/Assets/Mirror/Core/Threading/ConcurrentPool.cs new file mode 100644 index 0000000..eeac0cc --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentPool.cs @@ -0,0 +1,44 @@ +// Pool to avoid allocations (from libuv2k) +// API consistent with Microsoft's ObjectPool. +// concurrent for thread safe access. +// +// currently not in use. keep it in case we need it again. +using System; +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public class ConcurrentPool + { + // Mirror is single threaded, no need for concurrent collections + // concurrent bag is for items who's order doesn't matter. + // just about right for our use case here. + readonly ConcurrentBag objects = new ConcurrentBag(); + + // some types might need additional parameters in their constructor, so + // we use a Func generator + readonly Func objectGenerator; + + public ConcurrentPool(Func objectGenerator, int initialCapacity) + { + this.objectGenerator = objectGenerator; + + // allocate an initial pool so we have fewer (if any) + // allocations in the first few frames (or seconds). + for (int i = 0; i < initialCapacity; ++i) + objects.Add(objectGenerator()); + } + + // take an element from the pool, or create a new one if empty + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Get() => objects.TryTake(out T obj) ? obj : objectGenerator(); + + // return an element to the pool + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(T item) => objects.Add(item); + + // count to see how many objects are in the pool. useful for tests. + public int Count => objects.Count; + } +} diff --git a/Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta b/Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta new file mode 100644 index 0000000..40e966a --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed304bd790ff478ca37233f66d04d1c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Threading/ThreadLog.cs b/Assets/Mirror/Core/Threading/ThreadLog.cs new file mode 100644 index 0000000..36dca5f --- /dev/null +++ b/Assets/Mirror/Core/Threading/ThreadLog.cs @@ -0,0 +1,112 @@ +// threaded Debug.Log support (mischa 2022) +// +// Editor shows Debug.Logs from different threads. +// Builds don't show Debug.Logs from different threads. +// +// need to hook into logMessageReceivedThreaded to receive them in builds too. +using System.Collections.Concurrent; +using System.Threading; +using UnityEngine; + +namespace Mirror +{ + public static class ThreadLog + { + // queue log messages from threads + struct LogEntry + { + public int threadId; + public LogType type; + public string message; + public string stackTrace; + + public LogEntry(int threadId, LogType type, string message, string stackTrace) + { + this.threadId = threadId; + this.type = type; + this.message = message; + this.stackTrace = stackTrace; + } + } + + // ConcurrentQueue allocations are fine here. + // logs allocate anywway. + static readonly ConcurrentQueue logs = + new ConcurrentQueue(); + + // main thread id + static int mainThreadId; + +#if !UNITY_EDITOR + // Editor as of Unity 2021 does log threaded messages. + // only builds don't. + // do nothing in editor, otherwise we would log twice. + // before scene load ensures thread logs are all caught. + // otherwise some component's Awake may be called before we hooked it up. + // for example, ThreadedTransport's early logs wouldn't be caught. + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void Initialize() + { + + // set main thread id + mainThreadId = Thread.CurrentThread.ManagedThreadId; + + // receive threaded log calls + Application.logMessageReceivedThreaded -= OnLog; // remove old first. TODO unnecessary? + Application.logMessageReceivedThreaded += OnLog; + + // process logs on main thread Update + NetworkLoop.OnLateUpdate -= OnLateUpdate; // remove old first. TODO unnecessary? + NetworkLoop.OnLateUpdate += OnLateUpdate; + + // log for debugging + Debug.Log("ThreadLog initialized."); + } +#endif + + static bool IsMainThread() => + Thread.CurrentThread.ManagedThreadId == mainThreadId; + + // callback runs on the same thread where the Debug.Log is called. + // we can use this to buffer messages for main thread here. + static void OnLog(string message, string stackTrace, LogType type) + { + // only enqueue messages from other threads. + // otherwise OnLateUpdate main thread logging would be enqueued + // as well, causing deadlock. + if (IsMainThread()) return; + + // queue for logging from main thread later + logs.Enqueue(new LogEntry(Thread.CurrentThread.ManagedThreadId, type, message, stackTrace)); + } + + static void OnLateUpdate() + { + // process queued logs on main thread + while (logs.TryDequeue(out LogEntry entry)) + { + switch (entry.type) + { + // add [Thread#] prefix to make it super obvious where this log message comes from. + // some projects may see unexpected messages that were previously hidden, + // since Unity wouldn't log them without ThreadLog.cs. + case LogType.Log: + Debug.Log($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Warning: + Debug.LogWarning($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Error: + Debug.LogError($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Exception: + Debug.LogError($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Assert: + Debug.LogAssertion($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + } + } + } + } +} diff --git a/Assets/Mirror/Core/Threading/ThreadLog.cs.meta b/Assets/Mirror/Core/Threading/ThreadLog.cs.meta new file mode 100644 index 0000000..bd0d5dd --- /dev/null +++ b/Assets/Mirror/Core/Threading/ThreadLog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22360406b3844808b0a305486758a703 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Threading/WorkerThread.cs b/Assets/Mirror/Core/Threading/WorkerThread.cs new file mode 100644 index 0000000..4b037c0 --- /dev/null +++ b/Assets/Mirror/Core/Threading/WorkerThread.cs @@ -0,0 +1,165 @@ +// worker thread for Unity (mischa 2022) +// thread with proper exception handling, profling, init, cleanup, etc. for Unity. +// use this from main thread. +using System; +using System.Diagnostics; +using System.Threading; +using UnityEngine.Profiling; +using Debug = UnityEngine.Debug; + +namespace Mirror +{ + public class WorkerThread + { + readonly Thread thread; + + protected volatile bool active; + + // stopwatch so we don't need to use Unity's Time (engine independent) + readonly Stopwatch watch = new Stopwatch(); + + // callbacks need to be set after constructor. + // inheriting classes can't pass their member funcs to base ctor. + // don't set them while the thread is running! + public Action Init; + public Action Tick; + public Action Cleanup; + + public WorkerThread(string identifier) + { + // start the thread wrapped in safety guard + // if main application terminates, this thread needs to terminate too + thread = new Thread( + () => Guard(identifier) + ); + thread.IsBackground = true; + } + + public void Start() + { + // only if thread isn't already running + if (thread.IsAlive) + { + Debug.LogWarning("WorkerThread is still active, can't start it again."); + return; + } + + active = true; + thread.Start(); + } + + // signal the thread to stop gracefully. + // returns immediately, but the thread may take a while to stop. + // may be overwritten to clear more flags like 'computing' etc. + public virtual void SignalStop() => active = false; + + // wait for the thread to fully stop + public bool StopBlocking(float timeout) + { + // only if alive + if (!thread.IsAlive) return true; + + // double precision for long running servers. + watch.Restart(); + + // signal to stop + SignalStop(); + + // wait while thread is still alive + while (IsAlive) + { + // simply wait.. + Thread.Sleep(0); + + // deadlock detection + if (watch.Elapsed.TotalSeconds >= timeout) + { + // force kill all threads as last resort to stop them. + // return false to indicate deadlock. + Interrupt(); + return false; + } + } + return true; + } + + public bool IsAlive => thread.IsAlive; + + // signal an interrupt in the thread. + // this function is very safe to use. + // https://stackoverflow.com/questions/5950994/thread-abort-vs-thread-interrupt + // + // note this does not always kill the thread: + // "If this thread is not currently blocked in a wait, sleep, or join + // state, it will be interrupted when it next begins to block." + // https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.interrupt?view=net-6.0 + // + // in other words, "while (true) {}" wouldn't throw an interrupt exception. + // and that's _okay_. using interrupt is safe & best practice. + // => Unity still aborts deadlocked threads on script reload. + // => and we catch + warn on AbortException. + public void Interrupt() => thread.Interrupt(); + + // thread constructor needs callbacks. + // always define them, and make them call actions. + // those can be set at any time. + void OnInit() => Init?.Invoke(); + void OnTick() => Tick?.Invoke(); + void OnCleanup() => Cleanup?.Invoke(); + + // guarded wrapper for thread code. + // catches exceptions which would otherwise be silent. + // shows in Unity profiler. + // etc. + public void Guard(string identifier) + { + try + { + // log when work begins = thread starts. + // very important for debugging threads. + Debug.Log($"{identifier}: started."); + + // show this thread in Unity profiler + Profiler.BeginThreadProfiling("Mirror Worker Threads", $"{identifier}"); + + // run init once + OnInit(); + + // run thread func while active + while (active) + { + OnTick(); + } + } + // Thread.Interrupt() will gracefully raise a InterruptedException. + catch (ThreadInterruptedException) + { + Debug.Log($"{identifier}: interrupted. That's okay."); + } + // Unity domain reload will cause a ThreadAbortException. + // for example, when saving a changed script while in play mode. + catch (ThreadAbortException) + { + Debug.LogWarning($"{identifier}: aborted. This may happen after domain reload. That's okay."); + } + catch (Exception e) + { + Debug.LogException(e); + } + finally + { + // run cleanup (if any) + active = false; + OnCleanup(); + + // remove this thread from Unity profiler + Profiler.EndThreadProfiling(); + + // log when work ends = thread terminates. + // very important for debugging threads. + // 'finally' to log no matter what (even if exceptions) + Debug.Log($"{identifier}: ended."); + } + } + } +} diff --git a/Assets/Mirror/Core/Threading/WorkerThread.cs.meta b/Assets/Mirror/Core/Threading/WorkerThread.cs.meta new file mode 100644 index 0000000..7427cd4 --- /dev/null +++ b/Assets/Mirror/Core/Threading/WorkerThread.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 605fa1d7e32f40a08e5549bb43fc5c07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Tools/AccurateInterval.cs b/Assets/Mirror/Core/Tools/AccurateInterval.cs index 653c7ba..9d2ce0e 100644 --- a/Assets/Mirror/Core/Tools/AccurateInterval.cs +++ b/Assets/Mirror/Core/Tools/AccurateInterval.cs @@ -34,53 +34,53 @@ public static class AccurateInterval [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Elapsed(double time, double interval, ref double lastTime) { - if (time >= lastTime + interval) - { - // naive implementation: - //lastTime = time; + // enough time elapsed? + if (time < lastTime + interval) + return false; - // accurate but doesn't handle heavy load situations: - //lastTime += interval; + // naive implementation: + //lastTime = time; - // heavy load edge case: - // * interval is 100ms - // * server is under heavy load, Updates slow down to 1/s - // * Elapsed(1.000) returns true. - // technically 10 intervals have elapsed. - // * server recovers to normal, Updates are every 10ms again - // * Elapsed(1.010) should return false again until 1.100. - // - // increasing lastTime by interval would require 10 more calls - // to ever catch up again: - // lastTime += interval - // - // as result, the next 10 calls to Elapsed would return true. - // Elapsed(1.001) => true - // Elapsed(1.002) => true - // Elapsed(1.003) => true - // ... - // even though technically the delta was not >= interval. - // - // this would keep the server under heavy load, and it may never - // catch-up. this is not ideal for large virtual worlds. - // - // instead, we want to skip multiples of 'interval' and only - // keep the remainder. - // - // see also: AccurateIntervalTests.Slowdown() + // accurate but doesn't handle heavy load situations: + //lastTime += interval; - // easy to understand: - //double elapsed = time - lastTime; - //double remainder = elapsed % interval; - //lastTime = time - remainder; + // heavy load edge case: + // * interval is 100ms + // * server is under heavy load, Updates slow down to 1/s + // * Elapsed(1.000) returns true. + // technically 10 intervals have elapsed. + // * server recovers to normal, Updates are every 10ms again + // * Elapsed(1.010) should return false again until 1.100. + // + // increasing lastTime by interval would require 10 more calls + // to ever catch up again: + // lastTime += interval + // + // as result, the next 10 calls to Elapsed would return true. + // Elapsed(1.001) => true + // Elapsed(1.002) => true + // Elapsed(1.003) => true + // ... + // even though technically the delta was not >= interval. + // + // this would keep the server under heavy load, and it may never + // catch-up. this is not ideal for large virtual worlds. + // + // instead, we want to skip multiples of 'interval' and only + // keep the remainder. + // + // see also: AccurateIntervalTests.Slowdown() - // easier: set to rounded multiples of interval (fholm). - // long to match double time. - long multiplier = (long)(time / interval); - lastTime = multiplier * interval; - return true; - } - return false; + // easy to understand: + //double elapsed = time - lastTime; + //double remainder = elapsed % interval; + //lastTime = time - remainder; + + // easier: set to rounded multiples of interval (fholm). + // long to match double time. + long multiplier = (long)(time / interval); + lastTime = multiplier * interval; + return true; } } } diff --git a/Assets/Mirror/Core/Tools/Compression.cs b/Assets/Mirror/Core/Tools/Compression.cs index 2a922fc..d04b566 100644 --- a/Assets/Mirror/Core/Tools/Compression.cs +++ b/Assets/Mirror/Core/Tools/Compression.cs @@ -174,21 +174,7 @@ public static int LargestAbsoluteComponentIndex(Vector4 value, out float largest const float QuaternionMinRange = -0.707107f; const float QuaternionMaxRange = 0.707107f; - const ushort TenBitsMax = 0x3FF; - - // helper function to access 'nth' component of quaternion - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static float QuaternionElement(Quaternion q, int element) - { - switch (element) - { - case 0: return q.x; - case 1: return q.y; - case 2: return q.z; - case 3: return q.w; - default: return 0; - } - } + const ushort TenBitsMax = 0b11_1111_1111; // note: assumes normalized quaternions public static uint CompressQuaternion(Quaternion q) @@ -206,7 +192,7 @@ public static uint CompressQuaternion(Quaternion q) // [largest] always positive by negating the entire quaternion if // [largest] is negative. in quaternion space (x,y,z,w) and // (-x,-y,-z,-w) represent the same rotation." - if (QuaternionElement(q, largestIndex) < 0) + if (q[largestIndex] < 0) withoutLargest = -withoutLargest; // put index & three floats into one integer. @@ -293,11 +279,46 @@ public static Quaternion DecompressQuaternion(uint data) } // varint compression ////////////////////////////////////////////////// + // helper function to predict varint size for a given number. + // useful when checking if a message + size header will fit, etc. + public static int VarUIntSize(ulong value) + { + if (value <= 240) + return 1; + if (value <= 2287) + return 2; + if (value <= 67823) + return 3; + if (value <= 16777215) + return 4; + if (value <= 4294967295) + return 5; + if (value <= 1099511627775) + return 6; + if (value <= 281474976710655) + return 7; + if (value <= 72057594037927935) + return 8; + return 9; + } + + // helper function to predict varint size for a given number. + // useful when checking if a message + size header will fit, etc. + public static int VarIntSize(long value) + { + // CompressVarInt zigzags it first + ulong zigzagged = (ulong)((value >> 63) ^ (value << 1)); + return VarUIntSize(zigzagged); + } + // compress ulong varint. // same result for ulong, uint, ushort and byte. only need one function. // NOT an extension. otherwise weaver might accidentally use it. public static void CompressVarUInt(NetworkWriter writer, ulong value) { + // straight forward implementation: + // keep this for understanding & debugging. + /* if (value <= 240) { writer.WriteByte((byte)value); @@ -379,6 +400,81 @@ public static void CompressVarUInt(NetworkWriter writer, ulong value) writer.WriteByte((byte)((value >> 48) & 0xFF)); writer.WriteByte((byte)((value >> 56) & 0xFF)); } + */ + + // faster implementation writes multiple bytes at once. + // avoids extra Space, WriteBlittable overhead. + // VarInt is in hot path, performance matters here. + if (value <= 240) + { + byte a = (byte)value; + writer.WriteByte(a); + return; + } + if (value <= 2287) + { + byte a = (byte)(((value - 240) >> 8) + 241); + byte b = (byte)((value - 240) & 0xFF); + writer.WriteUShort((ushort)(b << 8 | a)); + return; + } + if (value <= 67823) + { + byte a = (byte)249; + byte b = (byte)((value - 2288) >> 8); + byte c = (byte)((value - 2288) & 0xFF); + writer.WriteByte(a); + writer.WriteUShort((ushort)(c << 8 | b)); + return; + } + if (value <= 16777215) + { + byte a = (byte)250; + uint b = (uint)(value << 8); + writer.WriteUInt(b | a); + return; + } + if (value <= 4294967295) + { + byte a = (byte)251; + uint b = (uint)value; + writer.WriteByte(a); + writer.WriteUInt(b); + return; + } + if (value <= 1099511627775) + { + byte a = (byte)252; + byte b = (byte)(value & 0xFF); + uint c = (uint)(value >> 8); + writer.WriteUShort((ushort)(b << 8 | a)); + writer.WriteUInt(c); + return; + } + if (value <= 281474976710655) + { + byte a = (byte)253; + byte b = (byte)(value & 0xFF); + byte c = (byte)((value >> 8) & 0xFF); + uint d = (uint)(value >> 16); + writer.WriteByte(a); + writer.WriteUShort((ushort)(c << 8 | b)); + writer.WriteUInt(d); + return; + } + if (value <= 72057594037927935) + { + byte a = 254; + ulong b = value << 8; + writer.WriteULong(b | a); + return; + } + + // all others + { + writer.WriteByte(255); + writer.WriteULong(value); + } } // zigzag encoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba diff --git a/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs b/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs index 2080bc7..674abb8 100644 --- a/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs +++ b/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs @@ -7,7 +7,7 @@ namespace Mirror { public struct ExponentialMovingAverage { - readonly float alpha; + readonly double alpha; bool initialized; public double Value; @@ -17,7 +17,7 @@ public struct ExponentialMovingAverage public ExponentialMovingAverage(int n) { // standard N-day EMA alpha calculation - alpha = 2.0f / (n + 1); + alpha = 2.0 / (n + 1); initialized = false; Value = 0; Variance = 0; @@ -41,5 +41,13 @@ public void Add(double newValue) initialized = true; } } + + public void Reset() + { + initialized = false; + Value = 0; + Variance = 0; + StandardDeviation = 0; + } } } diff --git a/Assets/Mirror/Core/Tools/Extensions.cs b/Assets/Mirror/Core/Tools/Extensions.cs index 3654e4b..cd29a2a 100644 --- a/Assets/Mirror/Core/Tools/Extensions.cs +++ b/Assets/Mirror/Core/Tools/Extensions.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Net; using System.Runtime.CompilerServices; +using UnityEngine; namespace Mirror { @@ -9,19 +12,46 @@ public static class Extensions public static string ToHexString(this ArraySegment segment) => BitConverter.ToString(segment.Array, segment.Offset, segment.Count); - // string.GetHashCode is not guaranteed to be the same on all machines, but - // we need one that is the same on all machines. simple and stupid: + // string.GetHashCode is not guaranteed to be the same on all + // machines, but we need one that is the same on all machines. + // Uses fnv1a as hash function for more uniform distribution http://www.isthe.com/chongo/tech/comp/fnv/ + // Tests: https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed + // NOTE: Do not call this from hot path because it's slow O(N) for long method names. + // - As of 2012-02-16 There are 2 design-time callers (weaver) and 1 runtime caller that caches. public static int GetStableHashCode(this string text) { unchecked { - int hash = 23; - foreach (char c in text) - hash = hash * 31 + c; - return hash; + uint hash = 0x811c9dc5; + uint prime = 0x1000193; + + for (int i = 0; i < text.Length; ++i) + { + byte value = (byte)text[i]; + hash = hash ^ value; + hash *= prime; + } + + //UnityEngine.Debug.Log($"Created stable hash {(ushort)hash} for {text}"); + return (int)hash; } } + // smaller version of our GetStableHashCode. + // careful, this significantly increases chance of collisions. + public static ushort GetStableHashCode16(this string text) + { + // deterministic hash + int hash = GetStableHashCode(text); + + // Gets the 32bit fnv1a hash + // To get it down to 16bit but still reduce hash collisions we cant just cast it to ushort + // Instead we take the highest 16bits of the 32bit hash and fold them with xor into the lower 16bits + // This will create a more uniform 16bit hash, the method is described in: + // http://www.isthe.com/chongo/tech/comp/fnv/ in section "Changing the FNV hash size - xor-folding" + return (ushort)((hash >> 16) ^ hash); + } + // previously in DotnetCompatibility.cs // leftover from the UNET days. supposedly for windows store? internal static string GetMethodName(this Delegate func) @@ -43,7 +73,7 @@ public static void CopyTo(this IEnumerable source, List destination) } #if !UNITY_2021_OR_NEWER - // Unity 2020 and earlier doesn't have Queue.TryDequeue which we need for batching. + // Unity 2020 and earlier don't have Queue.TryDequeue which we need for batching. public static bool TryDequeue(this Queue source, out T element) { if (source.Count > 0) @@ -56,5 +86,42 @@ public static bool TryDequeue(this Queue source, out T element) return false; } #endif + +#if !UNITY_2021_OR_NEWER + // Unity 2020 and earlier don't have ConcurrentQueue.Clear which we need for ThreadedTransport. + public static void Clear(this ConcurrentQueue source) + { + // while count > 0 risks deadlock if other thread write at the same time. + // our safest solution is a best-effort approach to clear 'Count' once. + int count = source.Count; // get it only once + for (int i = 0; i < count; ++i) + { + source.TryDequeue(out _); + } + } +#endif + +#if !UNITY_2022_0_OR_NEWER + // Some patch versions of Unity 2021.3 and earlier don't have transform.GetPositionAndRotation which we use for performance in some places + public static void GetPositionAndRotation(this Transform transform, out Vector3 position, out Quaternion rotation) + { + position = transform.position; + rotation = transform.rotation; + } +#endif + + // IPEndPoint address only to pretty string. + // useful for to get a connection's address for IP bans etc. + public static string PrettyAddress(this IPEndPoint endPoint) + { + if (endPoint == null) return ""; + + // Map to IPv4 if "IsIPv4MappedToIPv6" for readability + // "::ffff:127.0.0.1" -> "127.0.0.1" + return + endPoint.Address.IsIPv4MappedToIPv6 + ? endPoint.Address.MapToIPv4().ToString() + : endPoint.Address.ToString(); + } } } diff --git a/Assets/Mirror/Core/Tools/Mathd.cs b/Assets/Mirror/Core/Tools/Mathd.cs index af5d7b8..374471a 100644 --- a/Assets/Mirror/Core/Tools/Mathd.cs +++ b/Assets/Mirror/Core/Tools/Mathd.cs @@ -5,15 +5,20 @@ namespace Mirror { public static class Mathd { + // Unity 2020 doesn't have Math.Clamp yet. /// Clamps value between 0 and 1 and returns value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Clamp01(double value) + public static double Clamp(double value, double min, double max) { - if (value < 0.0) - return 0; - return value > 1 ? 1 : value; + if (value < min) return min; + if (value > max) return max; + return value; } + /// Clamps value between 0 and 1 and returns value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Clamp01(double value) => Clamp(value, 0, 1); + /// Calculates the linear parameter t that produces the interpolant value within the range [a, b]. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InverseLerp(double a, double b, double value) => diff --git a/Assets/Mirror/Core/Tools/Pool.cs b/Assets/Mirror/Core/Tools/Pool.cs index e204575..f26d49b 100644 --- a/Assets/Mirror/Core/Tools/Pool.cs +++ b/Assets/Mirror/Core/Tools/Pool.cs @@ -32,7 +32,15 @@ public Pool(Func objectGenerator, int initialCapacity) // return an element to the pool [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Return(T item) => objects.Push(item); + public void Return(T item) + { + // make sure we can't accidentally insert null values into the pool. + // debugging this would be hard since it would only show on get(). + if (item == null) + throw new ArgumentNullException(nameof(item)); + + objects.Push(item); + } // count to see how many objects are in the pool. useful for tests. public int Count => objects.Count; diff --git a/Assets/Mirror/Core/Tools/Utils.cs b/Assets/Mirror/Core/Tools/Utils.cs index bf189e4..406484f 100644 --- a/Assets/Mirror/Core/Tools/Utils.cs +++ b/Assets/Mirror/Core/Tools/Utils.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using System.Security.Cryptography; using UnityEngine; +using UnityEngine.Rendering; using UnityEngine.SceneManagement; namespace Mirror @@ -32,6 +33,39 @@ public static class Channels public static class Utils { + // detect headless / dedicated server mode + // SystemInfo.graphicsDeviceType is never null in the editor. + // UNITY_SERVER works in builds for all Unity versions 2019 LTS and later. + // For Unity 2019 / 2020, there is no way to detect Server Build checkbox + // state in Build Settings, so they never auto-start headless server / client. + // UNITY_SERVER works in the editor in Unity 2021 LTS and later + // because that's when Dedicated Server platform was added. + // It is intentional for editor play mode to auto-start headless server / client + // when Dedicated Server platform is selected in the editor so that editor + // acts like a headless build to every extent possible for testing / debugging. + public static bool IsHeadless() => +#if UNITY_SERVER + true; +#else + SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null; +#endif + + // detect WebGL mode + public const bool IsWebGL = +#if UNITY_WEBGL + true; +#else + false; +#endif + + // detect Debug mode + public const bool IsDebug = +#if DEBUG + true; +#else + false; +#endif + public static uint GetTrueRandomUInt() { // use Crypto RNG to avoid having time based duplicates @@ -131,7 +165,6 @@ public static string PrettySeconds(double seconds) } // universal .spawned function - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static NetworkIdentity GetSpawnedInServerOrClient(uint netId) { // server / host mode: use the one from server. diff --git a/Assets/Mirror/Core/Transport.cs b/Assets/Mirror/Core/Transport.cs index 7e0716d..a20d84f 100644 --- a/Assets/Mirror/Core/Transport.cs +++ b/Assets/Mirror/Core/Transport.cs @@ -36,6 +36,12 @@ public abstract class Transport : MonoBehaviour /// Is this transport available in the current platform? public abstract bool Available(); + /// Is this transported encrypted for secure communication? + public virtual bool IsEncrypted => false; + + /// If encrypted, which cipher is used? + public virtual string EncryptionCipher => ""; + // client ////////////////////////////////////////////////////////////// /// Called by Transport when the client connected to the server. public Action OnClientConnected; @@ -53,6 +59,9 @@ public abstract class Transport : MonoBehaviour /// Called by Transport when the client encountered an error. public Action OnClientError; + /// Called by Transport when the client encountered an error. + public Action OnClientTransportException; + /// Called by Transport when the client disconnected from the server. public Action OnClientDisconnected; @@ -74,6 +83,10 @@ public abstract class Transport : MonoBehaviour /// If a Disconnect will also be raised, raise the Error first. public Action OnServerError; + /// Called by Transport when a server's connection encountered a problem. + /// If a Disconnect will also be raised, raise the Error first. + public Action OnServerTransportException; + /// Called by Transport when a client disconnected from the server. public Action OnServerDisconnected; diff --git a/Assets/Mirror/Core/WeaverFuse.cs b/Assets/Mirror/Core/WeaverFuse.cs new file mode 100644 index 0000000..f850323 --- /dev/null +++ b/Assets/Mirror/Core/WeaverFuse.cs @@ -0,0 +1,22 @@ +// safety fuse for weaver to flip. +// runtime can check this to ensure weaving succeded. +// otherwise running server/client would give lots of random 'writer not found' etc. errors. +// this is much cleaner. +// +// note that ILPostProcessor errors already block entering playmode. +// however, issues could still stop the weaving from running at all. +// WeaverFuse can check if it actually ran. +namespace Mirror +{ + public static class WeaverFuse + { + // this trick only works for ILPostProcessor. + // CompilationFinishedHook can't weaver Mirror.dll. + public static bool Weaved() => +#if UNITY_2020_3_OR_NEWER + false; +#else + true; +#endif + } +} diff --git a/Assets/Mirror/Core/WeaverFuse.cs.meta b/Assets/Mirror/Core/WeaverFuse.cs.meta new file mode 100644 index 0000000..c5a9e7b --- /dev/null +++ b/Assets/Mirror/Core/WeaverFuse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4de3dfbcbd2e41fcac947c04bcac52c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Editor/EditorHelper.cs b/Assets/Mirror/Editor/EditorHelper.cs index b10c7b0..c3551ab 100644 --- a/Assets/Mirror/Editor/EditorHelper.cs +++ b/Assets/Mirror/Editor/EditorHelper.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; @@ -27,5 +28,14 @@ public static string FindPath() return string.Empty; } } + + + public static IEnumerable IterateOverProject(string filter) + { + foreach (string guid in AssetDatabase.FindAssets(filter)) + { + yield return AssetDatabase.GUIDToAssetPath(guid); + } + } } } diff --git a/Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs b/Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs deleted file mode 100644 index 18ab111..0000000 --- a/Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-12-12 diff --git a/Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs.meta b/Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs.meta deleted file mode 100644 index 79a200d..0000000 --- a/Assets/Mirror/Editor/Empty/EnterPlayModeSettingsCheck.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b15a0d2ca0909400eb53dd6fe894cddd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Empty/LogLevelWindow.cs b/Assets/Mirror/Editor/Empty/LogLevelWindow.cs deleted file mode 100644 index 82e5275..0000000 --- a/Assets/Mirror/Editor/Empty/LogLevelWindow.cs +++ /dev/null @@ -1 +0,0 @@ -// 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 deleted file mode 100644 index b8cbaeb..0000000 --- a/Assets/Mirror/Editor/Empty/LogLevelWindow.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 257467f..0000000 --- a/Assets/Mirror/Editor/Empty/Logging.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs.meta b/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs.meta deleted file mode 100644 index 832876f..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/LogLevelWindow.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs.meta b/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs.meta deleted file mode 100644 index 3214b08..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/LogLevelsGUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs.meta b/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs.meta deleted file mode 100644 index 2c1fac4..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/LogSettingsEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs.meta b/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs.meta deleted file mode 100644 index b4c277d..0000000 --- a/Assets/Mirror/Editor/Empty/Logging/NetworkLogSettingsEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 39b95f7..0000000 --- a/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2021-02-16 diff --git a/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs.meta b/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs.meta deleted file mode 100644 index a1a0af3..0000000 --- a/Assets/Mirror/Editor/Empty/ScriptableObjectUtility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4d54a29ddd5b52b4eaa07ed39c0e3e83 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Empty/SyncVarDrawer.cs b/Assets/Mirror/Editor/Empty/SyncVarDrawer.cs deleted file mode 100644 index aaa3b9d..0000000 --- a/Assets/Mirror/Editor/Empty/SyncVarDrawer.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2022-11-03 diff --git a/Assets/Mirror/Editor/Empty/SyncVarDrawer.cs.meta b/Assets/Mirror/Editor/Empty/SyncVarDrawer.cs.meta deleted file mode 100644 index 0ee91aa..0000000 --- a/Assets/Mirror/Editor/Empty/SyncVarDrawer.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 874812594431423b84f763b987ff9681 -timeCreated: 1632553007 \ No newline at end of file diff --git a/Assets/Mirror/Editor/LagCompensatorInspector.cs b/Assets/Mirror/Editor/LagCompensatorInspector.cs new file mode 100644 index 0000000..f706384 --- /dev/null +++ b/Assets/Mirror/Editor/LagCompensatorInspector.cs @@ -0,0 +1,14 @@ +using UnityEditor; + +namespace Mirror +{ + [CustomEditor(typeof(LagCompensator))] + public class LagCompensatorInspector : Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.HelpBox("Preview Component - Feedback appreciated on GitHub or Discord!", MessageType.Warning); + DrawDefaultInspector(); + } + } +} diff --git a/Assets/Mirror/Core/Empty/Cloud/Ball.cs.meta b/Assets/Mirror/Editor/LagCompensatorInspector.cs.meta similarity index 83% rename from Assets/Mirror/Core/Empty/Cloud/Ball.cs.meta rename to Assets/Mirror/Editor/LagCompensatorInspector.cs.meta index a6fc272..0f3e8f7 100644 --- a/Assets/Mirror/Core/Empty/Cloud/Ball.cs.meta +++ b/Assets/Mirror/Editor/LagCompensatorInspector.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b4e9cc0829b13e54594a80883836bda7 +guid: 703e39b5385ae2e479987ff4ec0707a1 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirror/Editor/Mirror.Editor.asmdef b/Assets/Mirror/Editor/Mirror.Editor.asmdef index 651b8fe..800e67b 100644 --- a/Assets/Mirror/Editor/Mirror.Editor.asmdef +++ b/Assets/Mirror/Editor/Mirror.Editor.asmdef @@ -3,6 +3,7 @@ "rootNamespace": "", "references": [ "GUID:30817c1a0e6d646d99c048fc403f5979", + "GUID:72872094b21c16e48b631b2224833d49", "GUID:1d0b9d21c3ff546a4aa32399dfd33474" ], "includePlatforms": [ diff --git a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs index 7cae54f..52c56d6 100644 --- a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs +++ b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs @@ -43,7 +43,8 @@ bool SyncsAnything(Type scriptClass) void OnEnable() { - if (target == null) { Debug.LogWarning("NetworkBehaviourInspector had no target object"); return; } + // sometimes target is null. just return early. + if (target == null) return; // If target's base class is changed from NetworkBehaviour to MonoBehaviour // then Unity temporarily keep using this Inspector causing things to break diff --git a/Assets/Mirror/Editor/NetworkInformationPreview.cs b/Assets/Mirror/Editor/NetworkInformationPreview.cs index ec0a01e..b4dbe5e 100644 --- a/Assets/Mirror/Editor/NetworkInformationPreview.cs +++ b/Assets/Mirror/Editor/NetworkInformationPreview.cs @@ -126,7 +126,9 @@ float DrawNetworkIdentityInfo(NetworkIdentity identity, float initialX, float Y) 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); + + // height needs a +1 to line up nicely + Rect idLabelRect = new Rect(maxNameLabelSize.x, Y, maxValueLabelSize.x, maxValueLabelSize.y + 1); foreach (NetworkIdentityInfo info in infos) { diff --git a/Assets/Mirror/Editor/NetworkManagerEditor.cs b/Assets/Mirror/Editor/NetworkManagerEditor.cs index 94b0844..82b2b1b 100644 --- a/Assets/Mirror/Editor/NetworkManagerEditor.cs +++ b/Assets/Mirror/Editor/NetworkManagerEditor.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections.Generic; +using System.Linq; using UnityEditor; using UnityEditorInternal; using UnityEngine; @@ -42,6 +45,76 @@ public override void OnInspectorGUI() { serializedObject.ApplyModifiedProperties(); } + + if (GUILayout.Button("Populate Spawnable Prefabs")) + { + ScanForNetworkIdentities(); + } + } + + void ScanForNetworkIdentities() + { + List identities = new List(); + bool cancelled = false; + try + { + string[] paths = EditorHelper.IterateOverProject("t:prefab").ToArray(); + int count = 0; + foreach (string path in paths) + { + // ignore test & example prefabs. + // users sometimes keep the folders in their projects. + if (path.Contains("Mirror/Tests/") || + path.Contains("Mirror/Examples/")) + { + continue; + } + + if (EditorUtility.DisplayCancelableProgressBar("Searching for NetworkIdentities..", + $"Scanned {count}/{paths.Length} prefabs. Found {identities.Count} new ones", + count / (float)paths.Length)) + { + cancelled = true; + break; + } + + count++; + + NetworkIdentity ni = AssetDatabase.LoadAssetAtPath(path); + if (!ni) + { + continue; + } + + if (!networkManager.spawnPrefabs.Contains(ni.gameObject)) + { + identities.Add(ni.gameObject); + } + + } + } + finally + { + + EditorUtility.ClearProgressBar(); + if (!cancelled) + { + // RecordObject is needed for "*" to show up in Scene. + // however, this only saves List.Count without the entries. + Undo.RecordObject(networkManager, "NetworkManager: populated prefabs"); + + // add the entries + networkManager.spawnPrefabs.AddRange(identities); + + // sort alphabetically for better UX + networkManager.spawnPrefabs = networkManager.spawnPrefabs.OrderBy(go => go.name).ToList(); + + // SetDirty is required to save the individual entries properly. + EditorUtility.SetDirty(target); + } + // Loading assets might use a lot of memory, so try to unload them after + Resources.UnloadUnusedAssets(); + } } static void DrawHeader(Rect headerRect) diff --git a/Assets/Mirror/Editor/NetworkScenePostProcess.cs b/Assets/Mirror/Editor/NetworkScenePostProcess.cs index 6dcd65d..2fa07d6 100644 --- a/Assets/Mirror/Editor/NetworkScenePostProcess.cs +++ b/Assets/Mirror/Editor/NetworkScenePostProcess.cs @@ -33,9 +33,7 @@ public static void OnPostProcessScene() // 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, @@ -88,22 +86,12 @@ static void PrepareSceneObject(NetworkIdentity identity) 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/ReadOnlyDrawer.cs b/Assets/Mirror/Editor/ReadOnlyDrawer.cs new file mode 100644 index 0000000..4a09707 --- /dev/null +++ b/Assets/Mirror/Editor/ReadOnlyDrawer.cs @@ -0,0 +1,19 @@ +using UnityEngine; +using UnityEditor; + +namespace Mirror +{ + [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] + public class ReadOnlyDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + // Cache the current GUI enabled state + bool prevGuiEnabledState = GUI.enabled; + + GUI.enabled = false; + EditorGUI.PropertyField(position, property, label, true); + GUI.enabled = prevGuiEnabledState; + } + } +} diff --git a/Assets/Mirror/Components/NetworkTransformBase.cs.meta b/Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta similarity index 83% rename from Assets/Mirror/Components/NetworkTransformBase.cs.meta rename to Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta index 37a1147..eb6eb0f 100644 --- a/Assets/Mirror/Components/NetworkTransformBase.cs.meta +++ b/Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7c44135fde488424eaf28566206ce473 +guid: 22f17bdd21f104c41bc175937fefbdec MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs b/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs index 2c95bcf..735b018 100644 --- a/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs +++ b/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using System.Reflection; +using System.Text.RegularExpressions; using UnityEditor; namespace Mirror @@ -18,7 +19,12 @@ public SyncObjectCollectionField(FieldInfo field) { this.field = field; visible = false; - label = $"{field.Name} [{field.FieldType.Name}]"; + + // field.FieldType.Name has a backtick and number at the end, e.g. SyncList`1 + // so we split it and only take the first part so it looks nicer. + // e.g. SyncList`1 -> SyncList + // Better to do it one time here than in hot path in OnInspectorGUI + label = $"{field.Name} [{Regex.Replace(field.FieldType.Name, @"`\d+", "")}]"; } } diff --git a/Assets/Mirror/Editor/Weaver/Empty.meta b/Assets/Mirror/Editor/Weaver/Empty.meta deleted file mode 100644 index 6e29ee7..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index a88144a..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs +++ /dev/null @@ -1 +0,0 @@ -// 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 deleted file mode 100644 index 685f914..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/GenericArgumentResolver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index b38f171..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// 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 deleted file mode 100644 index cbea4d6..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/MessageClassProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index a214b81..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/Program.cs +++ /dev/null @@ -1 +0,0 @@ -// Removed 05/09/20 diff --git a/Assets/Mirror/Editor/Weaver/Empty/Program.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/Program.cs.meta deleted file mode 100644 index 0a14018..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/Program.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index a88144a..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// 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 deleted file mode 100644 index 0a7c2aa..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/SyncDictionaryProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 2fdbc52..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2020-09 diff --git a/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs.meta deleted file mode 100644 index 81b9576..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/SyncEventProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index a88144a..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// 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 deleted file mode 100644 index b73b047..0000000 --- a/Assets/Mirror/Editor/Weaver/Empty/SyncListProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/CompilationFinishedHook.cs b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs index 9016949..b5db851 100644 --- a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs @@ -57,11 +57,7 @@ public static void WeaveExistingAssemblies() } } -#if UNITY_2019_3_OR_NEWER EditorUtility.RequestScriptReload(); -#else - UnityEditorInternal.InternalEditorUtility.RequestScriptReload(); -#endif } static Assembly FindCompilationPipelineAssembly(string assemblyName) => @@ -79,13 +75,16 @@ public static void OnCompilationFinished(string assemblyPath, CompilerMessage[] return; } - // Should not run on the editor only assemblies - if (assemblyPath.Contains("-Editor") || assemblyPath.Contains(".Editor")) + // Should not run on the editor only assemblies (test ones still need to be weaved) + if (assemblyPath.Contains("-Editor") || + (assemblyPath.Contains(".Editor") && !assemblyPath.Contains(".Tests"))) { return; } - // don't weave mirror files + // skip Mirror.dll because CompilationFinishedHook can't weave itself. + // this would cause a sharing violation. + // skip Mirror.Weaver.dll too. string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); if (assemblyName == MirrorRuntimeAssemblyName || assemblyName == MirrorWeaverAssemblyName) { diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs index cbc8e41..0823234 100644 --- a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs @@ -14,7 +14,7 @@ // we need a custom resolver for ILPostProcessor. #if UNITY_2020_3_OR_NEWER using System; -using System.Collections.Generic; +using System.Collections.Concurrent; using System.IO; using System.Linq; using System.Threading; @@ -26,12 +26,23 @@ namespace Mirror.Weaver class ILPostProcessorAssemblyResolver : IAssemblyResolver { readonly string[] assemblyReferences; - readonly Dictionary assemblyCache = - new Dictionary(); + + // originally we used Dictionary + lock. + // Resolve() is called thousands of times for large projects. + // ILPostProcessor is multithreaded, so best to use ConcurrentDictionary without the lock here. + readonly ConcurrentDictionary assemblyCache = + new ConcurrentDictionary(); + + // Resolve() calls FindFile() every time. + // thousands of times for String => mscorlib alone in large projects. + // cache the results! ILPostProcessor is multithreaded, so use a ConcurrentDictionary here. + readonly ConcurrentDictionary fileNameCache = + new ConcurrentDictionary(); + readonly ICompiledAssembly compiledAssembly; AssemblyDefinition selfAssembly; - Logger Log; + readonly Logger Log; public ILPostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly, Logger Log) { @@ -54,56 +65,82 @@ protected virtual void Dispose(bool disposing) public AssemblyDefinition Resolve(AssemblyNameReference name) => Resolve(name, new ReaderParameters(ReadingMode.Deferred)); + // here is an example on when this is called: + // Player : NetworkBehaviour has a [SyncVar] of type String. + // Weaver's SyncObjectInitializer checks if ImplementsSyncObject() + // which needs to resolve the type 'String' from mscorlib. + // Resolve() lives in CecilX.MetadataResolver.Resolve() + // which calls assembly_resolver.Resolve(). + // which uses our ILPostProcessorAssemblyResolver here. + // + // for large projects, this is called thousands of times for mscorlib alone. + // initially ILPostProcessorAssemblyResolver took 30x longer than with CompilationFinishedHook. + // we need to cache and speed up everything we can here! public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) { - lock (assemblyCache) + if (name.Name == compiledAssembly.Name) + return selfAssembly; + + // cache FindFile. + // in large projects, this is called thousands(!) of times for String=>mscorlib alone. + // reduces a single String=>mscorlib resolve from 0.771ms to 0.015ms. + // => 50x improvement in TypeReference.Resolve() speed! + // => 22x improvement in Weaver speed! + if (!fileNameCache.TryGetValue(name.Name, out string fileName)) { - if (name.Name == compiledAssembly.Name) - return selfAssembly; + fileName = FindFile(name.Name); + fileNameCache.TryAdd(name.Name, fileName); + } - string fileName = FindFile(name); - if (fileName == null) + 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! + + // the fix for #2503 started showing this warning for Bee.BeeDriver on mac, + // which is for compilation. we can ignore that one. + if (!name.Name.StartsWith("Bee.BeeDriver")) { - // 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; } + return null; + } - DateTime lastWriteTime = File.GetLastWriteTime(fileName); - - string cacheKey = fileName + lastWriteTime; - - if (assemblyCache.TryGetValue(cacheKey, out AssemblyDefinition result)) - return result; - - parameters.AssemblyResolver = this; + // try to get cached assembly by filename + writetime + DateTime lastWriteTime = File.GetLastWriteTime(fileName); + string cacheKey = fileName + lastWriteTime; + if (assemblyCache.TryGetValue(cacheKey, out AssemblyDefinition result)) + return result; - MemoryStream ms = MemoryStreamFor(fileName); + // otherwise resolve and cache a new assembly + parameters.AssemblyResolver = this; + MemoryStream ms = MemoryStreamFor(fileName); - string pdb = fileName + ".pdb"; - if (File.Exists(pdb)) - parameters.SymbolStream = MemoryStreamFor(pdb); + string pdb = fileName + ".pdb"; + if (File.Exists(pdb)) + parameters.SymbolStream = MemoryStreamFor(pdb); - AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters); - assemblyCache.Add(cacheKey, assemblyDefinition); - return assemblyDefinition; - } + AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters); + assemblyCache.TryAdd(cacheKey, assemblyDefinition); + return assemblyDefinition; } // find assemblyname in assembly's references - string FindFile(AssemblyNameReference name) + string FindFile(string name) { - string fileName = assemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == name.Name + ".dll"); - if (fileName != null) - return fileName; + // perhaps the type comes from a .dll or .exe + // check both in one call without Linq instead of iterating twice like originally + foreach (string r in assemblyReferences) + { + if (Path.GetFileNameWithoutExtension(r) == name) + return r; + } - // perhaps the type comes from an exe instead - fileName = assemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == name.Name + ".exe"); - if (fileName != null) - return fileName; + // this is called thousands(!) of times. + // constructing strings only once saves ~0.1ms per call for mscorlib. + string dllName = name + ".dll"; // 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 @@ -114,7 +151,7 @@ string FindFile(AssemblyNameReference name) // 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"); + string candidate = Path.Combine(parentDir, dllName); if (File.Exists(candidate)) return candidate; } @@ -122,8 +159,9 @@ string FindFile(AssemblyNameReference name) return null; } - // open file as MemoryStream - // attempts multiple times, not sure why.. + // open file as MemoryStream. + // ILPostProcessor is multithreaded. + // retry a few times in case another thread is still accessing the file. static MemoryStream MemoryStreamFor(string fileName) { return Retry(10, TimeSpan.FromSeconds(1), () => diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs index 2c070cc..e8595fd 100644 --- a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs @@ -24,6 +24,7 @@ void Add(string message, DiagnosticType logType) public void LogDiagnostics(string message, DiagnosticType logType = DiagnosticType.Warning) { + // TODO IN-44868 FIX IS IN 2021.3.32f1, 2022.3.11f1, 2023.2.0b13 and 2023.3.0a8 // 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. diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs b/Assets/Mirror/Editor/Weaver/Extensions.cs index 9a5759a..566a51a 100644 --- a/Assets/Mirror/Editor/Weaver/Extensions.cs +++ b/Assets/Mirror/Editor/Weaver/Extensions.cs @@ -89,7 +89,10 @@ public static bool IsMultidimensionalArray(this TypeReference tr) => public static bool IsNetworkIdentityField(this TypeReference tr) => tr.Is() || tr.Is() || - tr.IsDerivedFrom(); + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + tr.IsDerivedFrom() || + tr.Is(); public static bool CanBeResolved(this TypeReference parent) { @@ -239,7 +242,16 @@ public static IEnumerable FindAllPublicFields(this TypeDefiniti { foreach (FieldDefinition field in typeDefinition.Fields) { - if (field.IsStatic || field.IsPrivate) + // ignore static, private, protected fields + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3485 + // credit: James Frowen + if (field.IsStatic || field.IsPrivate || field.IsFamily) + continue; + + // also ignore internal fields + // we dont want to create different writers for this type if they are in current dll or another dll + // so we have to ignore internal in all cases + if (field.IsAssembly) continue; if (field.IsNotSerialized) diff --git a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs index 55893f7..db2d5af 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs @@ -10,10 +10,11 @@ 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, channel); + NetworkWriterPooled writer = NetworkWriterPool.Get(); + writer.Write(thrusting); + writer.WritePackedUInt32((uint)spin); + base.SendCommandInternal(cmdName, cmdHash, writer, channel); + NetworkWriterPool.Return(writer); } public void CallCmdThrust(float thrusting, int spin) @@ -52,6 +53,11 @@ public static MethodDefinition ProcessCommandCall(WeaverTypes weaverTypes, Write worker.Emit(OpCodes.Ldarg_0); // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions worker.Emit(OpCodes.Ldstr, md.FullName); + // pass the function hash so we don't have to compute it at runtime + // otherwise each GetStableHash call requires O(N) complexity. + // noticeable for long function names: + // https://github.com/MirrorNetworking/Mirror/issues/3375 + worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode()); // writer worker.Emit(OpCodes.Ldloc_0); worker.Emit(OpCodes.Ldc_I4, channel); @@ -78,7 +84,7 @@ protected static void InvokeCmdCmdThrust(NetworkBehaviour obj, NetworkReader rea */ public static MethodDefinition ProcessCommandInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition method, MethodDefinition cmdCallFunc, ref bool WeavingFailed) { - string cmdName = Weaver.GenerateMethodName(Weaver.InvokeRpcPrefix, method); + string cmdName = Weaver.GenerateMethodName(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix, method); MethodDefinition cmd = new MethodDefinition(cmdName, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, diff --git a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs index 7c1b2c3..47f1b94 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs @@ -26,6 +26,9 @@ class NetworkBehaviourProcessor List syncObjects = new List(); // Dictionary syncVarNetIds = new Dictionary(); + // - Every syncvar with a hook has a new field created to store the Action delegate so we don't allocate on every hook invocation + // This dictionary maps each syncvar field to the field that will store the hook method delegate instance, and the method from which the delegate instance is constructed from + Dictionary syncVarHookDelegates = new Dictionary(); readonly List commands = new List(); readonly List clientRpcs = new List(); readonly List targetRpcs = new List(); @@ -71,7 +74,7 @@ public bool Process(ref bool WeavingFailed) MarkAsProcessed(netBehaviourSubclass); // deconstruct tuple and set fields - (syncVars, syncVarNetIds) = syncVarAttributeProcessor.ProcessSyncVars(netBehaviourSubclass, ref WeavingFailed); + (syncVars, syncVarNetIds, syncVarHookDelegates) = syncVarAttributeProcessor.ProcessSyncVars(netBehaviourSubclass, ref WeavingFailed); syncObjects = SyncObjectProcessor.FindSyncObjectsFields(writers, readers, Log, netBehaviourSubclass, ref WeavingFailed); @@ -205,20 +208,29 @@ public static bool WriteArguments(ILProcessor worker, Writers writers, Logger Lo } #region mark / check type as processed - public const string ProcessedFunctionName = "MirrorProcessed"; + public const string ProcessedFunctionName = "Weaved"; - // by adding an empty MirrorProcessed() function + // check if the type has a "Weaved" function already public static bool WasProcessed(TypeDefinition td) { return td.GetMethod(ProcessedFunctionName) != null; } + // add the Weaved() function which returns true. + // can be called at runtime and from tests to check if weaving succeeded. public void MarkAsProcessed(TypeDefinition td) { if (!WasProcessed(td)) { - MethodDefinition versionMethod = new MethodDefinition(ProcessedFunctionName, MethodAttributes.Private, weaverTypes.Import(typeof(void))); + // add a function: + // public override bool MirrorProcessed() { return true; } + // ReuseSlot means 'override'. + MethodDefinition versionMethod = new MethodDefinition( + ProcessedFunctionName, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot, + weaverTypes.Import(typeof(bool))); ILProcessor worker = versionMethod.Body.GetILProcessor(); + worker.Emit(OpCodes.Ldc_I4_1); worker.Emit(OpCodes.Ret); td.Methods.Add(versionMethod); } @@ -312,7 +324,7 @@ void InjectIntoStaticConstructor(ref bool WeavingFailed) // we need to inject several initializations into NetworkBehaviour ctor void InjectIntoInstanceConstructor(ref bool WeavingFailed) { - if (syncObjects.Count == 0) + if ((syncObjects.Count == 0) && (syncVarHookDelegates.Count == 0)) return; // find instance constructor @@ -340,6 +352,14 @@ void InjectIntoInstanceConstructor(ref bool WeavingFailed) SyncObjectInitializer.GenerateSyncObjectInitializer(ctorWorker, weaverTypes, fd); } + // initialize all delegate fields in ctor + foreach(KeyValuePair entry in syncVarHookDelegates) + { + FieldDefinition syncVarField = entry.Key; + (FieldDefinition hookDelegate, MethodDefinition hookMethod) = entry.Value; + syncVarAttributeProcessor.GenerateSyncVarHookDelegateInitializer(ctorWorker, syncVarField, hookDelegate, hookMethod); + } + // add final 'Ret' instruction to ctor ctorWorker.Append(ctorWorker.Create(OpCodes.Ret)); } @@ -443,7 +463,21 @@ void GenerateSerialization(ref bool WeavingFailed) // this worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldfld, syncVar); - MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + MethodReference writeFunc; + // For NBs we always need to use the default NetworkBehaviour write func + // since the reader counter part uses that exact layout which is not easy to change + // without introducing more edge cases + // effectively this disallows custom NB-type writers/readers on SyncVars + // see: https://github.com/MirrorNetworking/Mirror/issues/2680 + if (syncVar.FieldType.IsDerivedFrom()) + { + writeFunc = writers.GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + } + else + { + writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + } + if (writeFunc != null) { worker.Emit(OpCodes.Call, writeFunc); @@ -470,7 +504,7 @@ void GenerateSerialization(ref bool WeavingFailed) worker.Emit(OpCodes.Ldarg_1); // base worker.Emit(OpCodes.Ldarg_0); - worker.Emit(OpCodes.Call, weaverTypes.NetworkBehaviourDirtyBitsReference); + worker.Emit(OpCodes.Ldfld, weaverTypes.NetworkBehaviourDirtyBitsReference); MethodReference writeUint64Func = writers.GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); worker.Emit(OpCodes.Call, writeUint64Func); @@ -490,7 +524,7 @@ void GenerateSerialization(ref bool WeavingFailed) // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL) // base worker.Emit(OpCodes.Ldarg_0); - worker.Emit(OpCodes.Call, weaverTypes.NetworkBehaviourDirtyBitsReference); + worker.Emit(OpCodes.Ldfld, weaverTypes.NetworkBehaviourDirtyBitsReference); // 8 bytes = long worker.Emit(OpCodes.Ldc_I8, 1L << dirtyBit); worker.Emit(OpCodes.And); @@ -503,7 +537,21 @@ void GenerateSerialization(ref bool WeavingFailed) worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldfld, syncVar); - MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + MethodReference writeFunc; + // For NBs we always need to use the default NetworkBehaviour write func + // since the reader counter part uses that exact layout which is not easy to change + // without introducing more edge cases + // effectively this disallows custom NB-type writers/readers on SyncVars + // see: https://github.com/MirrorNetworking/Mirror/issues/2680 + if (syncVar.FieldType.IsDerivedFrom()) + { + writeFunc = writers.GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + } + else + { + writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + } + if (writeFunc != null) { worker.Emit(OpCodes.Call, writeFunc); @@ -545,15 +593,18 @@ void DeserializeField(FieldDefinition syncVar, ILProcessor worker, ref bool Weav worker.Emit(OpCodes.Ldflda, syncVar); } - // hook? then push 'new Action(Hook)' onto stack - MethodDefinition hookMethod = syncVarAttributeProcessor.GetHookMethod(netBehaviourSubclass, syncVar, ref WeavingFailed); - if (hookMethod != null) + // If a hook exists, then we need to load the hook delegate on the stack + // The hook delegate is created once in the constructor and stored in an instance field + // We load the delegate from this instance field to avoid instantiating a new delegate instance every time (drastically reduces allocations) + if(syncVarHookDelegates.TryGetValue(syncVar, out (FieldDefinition hookDelegateField, MethodDefinition) value)) { - syncVarAttributeProcessor.GenerateNewActionFromHookMethod(syncVar, worker, hookMethod); + // A hook exists. Push this.hookDelegateField onto the stack + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, value.hookDelegateField); } - // otherwise push 'null' as hook else { + // No hook exists. Push 'null' as hook worker.Emit(OpCodes.Ldnull); } @@ -582,10 +633,9 @@ void DeserializeField(FieldDefinition syncVar, ILProcessor worker, ref bool Weav worker.Emit(OpCodes.Ldflda, netIdField); worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_NetworkIdentity); } - // TODO this only uses the persistent netId for types DERIVED FROM NB. - // not if the type is just 'NetworkBehaviour'. - // this is what original implementation did too. fix it after. - else if (syncVar.FieldType.IsDerivedFrom()) + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (syncVar.FieldType.IsDerivedFrom() || syncVar.FieldType.Is()) { // reader worker.Emit(OpCodes.Ldarg_1); diff --git a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs index 280240c..58a19d8 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs @@ -1,4 +1,5 @@ // finds all readers and writers and register them +using System.Collections.Generic; using System.Linq; using Mono.CecilX; using Mono.CecilX.Cil; @@ -17,6 +18,21 @@ public static bool Process(AssemblyDefinition CurrentAssembly, IAssemblyResolver // otherwise Unity crashes when running tests ProcessMirrorAssemblyClasses(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed); + // process dependencies first, this way weaver can process types of other assemblies properly. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2503 + // + // find NetworkReader/Writer extensions in referenced assemblies + // save a copy of the collection enumerator since it appears to be modified at some point during iteration + IEnumerable assemblyReferences = CurrentAssembly.MainModule.AssemblyReferences.ToList(); + foreach (AssemblyNameReference assemblyNameReference in assemblyReferences) + { + AssemblyDefinition referencedAssembly = resolver.Resolve(assemblyNameReference); + if (referencedAssembly != null) + { + ProcessAssemblyClasses(CurrentAssembly, referencedAssembly, writers, readers, ref WeavingFailed); + } + } + // find readers/writers in the assembly we are in right now. return ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly, writers, readers, ref WeavingFailed); } diff --git a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs index df44f20..ca2d7b9 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs @@ -8,7 +8,7 @@ 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) { - string rpcName = Weaver.GenerateMethodName(Weaver.InvokeRpcPrefix, md); + string rpcName = Weaver.GenerateMethodName(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix, md); MethodDefinition rpc = new MethodDefinition(rpcName, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, weaverTypes.Import(typeof(void))); @@ -82,6 +82,11 @@ public static MethodDefinition ProcessRpcCall(WeaverTypes weaverTypes, Writers w worker.Emit(OpCodes.Ldarg_0); // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions worker.Emit(OpCodes.Ldstr, md.FullName); + // pass the function hash so we don't have to compute it at runtime + // otherwise each GetStableHash call requires O(N) complexity. + // noticeable for long function names: + // https://github.com/MirrorNetworking/Mirror/issues/3375 + worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode()); // writer worker.Emit(OpCodes.Ldloc_0); worker.Emit(OpCodes.Ldc_I4, channel); diff --git a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs index 50df598..a0b7739 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs @@ -25,7 +25,7 @@ static bool ProcessSiteMethod(WeaverTypes weaverTypes, Logger Log, MethodDefinit { if (md.Name == ".cctor" || md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || - md.Name.StartsWith(Weaver.InvokeRpcPrefix)) + md.Name.StartsWith(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix)) return false; if (md.IsAbstract) @@ -123,7 +123,16 @@ static void InjectGuardParameters(MethodDefinition md, ILProcessor worker, Instr ParameterDefinition param = md.Parameters[index]; if (param.IsOut) { - TypeReference elementType = param.ParameterType.GetElementType(); + // this causes IL2CPP build issues with generic out parameters: + // https://github.com/MirrorNetworking/Mirror/issues/3482 + // TypeReference elementType = param.ParameterType.GetElementType(); + // + // instead we need to use ElementType not GetElementType() + // GetElementType() will get the element type of the inner elementType + // which will return wrong type for arrays and generic + // credit: JamesFrowen + ByReferenceType byRefType = (ByReferenceType)param.ParameterType; + TypeReference elementType = byRefType.ElementType; md.Body.Variables.Add(new VariableDefinition(elementType)); md.Body.InitLocals = true; diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs index 0a6f376..73a9526 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs @@ -11,7 +11,7 @@ namespace Mirror.Weaver public static class SyncVarAttributeAccessReplacer { // process the module - public static void Process(ModuleDefinition moduleDef, SyncVarAccessLists syncVarAccessLists) + public static void Process(Logger Log, ModuleDefinition moduleDef, SyncVarAccessLists syncVarAccessLists) { DateTime startTime = DateTime.Now; @@ -20,31 +20,31 @@ public static void Process(ModuleDefinition moduleDef, SyncVarAccessLists syncVa { if (td.IsClass) { - ProcessClass(syncVarAccessLists, td); + ProcessClass(Log, syncVarAccessLists, td); } } Console.WriteLine($" ProcessSitesModule {moduleDef.Name} elapsed time:{(DateTime.Now - startTime)}"); } - static void ProcessClass(SyncVarAccessLists syncVarAccessLists, TypeDefinition td) + static void ProcessClass(Logger Log, SyncVarAccessLists syncVarAccessLists, TypeDefinition td) { //Console.WriteLine($" ProcessClass {td}"); // process all methods in this class foreach (MethodDefinition md in td.Methods) { - ProcessMethod(syncVarAccessLists, md); + ProcessMethod(Log, syncVarAccessLists, md); } // processes all nested classes in this class recursively foreach (TypeDefinition nested in td.NestedTypes) { - ProcessClass(syncVarAccessLists, nested); + ProcessClass(Log, syncVarAccessLists, nested); } } - static void ProcessMethod(SyncVarAccessLists syncVarAccessLists, MethodDefinition md) + static void ProcessMethod(Logger Log, SyncVarAccessLists syncVarAccessLists, MethodDefinition md) { // process all references to replaced members with properties //Log.Warning($" ProcessSiteMethod {md}"); @@ -52,7 +52,7 @@ static void ProcessMethod(SyncVarAccessLists syncVarAccessLists, MethodDefinitio // skip static constructor, "MirrorProcessed", "InvokeUserCode_" if (md.Name == ".cctor" || md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || - md.Name.StartsWith(Weaver.InvokeRpcPrefix)) + md.Name.StartsWith(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix)) return; // skip abstract @@ -67,32 +67,64 @@ static void ProcessMethod(SyncVarAccessLists syncVarAccessLists, MethodDefinitio for (int i = 0; i < md.Body.Instructions.Count;) { Instruction instr = md.Body.Instructions[i]; - i += ProcessInstruction(syncVarAccessLists, md, instr, i); + i += ProcessInstruction(Log, syncVarAccessLists, md, instr, i); } } } - static int ProcessInstruction(SyncVarAccessLists syncVarAccessLists, MethodDefinition md, Instruction instr, int iCount) + static int ProcessInstruction(Logger Log, SyncVarAccessLists syncVarAccessLists, MethodDefinition md, Instruction instr, int iCount) { // stfld (sets value of a field)? - if (instr.OpCode == OpCodes.Stfld && instr.Operand is FieldDefinition opFieldst) + if (instr.OpCode == OpCodes.Stfld) { - ProcessSetInstruction(syncVarAccessLists, md, instr, opFieldst); + // operand is a FieldDefinition in the same assembly? + if (instr.Operand is FieldDefinition opFieldst) + { + ProcessSetInstruction(syncVarAccessLists, md, instr, opFieldst); + } + // operand is a FieldReference in another assembly? + // this is not supported just yet. + // compilation error is better than silently failing SyncVar serialization at runtime. + // https://github.com/MirrorNetworking/Mirror/issues/3525 + else if (instr.Operand is FieldReference opFieldstRef) + { + // resolve it from the other assembly + FieldDefinition field = opFieldstRef.Resolve(); + + // [SyncVar]? + if (field.HasCustomAttribute()) + { + // ILPostProcessor would need to Process() the assembly's + // references before processing this one. + // we can not control the order. + // instead, Log an error to suggest adding a SetSyncVar(value) function. + // this is a very easy solution for a very rare edge case. + Log.Error($"'[SyncVar] {opFieldstRef.DeclaringType.Name}.{opFieldstRef.Name}' in '{field.Module.Name}' is modified by '{md.FullName}' in '{md.Module.Name}'. Modifying a [SyncVar] from another assembly is not supported. Please add a: 'public void Set{opFieldstRef.Name}(value) {{ this.{opFieldstRef.Name} = value; }}' method in '{opFieldstRef.DeclaringType.Name}' and call this function from '{md.FullName}' instead."); + } + } } // ldfld (load value of a field)? - if (instr.OpCode == OpCodes.Ldfld && instr.Operand is FieldDefinition opFieldld) + if (instr.OpCode == OpCodes.Ldfld) { - // this instruction gets the value of a field. cache the field reference. - ProcessGetInstruction(syncVarAccessLists, md, instr, opFieldld); + // operand is a FieldDefinition in the same assembly? + if (instr.Operand is FieldDefinition opFieldld) + { + // this instruction gets the value of a field. cache the field reference. + ProcessGetInstruction(syncVarAccessLists, md, instr, opFieldld); + } } // ldflda (load field address aka reference) - if (instr.OpCode == OpCodes.Ldflda && instr.Operand is FieldDefinition opFieldlda) + if (instr.OpCode == OpCodes.Ldflda) { - // watch out for initobj instruction - // see https://github.com/vis2k/Mirror/issues/696 - return ProcessLoadAddressInstruction(syncVarAccessLists, md, instr, opFieldlda, iCount); + // operand is a FieldDefinition in the same assembly? + if (instr.Operand is FieldDefinition opFieldlda) + { + // watch out for initobj instruction + // see https://github.com/vis2k/Mirror/issues/696 + return ProcessLoadAddressInstruction(syncVarAccessLists, md, instr, opFieldlda, iCount); + } } // we processed one instruction (instr) diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs index ee33de3..76e3ac7 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs @@ -46,15 +46,26 @@ public MethodDefinition GetHookMethod(TypeDefinition td, FieldDefinition syncVar return FindHookMethod(td, syncVar, hookFunctionName, ref WeavingFailed); } + // Create a field definition for a field that will store the Action delegate instance for the syncvar hook method (only instantiate delegate once) + public FieldDefinition CreateNewActionFieldDefinitionFromHookMethod(FieldDefinition syncVarField) + { + TypeReference actionRef = assembly.MainModule.ImportReference(typeof(Action<,>)); + GenericInstanceType syncVarHookActionDelegateType = actionRef.MakeGenericInstanceType(syncVarField.FieldType, syncVarField.FieldType); + string syncVarHookDelegateFieldName = $"_Mirror_SyncVarHookDelegate_{syncVarField.Name}"; + return new FieldDefinition(syncVarHookDelegateFieldName, FieldAttributes.Public, syncVarHookActionDelegateType); + } + // push hook from GetHookMethod() onto the stack as a new Action. // allows for reuse without handling static/virtual cases every time. + // perf warning: it is recommended to use this method only when generating IL to create a new Action() in order to store it into a field + // avoid using this to emit IL to instantiate a new action instance every single time one is needed for the same method public void GenerateNewActionFromHookMethod(FieldDefinition syncVar, ILProcessor worker, MethodDefinition hookMethod) { // IL_000a: ldarg.0 // IL_000b: ldftn instance void Mirror.Examples.Tanks.Tank::ExampleHook(int32, int32) // IL_0011: newobj instance void class [netstandard]System.Action`2::.ctor(object, native int) - // we support static hook sand instance hooks. + // we support static hooks and instance hooks. if (hookMethod.IsStatic) { // for static hooks, we need to push 'null' first. @@ -95,15 +106,23 @@ public void GenerateNewActionFromHookMethod(FieldDefinition syncVar, ILProcessor // call 'new Action()' constructor to convert the function to an action // we need to make an instance of the generic Action. - // - // TODO this allocates a new 'Action' for every SyncVar hook call. - // we should allocate it once and store it somewhere in the future. - // hooks are only called on the client though, so it's not too bad for now. TypeReference actionRef = assembly.MainModule.ImportReference(typeof(Action<,>)); GenericInstanceType genericInstance = actionRef.MakeGenericInstanceType(syncVar.FieldType, syncVar.FieldType); worker.Emit(OpCodes.Newobj, weaverTypes.ActionT_T.MakeHostInstanceGeneric(assembly.MainModule, genericInstance)); } + // generates CIL to set an Action instance field to a new Action(hookMethod) + // this.hookDelegate = new Action(HookMethod); + public void GenerateSyncVarHookDelegateInitializer(ILProcessor worker, FieldDefinition syncVar, FieldDefinition hookDelegate, MethodDefinition hookMethod) + { + // push this + worker.Emit(OpCodes.Ldarg_0); + // push new Action(hookMethod) + GenerateNewActionFromHookMethod(syncVar, worker, hookMethod); + // set field + worker.Emit(OpCodes.Stfld, hookDelegate); + } + MethodDefinition FindHookMethod(TypeDefinition td, FieldDefinition syncVar, string hookFunctionName, ref bool WeavingFailed) { List methods = td.GetMethods(hookFunctionName); @@ -203,7 +222,9 @@ public MethodDefinition GenerateSyncVarGetter(FieldDefinition fd, string origina worker.Emit(OpCodes.Call, weaverTypes.getSyncVarNetworkIdentityReference); worker.Emit(OpCodes.Ret); } - else if (fd.FieldType.IsDerivedFrom()) + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (fd.FieldType.IsDerivedFrom() || fd.FieldType.Is()) { // return this.GetSyncVarNetworkBehaviour(ref field, uint netId); // this. @@ -240,7 +261,7 @@ public MethodDefinition GenerateSyncVarGetter(FieldDefinition fd, string origina // } // // the setter used to be manually IL generated, but we moved it to C# :) - public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId, ref bool WeavingFailed) + public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId, Dictionary syncVarHookDelegates, ref bool WeavingFailed) { //Create the set method MethodDefinition set = new MethodDefinition($"set_Network{originalName}", MethodAttributes.Public | @@ -302,11 +323,17 @@ public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition // push the dirty bit for this SyncVar worker.Emit(OpCodes.Ldc_I8, dirtyBit); - // hook? then push 'new Action(Hook)' onto stack + // hook? then push 'this.HookDelegate' onto stack MethodDefinition hookMethod = GetHookMethod(td, fd, ref WeavingFailed); if (hookMethod != null) { - GenerateNewActionFromHookMethod(fd, worker, hookMethod); + // Create the field that will store a single instance of the hook as a delegate (field will be set in constructor) + FieldDefinition hookActionDelegateField = CreateNewActionFieldDefinitionFromHookMethod(fd); + syncVarHookDelegates[fd] = (hookActionDelegateField, hookMethod); + + // push this.hookActionDelegateField + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, hookActionDelegateField); } // otherwise push 'null' as hook else @@ -331,10 +358,9 @@ public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition worker.Emit(OpCodes.Ldflda, netIdFieldReference); worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_NetworkIdentity); } - // TODO this only uses the persistent netId for types DERIVED FROM NB. - // not if the type is just 'NetworkBehaviour'. - // this is what original implementation did too. fix it after. - else if (fd.FieldType.IsDerivedFrom()) + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (fd.FieldType.IsDerivedFrom() || fd.FieldType.Is()) { // NetworkIdentity setter needs one more parameter: netId field ref // (actually its a NetworkBehaviourSyncVar type) @@ -361,14 +387,16 @@ public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition return set; } - public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary syncVarNetIds, long dirtyBit, ref bool WeavingFailed) + public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary syncVarNetIds, Dictionary syncVarHookDelegates, 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()) + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + if (fd.FieldType.IsDerivedFrom() || fd.FieldType.Is()) { netIdField = new FieldDefinition($"___{fd.Name}NetId", FieldAttributes.Family, // needs to be protected for generic classes, otherwise access isn't allowed @@ -388,7 +416,7 @@ public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary syncVars, Dictionary syncVarNetIds) ProcessSyncVars(TypeDefinition td, ref bool WeavingFailed) + public (List syncVars, Dictionary syncVarNetIds, Dictionary syncVarHookDelegates) ProcessSyncVars(TypeDefinition td, ref bool WeavingFailed) { List syncVars = new List(); Dictionary syncVarNetIds = new Dictionary(); + Dictionary syncVarHookDelegates = 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 @@ -442,13 +471,6 @@ public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary SyncVarLimit) @@ -475,9 +497,19 @@ public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary fields + foreach((FieldDefinition hookDelegateInstanceField, MethodDefinition) entry in syncVarHookDelegates.Values) + { + td.Fields.Add(entry.hookDelegateInstanceField); + } + + // include parent class syncvars + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3457 + int parentSyncVarCount = syncVarAccessLists.GetSyncVarStart(td.BaseType.FullName); + syncVarAccessLists.SetNumSyncVars(td.FullName, parentSyncVarCount + syncVars.Count); + + return (syncVars, syncVarNetIds, syncVarHookDelegates); } } } diff --git a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs index 757aa44..8d56040 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs @@ -23,7 +23,7 @@ public static bool HasNetworkConnectionParameter(MethodDefinition md) public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed) { - string trgName = Weaver.GenerateMethodName(Weaver.InvokeRpcPrefix, md); + string trgName = Weaver.GenerateMethodName(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix, md); MethodDefinition rpc = new MethodDefinition(trgName, MethodAttributes.Family | MethodAttributes.Static | @@ -42,16 +42,25 @@ public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, R // 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 + // TargetRpcs are sent from server to client. + // on server, we currently support two types: + // TargetRpc(NetworkConnection) + // TargetRpc(NetworkConnectionToClient) + // however, it's always a connection to client. + // in the future, only NetworkConnectionToClient will be supported. + // explicit typing helps catch issues at compile time. // - // TODO - // a) .connectionToServer = best solution. no doubt. - // b) NetworkClient.connection for now. add TODO to not use static later. - worker.Emit(OpCodes.Call, weaverTypes.NetworkClientConnectionReference); + // on client, InvokeTargetRpc calls the original code. + // we need to fill in the NetworkConnection parameter. + // NetworkClient.connection is always a connection to server. + // + // we used to pass NetworkClient.connection as the TargetRpc parameter. + // which caused: https://github.com/MirrorNetworking/Mirror/issues/3455 + // when the parameter is defined as a NetworkConnectionToClient. + // + // a client's connection never fits into a NetworkConnectionToClient. + // we need to always pass null here. + worker.Emit(OpCodes.Ldnull); } // process reader parameters and skip first one if first one is NetworkConnection @@ -130,6 +139,11 @@ public static MethodDefinition ProcessTargetRpcCall(WeaverTypes weaverTypes, Wri } // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions worker.Emit(OpCodes.Ldstr, md.FullName); + // pass the function hash so we don't have to compute it at runtime + // otherwise each GetStableHash call requires O(N) complexity. + // noticeable for long function names: + // https://github.com/MirrorNetworking/Mirror/issues/3375 + worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode()); // writer worker.Emit(OpCodes.Ldloc_0); worker.Emit(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0)); diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs b/Assets/Mirror/Editor/Weaver/Readers.cs index fa888c9..33941d9 100644 --- a/Assets/Mirror/Editor/Weaver/Readers.cs +++ b/Assets/Mirror/Editor/Weaver/Readers.cs @@ -113,7 +113,9 @@ MethodReference GenerateReader(TypeReference variableReference, ref bool Weaving return GenerateReadCollection(variableReference, elementType, nameof(NetworkReaderExtensions.ReadList), ref WeavingFailed); } - else if (variableReference.IsDerivedFrom()) + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (variableReference.IsDerivedFrom() || variableReference.Is()) { return GetNetworkBehaviourReader(variableReference); } diff --git a/Assets/Mirror/Editor/Weaver/Resolvers.cs b/Assets/Mirror/Editor/Weaver/Resolvers.cs index a9d551b..0af32ca 100644 --- a/Assets/Mirror/Editor/Weaver/Resolvers.cs +++ b/Assets/Mirror/Editor/Weaver/Resolvers.cs @@ -42,6 +42,38 @@ public static MethodReference ResolveMethod(TypeReference t, AssemblyDefinition return null; } + public static FieldReference ResolveField(TypeReference tr, AssemblyDefinition assembly, Logger Log, string name, ref bool WeavingFailed) + { + if (tr == null) + { + Log.Error($"Cannot resolve Field {name} without a class"); + WeavingFailed = true; + return null; + } + FieldReference field = ResolveField(tr, assembly, Log, m => m.Name == name, ref WeavingFailed); + if (field == null) + { + Log.Error($"Field not found with name {name} in type {tr.Name}", tr); + WeavingFailed = true; + } + return field; + } + + public static FieldReference ResolveField(TypeReference t, AssemblyDefinition assembly, Logger Log, System.Func predicate, ref bool WeavingFailed) + { + foreach (FieldDefinition fieldRef in t.Resolve().Fields) + { + if (predicate(fieldRef)) + { + return assembly.MainModule.ImportReference(fieldRef); + } + } + + Log.Error($"Field not found in type {t.Name}", t); + WeavingFailed = true; + return null; + } + public static MethodReference TryResolveMethodInParents(TypeReference tr, AssemblyDefinition assembly, string name) { if (tr == null) diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs b/Assets/Mirror/Editor/Weaver/Weaver.cs index 2644e68..3aef7b8 100644 --- a/Assets/Mirror/Editor/Weaver/Weaver.cs +++ b/Assets/Mirror/Editor/Weaver/Weaver.cs @@ -2,14 +2,14 @@ using System.Collections.Generic; using System.Diagnostics; using Mono.CecilX; +using Mono.CecilX.Cil; +using Mono.CecilX.Rocks; 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"; @@ -118,7 +118,17 @@ bool WeaveModule(ModuleDefinition moduleDefinition) Stopwatch watch = Stopwatch.StartNew(); watch.Start(); - foreach (TypeDefinition td in moduleDefinition.Types) + // ModuleDefinition.Types only finds top level types. + // GetAllTypes recursively finds all nested types as well. + // fixes nested types not being weaved, for example: + // class Parent { // ModuleDefinition.Types finds this + // class Child { // .Types.NestedTypes finds this + // class GrandChild {} // only GetAllTypes finds this too + // } + // } + // note this is not about inheritance, only about type definitions. + // see test: NetworkBehaviourTests.DeeplyNested() + foreach (TypeDefinition td in moduleDefinition.GetAllTypes()) { if (td.IsClass && td.BaseType.CanBeResolved()) { @@ -142,6 +152,16 @@ void CreateGeneratedCodeClass() weaverTypes.Import()); } + void ToggleWeaverFuse() + { + // // find Weaved() function + MethodDefinition func = weaverTypes.weaverFuseMethod.Resolve(); + // // change return 0 to return 1 + + ILProcessor worker = func.Body.GetILProcessor(); + func.Body.Instructions[0] = worker.Create(OpCodes.Ldc_I4_1); + } + // Weave takes an AssemblyDefinition to be compatible with both old and // new weavers: // * old takes a filepath, new takes a in-memory byte[] @@ -214,7 +234,7 @@ public bool Weave(AssemblyDefinition assembly, IAssemblyResolver resolver, out b if (modified) { - SyncVarAttributeAccessReplacer.Process(moduleDefinition, syncVarAccessLists); + SyncVarAttributeAccessReplacer.Process(Log, moduleDefinition, syncVarAccessLists); // add class that holds read/write functions moduleDefinition.Types.Add(GeneratedCodeClass); @@ -228,6 +248,12 @@ public bool Weave(AssemblyDefinition assembly, IAssemblyResolver resolver, out b //CurrentAssembly.Write(new WriterParameters{ WriteSymbols = true }); } + // if weaving succeeded, switch on the Weaver Fuse in Mirror.dll + if (CurrentAssembly.Name.Name == MirrorAssemblyName) + { + ToggleWeaverFuse(); + } + return true; } catch (Exception e) diff --git a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs index 173af58..aa0d42d 100644 --- a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs +++ b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs @@ -10,7 +10,7 @@ public class WeaverTypes { public MethodReference ScriptableObjectCreateInstanceMethod; - public MethodReference NetworkBehaviourDirtyBitsReference; + public FieldReference NetworkBehaviourDirtyBitsReference; public MethodReference GetWriterReference; public MethodReference ReturnWriterReference; @@ -53,6 +53,9 @@ public class WeaverTypes public MethodReference readNetworkBehaviourGeneric; + public TypeReference weaverFuseType; + public MethodReference weaverFuseMethod; + // attributes public TypeDefinition initializeOnLoadMethodAttribute; public TypeDefinition runtimeInitializeOnLoadMethodAttribute; @@ -75,30 +78,19 @@ public WeaverTypes(AssemblyDefinition assembly, Logger Log, ref bool WeavingFail TypeReference ActionType = Import(typeof(Action<,>)); ActionT_T = Resolvers.ResolveMethod(ActionType, assembly, Log, ".ctor", ref WeavingFailed); + weaverFuseType = Import(typeof(WeaverFuse)); + weaverFuseMethod = Resolvers.ResolveMethod(weaverFuseType, assembly, Log, "Weaved", ref WeavingFailed); + TypeReference NetworkServerType = Import(typeof(NetworkServer)); NetworkServerGetActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_active", ref WeavingFailed); + TypeReference NetworkClientType = Import(typeof(NetworkClient)); NetworkClientGetActive = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_active", ref WeavingFailed); - - TypeReference RemoteCallDelegateType = Import(); - RemoteCallDelegateConstructor = Resolvers.ResolveMethod(RemoteCallDelegateType, assembly, Log, ".ctor", ref WeavingFailed); + NetworkClientConnectionReference = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_connection", ref WeavingFailed); TypeReference NetworkBehaviourType = Import(); - TypeReference RemoteProcedureCallsType = Import(typeof(RemoteCalls.RemoteProcedureCalls)); - - 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)); - GetWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Get", ref WeavingFailed); - ReturnWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Return", ref WeavingFailed); - - NetworkClientConnectionReference = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_connection", ref WeavingFailed); + NetworkBehaviourDirtyBitsReference = Resolvers.ResolveField(NetworkBehaviourType, assembly, Log, "syncVarDirtyBits", ref WeavingFailed); generatedSyncVarSetter = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter", ref WeavingFailed); generatedSyncVarSetter_GameObject = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_GameObject", ref WeavingFailed); @@ -114,9 +106,25 @@ public WeaverTypes(AssemblyDefinition assembly, Logger Log, ref bool WeavingFail getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkIdentity", ref WeavingFailed); getSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkBehaviour", 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 RemoteProcedureCallsType = Import(typeof(RemoteCalls.RemoteProcedureCalls)); registerCommandReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterCommand", ref WeavingFailed); registerRpcReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterRpc", ref WeavingFailed); + TypeReference RemoteCallDelegateType = Import(); + RemoteCallDelegateConstructor = Resolvers.ResolveMethod(RemoteCallDelegateType, assembly, Log, ".ctor", ref WeavingFailed); + + TypeReference ScriptableObjectType = Import(); + ScriptableObjectCreateInstanceMethod = Resolvers.ResolveMethod( + ScriptableObjectType, assembly, Log, + md => md.Name == "CreateInstance" && md.HasGenericParameters, + 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 => @@ -133,11 +141,10 @@ public WeaverTypes(AssemblyDefinition assembly, Logger Log, ref bool WeavingFail 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 NetworkWriterPoolType = Import(typeof(NetworkWriterPool)); + GetWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Get", ref WeavingFailed); + ReturnWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Return", ref WeavingFailed); TypeReference readerExtensions = Import(typeof(NetworkReaderExtensions)); readNetworkBehaviourGeneric = Resolvers.ResolveMethod(readerExtensions, assembly, Log, (md => diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs b/Assets/Mirror/Editor/Weaver/Writers.cs index 51d514e..8311a26 100644 --- a/Assets/Mirror/Editor/Weaver/Writers.cs +++ b/Assets/Mirror/Editor/Weaver/Writers.cs @@ -115,7 +115,9 @@ MethodReference GenerateWriter(TypeReference variableReference, ref bool Weaving return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteList), ref WeavingFailed); } - if (variableReference.IsDerivedFrom()) + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + if (variableReference.IsDerivedFrom() || variableReference.Is()) { return GetNetworkBehaviourWriter(variableReference); } diff --git a/Assets/Mirror/Examples.meta b/Assets/Mirror/Examples.meta deleted file mode 100644 index b594a81..0000000 --- a/Assets/Mirror/Examples.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a08b1f591326642d1b140fc818c9c6b1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels.meta b/Assets/Mirror/Examples/AdditiveLevels.meta deleted file mode 100644 index d8d6382..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c2da9e7acc6ad1648b0ff0849ef4c283 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials.meta deleted file mode 100644 index 7a5d3cd..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 60c31680133898d43822d2d9eae56494 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat deleted file mode 100644 index 6531132..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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: CubeSphere - 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/AdditiveLevels/Materials/Ground.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat deleted file mode 100644 index 7dd07ac..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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: Ground - 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: 0.027055884, g: 0.09279272, b: 0.3018868, a: 1} - - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat deleted file mode 100644 index a394fe1..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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/AdditiveLevels/Materials/Portal.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat deleted file mode 100644 index f0d5fce..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat +++ /dev/null @@ -1,78 +0,0 @@ -%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: Portal - 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: 1 - - _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.54901963, g: 0.54901963, b: 1, a: 0.23529412} - - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat deleted file mode 100644 index 7d59ae9..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat +++ /dev/null @@ -1,104 +0,0 @@ -%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: Skybox - m_Shader: {fileID: 104, 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: - - _BackTex: - m_Texture: {fileID: 2800000, guid: 1566af6e663684dbd85aa5fb32fd9148, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _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} - - _DownTex: - m_Texture: {fileID: 2800000, guid: 9ffeeee1accdc4b4faf2b3e27b226340, type: 3} - 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} - - _FrontTex: - m_Texture: {fileID: 2800000, guid: ca928ef0e269448ba82388eb41d48544, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _LeftTex: - m_Texture: {fileID: 2800000, guid: e5a0eeef6a2514a78b267405d686fe09, type: 3} - 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} - - _RightTex: - m_Texture: {fileID: 2800000, guid: 4c8911efa34c845f28fbac86385a1b41, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _UpTex: - m_Texture: {fileID: 2800000, guid: bd9ad886b003944169e7ce1286756940, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - m_Floats: - - _BumpScale: 1 - - _Cutoff: 0.5 - - _DetailNormalMapScale: 1 - - _DstBlend: 0 - - _Exposure: 1 - - _GlossMapScale: 1 - - _Glossiness: 0.5 - - _GlossyReflections: 1 - - _Metallic: 0 - - _Mode: 0 - - _OcclusionStrength: 1 - - _Parallax: 0.02 - - _Rotation: 0 - - _SmoothnessTextureChannel: 0 - - _SpecularHighlights: 1 - - _SrcBlend: 1 - - _UVSec: 0 - - _ZWrite: 1 - m_Colors: - - _Color: {r: 1, g: 1, b: 1, a: 1} - - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - - _Tint: {r: 0.5, g: 0.5, b: 0.5, a: 0.5} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta deleted file mode 100644 index 53c5d15..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 81f714daf7144784b8a2f42f1cd30927 -timeCreated: 1497127647 -licenseType: Store -NativeFormatImporter: - mainObjectFileID: 2100000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta deleted file mode 100644 index 5f7c126..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ec3b6ac9651c31248bcfbf695e6f597a -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 2100000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta deleted file mode 100644 index 0bb6a54..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d9d4b9adc9613a04fb715c64d3d2dcf8 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab deleted file mode 100644 index 45456a0..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab +++ /dev/null @@ -1,136 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &3181899219042528418 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 3181899219042528419} - - component: {fileID: 3181899219042528430} - - component: {fileID: 3181899219042528417} - - component: {fileID: 3181899219042528416} - - component: {fileID: -1828993248307539358} - - component: {fileID: 96969086124788804} - m_Layer: 0 - m_Name: Cube - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &3181899219042528419 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3181899219042528418} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0.5, 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 &3181899219042528430 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3181899219042528418} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &3181899219042528417 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3181899219042528418} - 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: 38950807c6bf6454dbef567827b770b6, 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: 1 - 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!65 &3181899219042528416 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3181899219042528418} - 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!114 &-1828993248307539358 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3181899219042528418} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 0 - _assetId: 2131474587 - serverOnly: 0 - visible: 0 - hasSpawned: 0 ---- !u!114 &96969086124788804 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3181899219042528418} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - color: - serializedVersion: 2 - rgba: 4278190080 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta deleted file mode 100644 index e5705b1..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7c6a0a278eba11e44b9a86cd4da603df -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab deleted file mode 100644 index 73af6db..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab +++ /dev/null @@ -1,156 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &7349408984269008055 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7349408984269008052} - - component: {fileID: 7349408984269008059} - - component: {fileID: 7349408984269008058} - - component: {fileID: 7349408984269008053} - - component: {fileID: 7349408984269008063} - - component: {fileID: 7349408984269008062} - - component: {fileID: 7349408984269008057} - - component: {fileID: 7349408984269008056} - m_Layer: 0 - m_Name: Plane - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &7349408984269008052 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 50, y: 1, z: 50} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &7349408984269008059 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &7349408984269008058 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - 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: 20d755ab53045e545ab0b6e59c710ed9, 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: 1 - 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!64 &7349408984269008053 -MeshCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - 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!65 &7349408984269008063 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 20, z: 0.05} - m_Center: {x: 0, y: 10, z: -0.5} ---- !u!65 &7349408984269008062 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 0.05, y: 20, z: 1} - m_Center: {x: -0.5, y: 10, z: 0} ---- !u!65 &7349408984269008057 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 0.05, y: 20, z: 1} - m_Center: {x: 0.5, y: 10, z: 0} ---- !u!65 &7349408984269008056 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7349408984269008055} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 20, z: 0.05} - m_Center: {x: 0, y: 10, z: 0.5} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta deleted file mode 100644 index 98f04d3..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4fdcc4aa5c669b348a5954a92f5e8e89 -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab deleted file mode 100644 index e7a8354..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab +++ /dev/null @@ -1,367 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &1724664263041697580 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7513987664611104733} - - component: {fileID: 3866048407219963700} - - component: {fileID: 6667391912482377964} - m_Layer: 0 - m_Name: Visor - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &7513987664611104733 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1724664263041697580} - 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 962190737825349125} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &3866048407219963700 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1724664263041697580} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &6667391912482377964 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1724664263041697580} - 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: 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 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!1 &5620029719931856626 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 962190737825349125} - - component: {fileID: 8168211270351413936} - - component: {fileID: 5601443051240418659} - m_Layer: 0 - m_Name: Capsule - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &962190737825349125 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5620029719931856626} - 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: - - {fileID: 7513987664611104733} - m_Father: {fileID: 464867598898769114} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &8168211270351413936 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5620029719931856626} - m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &5601443051240418659 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5620029719931856626} - 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: 6b7039502d1528a4db29c4d43d159b01, 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: 1 - 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!1 &7619140271685878370 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 464867598898769114} - - component: {fileID: 5674344380471455553} - - component: {fileID: -4914236621144254103} - - component: {fileID: -903079073849018483} - - component: {fileID: -1734969889957956087} - - component: {fileID: 5462452979215896872} - - component: {fileID: -2422551836510166228} - - component: {fileID: 1763152038191860132} - - component: {fileID: 1747637013460943425} - m_Layer: 0 - m_Name: Player - m_TagString: Player - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &464867598898769114 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1.08, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 962190737825349125} - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &5674344380471455553 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 0 - _assetId: 1702147074 - serverOnly: 0 - visible: 0 - hasSpawned: 0 ---- !u!114 &-4914236621144254103 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 1 - syncMode: 0 - syncInterval: 0 - target: {fileID: 464867598898769114} - clientAuthority: 0 - syncPosition: 1 - syncRotation: 1 - syncScale: 0 - showGizmos: 0 - showOverlay: 0 - overlayColor: {r: 0, g: 0, b: 0, a: 0.5} - onlySyncOnChange: 1 - bufferResetMultiplier: 5 - positionSensitivity: 0.01 - rotationSensitivity: 0.01 - scaleSensitivity: 0.01 ---- !u!114 &-903079073849018483 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 22976424f775a0f4a8531e6713ff6de2, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 ---- !u!114 &-1734969889957956087 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - m_Enabled: 0 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 05e10150710dde14b83d3c8f5aa853c2, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - characterController: {fileID: 5462452979215896872} - controlsCanvas: {fileID: 0} - moveSpeedMultiplier: 8 - maxTurnSpeed: 100 - turnDelta: 3 - initialJumpSpeed: 0.2 - maxJumpSpeed: 5 - jumpDelta: 0.2 - groundState: 2 - horizontal: 0 - vertical: 0 - turnSpeed: 0 - jumpSpeed: 0 - animVelocity: 0 - animRotation: 0 - velocity: {x: 0, y: 0, z: 0} - direction: {x: 0, y: 0, z: 0} ---- !u!143 &5462452979215896872 -CharacterController: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - 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.02 - m_MinMoveDistance: 0 - m_Center: {x: 0, y: 0, z: 0} ---- !u!136 &-2422551836510166228 -CapsuleCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - 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!54 &1763152038191860132 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 1 - m_IsKinematic: 1 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 ---- !u!114 &1747637013460943425 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7619140271685878370} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - color: - serializedVersion: 2 - rgba: 4278190080 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab.meta deleted file mode 100644 index 9ec1c9e..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Player.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 9f0094c1325091d42a558274b947221f -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab deleted file mode 100644 index c94867a..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab +++ /dev/null @@ -1,254 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &1098173225717622925 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1098173225717622921} - - component: {fileID: 1098173225717622922} - - component: {fileID: 1098173225717622923} - - component: {fileID: 1098173225717622924} - - component: {fileID: 3141292696673982546} - - component: {fileID: 5948271423698091598} - m_Layer: 0 - m_Name: Portal - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1098173225717622921 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1098173225717622925} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: 0} - m_LocalScale: {x: 2, y: 2, z: 2} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1355348187805494562} - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &1098173225717622922 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1098173225717622925} - m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &1098173225717622923 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1098173225717622925} - m_Enabled: 1 - m_CastShadows: 0 - 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: 3500dce637708024da2f2e45e4f71cd3, 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: 1 - 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!136 &1098173225717622924 -CapsuleCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1098173225717622925} - m_Material: {fileID: 0} - m_IsTrigger: 1 - m_Enabled: 1 - m_Radius: 0.2 - m_Height: 1 - m_Direction: 1 - m_Center: {x: 0, y: 0, z: 0} ---- !u!114 &3141292696673982546 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1098173225717622925} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 0 - _assetId: 1770499856 - serverOnly: 0 - visible: 0 - hasSpawned: 0 ---- !u!114 &5948271423698091598 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1098173225717622925} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0e680878006965146a8f9d85834c4d1c, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - destinationScene: - startPosition: {x: 0, y: 0, z: 0} - label: {fileID: 8197110483235692531} - labelText: ---- !u!1 &5961932215084527574 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1355348187805494562} - - component: {fileID: 5428053421152709616} - - component: {fileID: 3243959486819493908} - - component: {fileID: 8197110483235692531} - m_Layer: 9 - m_Name: Label_TMP - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1355348187805494562 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5961932215084527574} - 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: 1098173225717622921} - 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: 1.5} - m_SizeDelta: {x: 20, y: 5} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!23 &5428053421152709616 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5961932215084527574} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - 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: 10100, guid: 0000000000000000e000000000000000, 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: 1 - 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 &3243959486819493908 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5961932215084527574} - m_Enabled: 0 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: cc58300ee45438a418d9e32957fdc0c0, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!102 &8197110483235692531 -TextMesh: - serializedVersion: 3 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5961932215084527574} - m_Text: - m_OffsetZ: 0 - m_CharacterSize: 0.05 - m_LineSpacing: 1 - m_Anchor: 4 - m_Alignment: 1 - m_TabSize: 4 - m_FontSize: 100 - m_FontStyle: 0 - m_RichText: 1 - m_Font: {fileID: 0} - m_Color: - serializedVersion: 2 - rgba: 4294967295 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta deleted file mode 100644 index d43ce42..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c624c75494b4d7d4086b9212f897e56a -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab deleted file mode 100644 index ab1abd4..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab +++ /dev/null @@ -1,136 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &2188792038427236743 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2188792038427236742} - - component: {fileID: 2188792038427236747} - - component: {fileID: 2188792038427236744} - - component: {fileID: 2188792038427236745} - - component: {fileID: -5172514306435102607} - - component: {fileID: 1758063572567377699} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &2188792038427236742 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2188792038427236743} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0.5, 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 &2188792038427236747 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2188792038427236743} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &2188792038427236744 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2188792038427236743} - 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: 38950807c6bf6454dbef567827b770b6, 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: 1 - 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!135 &2188792038427236745 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2188792038427236743} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!114 &-5172514306435102607 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2188792038427236743} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 0 - _assetId: 3918015202 - serverOnly: 0 - visible: 0 - hasSpawned: 0 ---- !u!114 &1758063572567377699 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2188792038427236743} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - color: - serializedVersion: 2 - rgba: 4278190080 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta deleted file mode 100644 index 95d16da..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e588080aa542be54d9ca9d5c734dc9ee -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab deleted file mode 100644 index c70961b..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab +++ /dev/null @@ -1,85 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &7582855647636897216 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7582855647636897223} - - component: {fileID: 7582855647636897221} - - component: {fileID: 7582855647636897222} - m_Layer: 0 - m_Name: StartPoint - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &7582855647636897223 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7582855647636897216} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 2, y: 0.05, z: 2} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &7582855647636897221 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7582855647636897216} - m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &7582855647636897222 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7582855647636897216} - 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: ec3b6ac9651c31248bcfbf695e6f597a, 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: 1 - 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} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta deleted file mode 100644 index ceaf231..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 849c125c9d8094249b3c664da1cd143a -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt b/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt deleted file mode 100644 index 9f5f0f1..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt +++ /dev/null @@ -1 +0,0 @@ -Setup details at https://mirror-networking.gitbook.io/docs/examples/additive-levels \ No newline at end of file diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes.meta deleted file mode 100644 index 2817b8a..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7a6d39d823db54d43925eb65b4ffec55 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity deleted file mode 100644 index bcaed3e..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity +++ /dev/null @@ -1,505 +0,0 @@ -%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: 12 - m_GIWorkflowMode: 1 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - 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: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 1 - 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_LightingSettings: {fileID: 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 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &185921126 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 185921129} - - component: {fileID: 185921128} - - component: {fileID: 185921127} - 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 &185921127 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 185921126} - m_Enabled: 1 ---- !u!20 &185921128 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 185921126} - 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: 15 - 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 &185921129 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 185921126} - 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1040404844 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1040404847} - - component: {fileID: 1040404846} - - component: {fileID: 1040404845} - m_Layer: 5 - m_Name: Panel - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1040404845 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1040404844} - 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: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 &1040404846 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1040404844} - m_CullTransparentMesh: 0 ---- !u!224 &1040404847 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1040404844} - 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: 1300359894} - 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!1 &1074858613 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1074858617} - - component: {fileID: 1074858616} - - component: {fileID: 1074858615} - - component: {fileID: 1074858614} - - component: {fileID: 1074858618} - m_Layer: 0 - m_Name: Network - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1074858614 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1074858613} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} - m_Name: - m_EditorClassIdentifier: - offsetX: 0 - offsetY: 0 ---- !u!114 &1074858615 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1074858613} - 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 - SendWindowSize: 4096 - ReceiveWindowSize: 4096 - MaxRetransmit: 40 - MaximizeSocketBuffers: 1 - ReliableMaxMessageSize: 298449 - UnreliableMaxMessageSize: 1199 - debugLog: 0 - statisticsGUI: 0 - statisticsLog: 0 ---- !u!114 &1074858616 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1074858613} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 01eafa8309a0894479f0f87ae1a9c30f, type: 3} - m_Name: - m_EditorClassIdentifier: - dontDestroyOnLoad: 1 - runInBackground: 1 - autoStartServerBuild: 1 - autoConnectClientBuild: 0 - sendRate: 30 - offlineScene: Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity - onlineScene: Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity - transport: {fileID: 1074858615} - networkAddress: localhost - maxConnections: 100 - authenticator: {fileID: 0} - playerPrefab: {fileID: 7619140271685878370, guid: 9f0094c1325091d42a558274b947221f, type: 3} - autoCreatePlayer: 0 - playerSpawnMethod: 1 - spawnPrefabs: [] - timeInterpolationGui: 0 - additiveScenes: - - Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity - - Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity - fadeInOut: {fileID: 1300359890} ---- !u!4 &1074858617 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1074858613} - 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: - - {fileID: 1300359894} - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1074858618 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1074858613} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b979f26c95d34324ba005bfacfa9c4fc, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &1300359889 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1300359894} - - component: {fileID: 1300359893} - - component: {fileID: 1300359892} - - component: {fileID: 1300359890} - m_Layer: 5 - m_Name: FadeCanvas - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1300359890 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1300359889} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 363a8867bb9c7b845a73233566df8c1e, type: 3} - m_Name: - m_EditorClassIdentifier: - speed: 1 - fadeImage: {fileID: 1040404845} - fadeColor: {r: 0, g: 0, b: 0, a: 1} ---- !u!114 &1300359892 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1300359889} - 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 - m_PresetInfoIsWorld: 0 ---- !u!223 &1300359893 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1300359889} - 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 &1300359894 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1300359889} - 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_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1040404847} - m_Father: {fileID: 1074858617} - 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} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity.meta deleted file mode 100644 index 13352b4..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Offline.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 9959d9d8e637be64dab77006a85135c1 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.meta deleted file mode 100644 index 133371f..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e73939c6462fca44d9c1fa826ff5c072 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity deleted file mode 100644 index 4ec4023..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity +++ /dev/null @@ -1,653 +0,0 @@ -%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: 1 - m_FogColor: {r: 0.0627451, g: 0.08235294, b: 0.18431373, 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: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 2100000, guid: 81f714daf7144784b8a2f42f1cd30927, type: 2} - 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.043674428, g: 0.044857424, b: 0.059592403, a: 1} - m_UseRadianceAmbientProbe: 0 ---- !u!157 &3 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 12 - 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: 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: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 1 - 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: 7868b86bff1943140826320e66c66468, type: 2} - m_LightingSettings: {fileID: 4890085278179872738, guid: b14d22a581510774fa4c3d6017f61944, type: 2} ---- !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 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &203151409 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 203151411} - - component: {fileID: 203151410} - m_Layer: 0 - m_Name: Directional Light (1) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &203151410 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 203151409} - 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: 0.5 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 0 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 0.5 - 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: 0 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ShadowRadius: 0 - m_ShadowAngle: 0 ---- !u!4 &203151411 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 203151409} - m_LocalRotation: {x: 0.55403227, y: -0.21201213, z: 0.14845248, w: 0.79124016} - 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: 1 - m_LocalEulerAnglesHint: {x: 70, y: -30, z: 0} ---- !u!1 &413994573 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 413994576} - - component: {fileID: 413994575} - - component: {fileID: 413994574} - 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 &413994574 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 413994573} - m_Enabled: 1 ---- !u!20 &413994575 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 413994573} - 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: 15 - 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 &413994576 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 413994573} - m_LocalRotation: {x: 0, y: -0.2658926, z: 0, w: 0.9640027} - m_LocalPosition: {x: 3.84, y: 1.91, z: -10} - 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: -30.84, z: 0} ---- !u!1 &1110529627 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1110529629} - - component: {fileID: 1110529628} - m_Layer: 0 - m_Name: Directional Light (3) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &1110529628 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1110529627} - 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: 0.5 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 0 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 0.5 - 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: 0 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ShadowRadius: 0 - m_ShadowAngle: 0 ---- !u!4 &1110529629 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1110529627} - m_LocalRotation: {x: 0.9848078, y: -0, z: -0, w: -0.17364809} - 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: 3 - m_LocalEulerAnglesHint: {x: 200, y: 0, z: 0} ---- !u!1 &1309024824 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1309024826} - - component: {fileID: 1309024825} - m_Layer: 0 - m_Name: Directional Light (4) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &1309024825 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1309024824} - 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: 0.5 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 0 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 0.5 - 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: 0 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ShadowRadius: 0 - m_ShadowAngle: 0 ---- !u!4 &1309024826 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1309024824} - m_LocalRotation: {x: 0.28678825, y: -0.70940644, z: -0.4967319, w: -0.4095759} - 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: 4 - m_LocalEulerAnglesHint: {x: 290, y: 120, z: 0} ---- !u!1 &1606864533 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1606864535} - - component: {fileID: 1606864534} - m_Layer: 0 - m_Name: Directional Light (2) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &1606864534 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1606864533} - 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: 0.5 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 0 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 0.5 - 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: 0 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ShadowRadius: 0 - m_ShadowAngle: 0 ---- !u!4 &1606864535 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1606864533} - m_LocalRotation: {x: 0.9063079, y: 0, z: 0, w: 0.42261827} - 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: 2 - m_LocalEulerAnglesHint: {x: 130, y: 0, z: 0} ---- !u!1 &1841150988 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1841150991} - - component: {fileID: 1841150990} - - component: {fileID: 1841150989} - m_Layer: 0 - m_Name: EventSystem - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1841150989 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1841150988} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} - m_Name: - m_EditorClassIdentifier: - m_SendPointerHoverToParent: 1 - m_HorizontalAxis: Horizontal - m_VerticalAxis: Vertical - m_SubmitButton: Submit - m_CancelButton: Cancel - m_InputActionsPerSecond: 10 - m_RepeatDelay: 0.5 - m_ForceModuleActive: 0 ---- !u!114 &1841150990 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1841150988} - 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 &1841150991 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1841150988} - 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: 5 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity.meta deleted file mode 100644 index 5713db8..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3c63960543989ea41ba3d3fb04d6dcf3 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/LightingData.asset b/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/LightingData.asset deleted file mode 100644 index ce15e19854518fe30a4f1d88515271f3d686d6ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19648 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 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/ReflectionProbe-0.exr.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/ReflectionProbe-0.exr.meta deleted file mode 100644 index ebde034..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/Online/ReflectionProbe-0.exr.meta +++ /dev/null @@ -1,92 +0,0 @@ -fileFormatVersion: 2 -guid: 433b69cd38057f84bb82796761c1be49 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 1 - seamlessCubemap: 1 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 2 - aniso: 0 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 2 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 100 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting b/Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting deleted file mode 100644 index fd67916..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting +++ /dev/null @@ -1,63 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!850595691 &4890085278179872738 -LightingSettings: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: OnlineSettings - serializedVersion: 3 - m_GIWorkflowMode: 1 - m_EnableBakedLightmaps: 0 - m_EnableRealtimeLightmaps: 0 - m_RealtimeEnvironmentLighting: 1 - m_BounceScale: 1 - m_AlbedoBoost: 1 - m_IndirectOutputScale: 1 - m_UsingShadowmask: 1 - m_BakeBackend: 1 - m_LightmapMaxSize: 1024 - m_BakeResolution: 40 - m_Padding: 2 - m_TextureCompression: 1 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAO: 0 - m_MixedBakeMode: 2 - m_LightmapsBakeMode: 1 - m_FilterMode: 1 - m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_RealtimeResolution: 2 - m_ForceWhiteAlbedo: 0 - m_ForceUpdates: 0 - m_FinalGather: 0 - m_FinalGatherRayCount: 256 - m_FinalGatherFiltering: 1 - m_PVRCulling: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 512 - m_PVREnvironmentSampleCount: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_LightProbeSampleCountMultiplier: 4 - m_PVRBounces: 2 - m_PVRMinBounces: 2 - m_PVREnvironmentMIS: 1 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting.meta deleted file mode 100644 index 96b73eb..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/OnlineSettings.lighting.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b14d22a581510774fa4c3d6017f61944 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 4890085278179872738 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity deleted file mode 100644 index 95a98ef..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity +++ /dev/null @@ -1,1021 +0,0 @@ -%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: 1 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - 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: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 1 - 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: 112000006, guid: 7868b86bff1943140826320e66c66468, - 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 &126437272 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 126437274} - - component: {fileID: 126437273} - m_Layer: 0 - m_Name: Environment - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &126437273 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 126437272} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 1317994002 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 0 ---- !u!4 &126437274 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 126437272} - 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: 1373387508} - - {fileID: 1445828407} - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &472411619 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 472411620} - - component: {fileID: 472411621} - m_Layer: 0 - m_Name: StartPosition - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &472411620 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 472411619} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -6, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1518259679} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &472411621 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 472411619} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &493146027 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 493146028} - - component: {fileID: 493146029} - m_Layer: 0 - m_Name: StartPosition - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &493146028 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 493146027} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -9, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1518259679} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &493146029 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 493146027} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &939597736 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 939597737} - m_Layer: 0 - m_Name: Cubes - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &939597737 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 939597736} - 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: 3181899219847070119} - - {fileID: 1294796099} - - {fileID: 2120764046} - - {fileID: 1071886464} - m_Father: {fileID: 0} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1001 &1071886463 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 939597737} - m_Modifications: - - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: sceneId - value: 656062201 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_Name - value: Cube - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_RootOrder - value: 3 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.x - value: 7 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} ---- !u!4 &1071886464 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - m_PrefabInstance: {fileID: 1071886463} - m_PrefabAsset: {fileID: 0} ---- !u!1 &1224119056 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1224119057} - - component: {fileID: 1224119058} - m_Layer: 0 - m_Name: StartPosition - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1224119057 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1224119056} - 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: 1518259679} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1224119058 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1224119056} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1001 &1294796098 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 939597737} - m_Modifications: - - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: sceneId - value: 3113436280 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_Name - value: Cube - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_RootOrder - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.x - value: -1 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} ---- !u!4 &1294796099 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - m_PrefabInstance: {fileID: 1294796098} - m_PrefabAsset: {fileID: 0} ---- !u!4 &1373387508 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - m_PrefabInstance: {fileID: 7582855648999245619} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &1445828406 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 126437274} - m_Modifications: - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_RootOrder - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008055, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_Name - value: Plane - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, type: 3} ---- !u!4 &1445828407 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - m_PrefabInstance: {fileID: 1445828406} - m_PrefabAsset: {fileID: 0} ---- !u!1 &1513281386 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1513281387} - - component: {fileID: 1513281388} - m_Layer: 0 - m_Name: StartPosition - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1513281387 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1513281386} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -3, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1518259679} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1513281388 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1513281386} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &1518259678 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1518259679} - m_Layer: 0 - m_Name: StartPosttions - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1518259679 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1518259678} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1.1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 493146028} - - {fileID: 472411620} - - {fileID: 1513281387} - - {fileID: 1224119057} - m_Father: {fileID: 0} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1842934413 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1842934415} - - component: {fileID: 1842934414} - m_Layer: 0 - m_Name: PhysicsSimulator - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1842934414 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1842934413} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 472efbe031bc80a499ea2a1003ac7452, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!4 &1842934415 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1842934413} - 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!1001 &2120764045 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 939597737} - m_Modifications: - - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: sceneId - value: 3424948259 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_Name - value: Cube - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_RootOrder - value: 2 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.x - value: 3 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} ---- !u!4 &2120764046 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - m_PrefabInstance: {fileID: 2120764045} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &1098173225757504847 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_RootOrder - value: 3 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalPosition.x - value: -10 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalPosition.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalPosition.z - value: 10 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622925, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_Name - value: Portal - objectReference: {fileID: 0} - - target: {fileID: 3141292696673982546, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: sceneId - value: 1143465467 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: startPosition.x - value: -5 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: startPosition.y - value: 1.1 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: startPosition.z - value: 10 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: destinationScene - value: Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: c624c75494b4d7d4086b9212f897e56a, type: 3} ---- !u!1001 &3181899219847070118 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 939597737} - m_Modifications: - - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: sceneId - value: 3043478025 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_Name - value: Cube - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_RootOrder - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.x - value: -5 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} ---- !u!4 &3181899219847070119 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, - type: 3} - m_PrefabInstance: {fileID: 3181899219847070118} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &7582855648999245619 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 126437274} - m_Modifications: - - target: {fileID: 7582855647636897216, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_Name - value: StartPoint - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_RootOrder - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalPosition.x - value: 5 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalPosition.z - value: -10 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 849c125c9d8094249b3c664da1cd143a, type: 3} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity.meta deleted file mode 100644 index 0b2651c..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 91c0fa5f4542be14dbad5c838292056b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity deleted file mode 100644 index de14d14..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity +++ /dev/null @@ -1,820 +0,0 @@ -%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: 1 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - 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: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 1 - 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: 7868b86bff1943140826320e66c66468, - 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!1001 &571924470 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_RootOrder - value: 3 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalPosition.x - value: 10 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalPosition.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalPosition.z - value: -10 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1098173225717622925, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: m_Name - value: Portal - objectReference: {fileID: 0} - - target: {fileID: 3141292696673982546, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: sceneId - value: 1073849646 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: originScene - value: Assets/DungeonTest/Scenes/Level2.unity - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: startPosition.x - value: 5 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: startPosition.y - value: 1.1 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: startPosition.z - value: -10 - objectReference: {fileID: 0} - - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, - type: 3} - propertyPath: destinationScene - value: Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel1.unity - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: c624c75494b4d7d4086b9212f897e56a, type: 3} ---- !u!1001 &1071886463 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 1514693545} - m_Modifications: - - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: sceneId - value: 2068572849 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_RootOrder - value: 3 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.x - value: 5 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_Name - value: Sphere - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} ---- !u!4 &1071886464 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - m_PrefabInstance: {fileID: 1071886463} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &1294796098 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 1514693545} - m_Modifications: - - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: sceneId - value: 131067959 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_RootOrder - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.x - value: -3 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_Name - value: Sphere - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} ---- !u!4 &1294796099 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - m_PrefabInstance: {fileID: 1294796098} - m_PrefabAsset: {fileID: 0} ---- !u!1 &1514693544 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1514693545} - m_Layer: 0 - m_Name: Spheres - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1514693545 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1514693544} - 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: 2188792038635513490} - - {fileID: 1294796099} - - {fileID: 2120764046} - - {fileID: 1071886464} - m_Father: {fileID: 0} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1842934413 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1842934415} - - component: {fileID: 1842934414} - m_Layer: 0 - m_Name: PhysicsSimulator - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1842934414 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1842934413} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 472efbe031bc80a499ea2a1003ac7452, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!4 &1842934415 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1842934413} - 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!1 &1932534637 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1932534639} - - component: {fileID: 1932534638} - m_Layer: 0 - m_Name: Environment - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1932534638 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1932534637} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 159404139 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 0 ---- !u!4 &1932534639 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1932534637} - 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: 1999985658} - - {fileID: 6358973573665600640} - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1001 &1999985657 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 1932534639} - m_Modifications: - - target: {fileID: 7582855647636897216, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_Name - value: StartPoint - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_RootOrder - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalPosition.x - value: -5 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalPosition.z - value: 10 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 849c125c9d8094249b3c664da1cd143a, type: 3} ---- !u!4 &1999985658 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, - type: 3} - m_PrefabInstance: {fileID: 1999985657} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &2120764045 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 1514693545} - m_Modifications: - - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: sceneId - value: 1581864539 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_RootOrder - value: 2 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.x - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_Name - value: Sphere - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} ---- !u!4 &2120764046 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - m_PrefabInstance: {fileID: 2120764045} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &2188792038635513489 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 1514693545} - m_Modifications: - - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: sceneId - value: 3873206969 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_RootOrder - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.x - value: -7 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - propertyPath: m_Name - value: Sphere - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} ---- !u!4 &2188792038635513490 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, - type: 3} - m_PrefabInstance: {fileID: 2188792038635513489} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &6358973573665600639 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 1932534639} - m_Modifications: - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_RootOrder - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7349408984269008055, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - propertyPath: m_Name - value: Plane - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, type: 3} ---- !u!4 &6358973573665600640 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, - type: 3} - m_PrefabInstance: {fileID: 6358973573665600639} - m_PrefabAsset: {fileID: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity.meta deleted file mode 100644 index 6296895..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scenes/SubLevel2.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e8e2dc8c3ef824b468c6f6e1980a4b27 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts.meta deleted file mode 100644 index 4e40c32..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: daf19edd647d8ae4ead9cb46f24f5424 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs deleted file mode 100644 index 00d459f..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs +++ /dev/null @@ -1,197 +0,0 @@ -using System.Collections; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Mirror.Examples.AdditiveLevels -{ - [AddComponentMenu("")] - public class AdditiveLevelsNetworkManager : NetworkManager - { - public static new AdditiveLevelsNetworkManager singleton { get; private set; } - - /// - /// Runs on both Server and Client - /// Networking is NOT initialized when this fires - /// - public override void Awake() - { - base.Awake(); - singleton = this; - } - - [Header("Additive Scenes - First is start scene")] - - [Scene, Tooltip("Add additive scenes here.\nFirst entry will be players' start scene")] - public string[] additiveScenes; - - [Header("Fade Control - See child FadeCanvas")] - - [Tooltip("Reference to FadeInOut script on child FadeCanvas")] - public FadeInOut fadeInOut; - - // This is set true after server loads all subscene instances - bool subscenesLoaded; - - // This is managed in LoadAdditive, UnloadAdditive, and checked in OnClientSceneChanged - bool isInTransition; - - #region Scene Management - - /// - /// 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) - { - // This fires after server fully changes scenes, e.g. offline to online - // If server has just loaded the Container (online) scene, load the subscenes on server - if (sceneName == onlineScene) - StartCoroutine(ServerLoadSubScenes()); - } - - IEnumerator ServerLoadSubScenes() - { - foreach (string additiveScene in additiveScenes) - yield return SceneManager.LoadSceneAsync(additiveScene, new LoadSceneParameters - { - loadSceneMode = LoadSceneMode.Additive, - localPhysicsMode = LocalPhysicsMode.Physics3D // change this to .Physics2D for a 2D game - }); - - subscenesLoaded = true; - } - - /// - /// Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed - /// This allows client to do work / cleanup / prep before the scene changes. - /// - /// Name of the scene that's about to be loaded - /// Scene operation that's about to happen - /// true to indicate that scene loading will be handled through overrides - public override void OnClientChangeScene(string sceneName, SceneOperation sceneOperation, bool customHandling) - { - //Debug.Log($"{System.DateTime.Now:HH:mm:ss:fff} OnClientChangeScene {sceneName} {sceneOperation}"); - - if (sceneOperation == SceneOperation.UnloadAdditive) - StartCoroutine(UnloadAdditive(sceneName)); - - if (sceneOperation == SceneOperation.LoadAdditive) - StartCoroutine(LoadAdditive(sceneName)); - } - - IEnumerator LoadAdditive(string sceneName) - { - isInTransition = true; - - // This will return immediately if already faded in - // e.g. by UnloadAdditive or by default startup state - yield return fadeInOut.FadeIn(); - - // host client is on server...don't load the additive scene again - if (mode == NetworkManagerMode.ClientOnly) - { - // Start loading the additive subscene - loadingSceneAsync = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); - - while (loadingSceneAsync != null && !loadingSceneAsync.isDone) - yield return null; - } - - // Reset these to false when ready to proceed - NetworkClient.isLoadingScene = false; - isInTransition = false; - - OnClientSceneChanged(); - - // Reveal the new scene content. - yield return fadeInOut.FadeOut(); - } - - IEnumerator UnloadAdditive(string sceneName) - { - isInTransition = true; - - // This will return immediately if already faded in - // e.g. by LoadAdditive above or by default startup state. - yield return fadeInOut.FadeIn(); - - // host client is on server...don't unload the additive scene here. - if (mode == NetworkManagerMode.ClientOnly) - { - yield return SceneManager.UnloadSceneAsync(sceneName); - yield return Resources.UnloadUnusedAssets(); - } - - // Reset these to false when ready to proceed - NetworkClient.isLoadingScene = false; - isInTransition = false; - - OnClientSceneChanged(); - - // There is no call to FadeOut here on purpose. - // Expectation is that a LoadAdditive or full scene change - // will follow that will call FadeOut after that scene loads. - } - - /// - /// 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. - /// - /// The network connection that the scene change message arrived on. - public override void OnClientSceneChanged() - { - // Only call the base method if not in a transition. - // This will be called from DoTransition after setting doingTransition to false - // but will also be called first by Mirror when the scene loading finishes. - if (!isInTransition) - base.OnClientSceneChanged(); - } - - #endregion - - #region Server System Callbacks - - /// - /// 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(NetworkConnectionToClient conn) - { - // This fires from a Ready message client sends to server after loading the online scene - base.OnServerReady(conn); - - if (conn.identity == null) - StartCoroutine(AddPlayerDelayed(conn)); - } - - // This delay is mostly for the host player that loads too fast for the - // server to have subscenes async loaded from OnServerSceneChanged ahead of it. - IEnumerator AddPlayerDelayed(NetworkConnectionToClient conn) - { - // Wait for server to async load all subscenes for game instances - while (!subscenesLoaded) - yield return null; - - // Send Scene msg to client telling it to load the first additive scene - conn.Send(new SceneMessage { sceneName = additiveScenes[0], sceneOperation = SceneOperation.LoadAdditive, customHandling = true }); - - // We have Network Start Positions in first additive scene...pick one - Transform start = GetStartPosition(); - - // Instantiate player as child of start position - this will place it in the additive scene - // This also lets player object "inherit" pos and rot from start position transform - GameObject player = Instantiate(playerPrefab, start); - // now set parent null to get it out from under the Start Position object - player.transform.SetParent(null); - - // Wait for end of frame before adding the player to ensure Scene Message goes first - yield return new WaitForEndOfFrame(); - - // Finally spawn the player object for this connection - NetworkServer.AddPlayerForConnection(conn, player); - } - - #endregion - } -} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta deleted file mode 100644 index af10a3c..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 01eafa8309a0894479f0f87ae1a9c30f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs deleted file mode 100644 index e9f781a..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Collections; -using UnityEngine; -using UnityEngine.UI; - -namespace Mirror.Examples.AdditiveLevels -{ - public class FadeInOut : MonoBehaviour - { - // set these in the inspector - [Range(1, 100), Tooltip("Speed of fade in / out: lower is slower")] - public byte speed = 1; - - [Tooltip("Reference to Image component on child panel")] - public Image fadeImage; - - [Tooltip("Color to use during scene transition")] - public Color fadeColor = Color.black; - - WaitForSeconds waitForSeconds; - - void Awake() - { - waitForSeconds = new WaitForSeconds(speed * 0.01f); - } - - public IEnumerator FadeIn() - { - float alpha = fadeImage.color.a; - - while (alpha < 1) - { - yield return waitForSeconds; - alpha += 0.01f; - fadeColor.a = alpha; - fadeImage.color = fadeColor; - } - } - - public IEnumerator FadeOut() - { - float alpha = fadeImage.color.a; - - while (alpha > 0) - { - yield return waitForSeconds; - alpha -= 0.01f; - fadeColor.a = alpha; - fadeImage.color = fadeColor; - } - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta deleted file mode 100644 index c54328f..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 363a8867bb9c7b845a73233566df8c1e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs deleted file mode 100644 index ccb88fb..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs +++ /dev/null @@ -1,21 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.AdditiveLevels -{ - // This script is attached to portal labels to keep them facing the camera - public class LookAtMainCamera : MonoBehaviour - { - // This will be enabled by Portal script in OnStartClient - void OnValidate() - { - this.enabled = false; - } - - // LateUpdate so that all camera updates are finished. - [ClientCallback] - void LateUpdate() - { - transform.forward = Camera.main.transform.forward; - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta deleted file mode 100644 index 34a9978..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cc58300ee45438a418d9e32957fdc0c0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PhysicsSimulator.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/PhysicsSimulator.cs deleted file mode 100644 index 7b0da7a..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PhysicsSimulator.cs +++ /dev/null @@ -1,40 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.AdditiveLevels -{ - 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/AdditiveLevels/Scripts/PhysicsSimulator.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/PhysicsSimulator.cs.meta deleted file mode 100644 index b683f9a..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PhysicsSimulator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 472efbe031bc80a499ea2a1003ac7452 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs deleted file mode 100644 index f0e3968..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs +++ /dev/null @@ -1,44 +0,0 @@ -using UnityEngine; -using UnityEngine.SceneManagement; - -// This sets up the scene camera for the local player - -namespace Mirror.Examples.AdditiveLevels -{ - public class PlayerCamera : NetworkBehaviour - { - Camera mainCam; - - void Awake() - { - mainCam = Camera.main; - } - - public override void OnStartLocalPlayer() - { - if (mainCam != null) - { - // configure and make camera a child of player with 3rd person offset - mainCam.orthographic = false; - mainCam.transform.SetParent(transform); - mainCam.transform.localPosition = new Vector3(0f, 3f, -8f); - mainCam.transform.localEulerAngles = new Vector3(10f, 0f, 0f); - } - else - Debug.LogWarning("PlayerCamera: Could not find a camera in scene with 'MainCamera' tag."); - } - - public override void OnStopLocalPlayer() - { - if (mainCam != null) - { - mainCam.transform.SetParent(null); - SceneManager.MoveGameObjectToScene(mainCam.gameObject, SceneManager.GetActiveScene()); - mainCam.orthographic = true; - mainCam.orthographicSize = 15f; - mainCam.transform.localPosition = new Vector3(0f, 70f, 0f); - mainCam.transform.localEulerAngles = new Vector3(90f, 0f, 0f); - } - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs.meta deleted file mode 100644 index c70cb63..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerCamera.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 22976424f775a0f4a8531e6713ff6de2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs deleted file mode 100644 index 01bd142..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs +++ /dev/null @@ -1,184 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.AdditiveLevels -{ - [RequireComponent(typeof(CapsuleCollider))] - [RequireComponent(typeof(CharacterController))] - [RequireComponent(typeof(NetworkTransform))] - [RequireComponent(typeof(Rigidbody))] - public class PlayerController : NetworkBehaviour - { - public enum GroundState : byte { Jumping, Falling, Grounded } - - [Header("Avatar Components")] - public CharacterController characterController; - - [Header("Movement")] - [Range(1, 20)] - public float moveSpeedMultiplier = 8f; - - [Header("Turning")] - [Range(1f, 200f)] - public float maxTurnSpeed = 100f; - [Range(.5f, 5f)] - public float turnDelta = 3f; - - [Header("Jumping")] - [Range(0.1f, 1f)] - public float initialJumpSpeed = 0.2f; - [Range(1f, 10f)] - public float maxJumpSpeed = 5f; - [Range(0.1f, 1f)] - public float jumpDelta = 0.2f; - - [Header("Diagnostics - Do Not Modify")] - public GroundState groundState = GroundState.Grounded; - - [Range(-1f, 1f)] - public float horizontal; - [Range(-1f, 1f)] - public float vertical; - - [Range(-200f, 200f)] - public float turnSpeed; - - [Range(-10f, 10f)] - public float jumpSpeed; - - [Range(-1.5f, 1.5f)] - public float animVelocity; - - [Range(-1.5f, 1.5f)] - public float animRotation; - - public Vector3Int velocity; - public Vector3 direction; - - void OnValidate() - { - if (characterController == null) - characterController = GetComponent(); - - // Override CharacterController default values - characterController.enabled = false; - characterController.skinWidth = 0.02f; - characterController.minMoveDistance = 0f; - - GetComponent().isKinematic = true; - - this.enabled = false; - } - - public override void OnStartAuthority() - { - characterController.enabled = true; - this.enabled = true; - } - - public override void OnStopAuthority() - { - this.enabled = false; - characterController.enabled = false; - } - - void Update() - { - if (!characterController.enabled) - return; - - HandleTurning(); - HandleJumping(); - HandleMove(); - - // Reset ground state - if (characterController.isGrounded) - groundState = GroundState.Grounded; - else if (groundState != GroundState.Jumping) - groundState = GroundState.Falling; - - // Diagnostic velocity...FloorToInt for display purposes - velocity = Vector3Int.FloorToInt(characterController.velocity); - } - - // TODO: Turning works while airborne...feature? - void HandleTurning() - { - // Q and E cancel each other out, reducing the turn to zero. - if (Input.GetKey(KeyCode.Q)) - turnSpeed = Mathf.MoveTowards(turnSpeed, -maxTurnSpeed, turnDelta); - if (Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, maxTurnSpeed, turnDelta); - - // If both pressed, reduce turning speed toward zero. - if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta); - - // If neither pressed, reduce turning speed toward zero. - if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta); - - transform.Rotate(0f, turnSpeed * Time.deltaTime, 0f); - } - - void HandleJumping() - { - // Handle variable force jumping. - // Jump starts with initial power on takeoff, and jumps higher / longer - // as player holds spacebar. Jump power is increased by a diminishing amout - // every frame until it reaches maxJumpSpeed, or player releases the spacebar, - // and then changes to the falling state until it gets grounded. - if (groundState != GroundState.Falling && Input.GetKey(KeyCode.Space)) - { - if (groundState != GroundState.Jumping) - { - // Start jump at initial power. - groundState = GroundState.Jumping; - jumpSpeed = initialJumpSpeed; - } - else - // Jumping has already started...increase power toward maxJumpSpeed over time. - jumpSpeed = Mathf.MoveTowards(jumpSpeed, maxJumpSpeed, jumpDelta); - - // If power has reached maxJumpSpeed, change to falling until grounded. - // This prevents over-applying jump power while already in the air. - if (jumpSpeed == maxJumpSpeed) - groundState = GroundState.Falling; - } - else if (groundState != GroundState.Grounded) - { - // handles running off a cliff and/or player released Spacebar. - groundState = GroundState.Falling; - jumpSpeed = Mathf.Min(jumpSpeed, maxJumpSpeed); - jumpSpeed += Physics.gravity.y * Time.deltaTime; - } - else - jumpSpeed = Physics.gravity.y * Time.deltaTime; - } - - // TODO: Directional input works while airborne...feature? - void HandleMove() - { - // Capture inputs - horizontal = Input.GetAxis("Horizontal"); - vertical = Input.GetAxis("Vertical"); - - // Create initial direction vector without jumpSpeed (y-axis). - direction = new Vector3(horizontal, 0f, vertical); - - // Clamp so diagonal strafing isn't a speed advantage. - direction = Vector3.ClampMagnitude(direction, 1f); - - // Transforms direction from local space to world space. - direction = transform.TransformDirection(direction); - - // Multiply for desired ground speed. - direction *= moveSpeedMultiplier; - - // Add jumpSpeed to direction as last step. - direction.y = jumpSpeed; - - // Finally move the character. - characterController.Move(direction * Time.deltaTime); - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs.meta deleted file mode 100644 index eebb2a3..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/PlayerController.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 05e10150710dde14b83d3c8f5aa853c2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs deleted file mode 100644 index 9625270..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections; -using System.IO; -using System.Text.RegularExpressions; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Mirror.Examples.AdditiveLevels -{ - public class Portal : NetworkBehaviour - { - [Scene, Tooltip("Which scene to send player from here")] - public string destinationScene; - - [Tooltip("Where to spawn player in Destination Scene")] - public Vector3 startPosition; - - [Tooltip("Reference to child TMP label")] - public TextMesh label; // don't depend on TMPro. 2019 errors. - - [SyncVar(hook = nameof(OnLabelTextChanged))] - public string labelText; - - public void OnLabelTextChanged(string _, string newValue) - { - label.text = labelText; - } - - // This is approximately the fade time - WaitForSeconds waitForFade = new WaitForSeconds(2f); - - public override void OnStartServer() - { - labelText = Path.GetFileNameWithoutExtension(destinationScene); - - // Simple Regex to insert spaces before capitals, numbers - labelText = Regex.Replace(labelText, @"\B[A-Z0-9]+", " $0"); - } - - public override void OnStartClient() - { - if (label.TryGetComponent(out LookAtMainCamera lookAtMainCamera)) - lookAtMainCamera.enabled = true; - } - - // Note that I have created layers called Player(6) and Portal(7) and set them - // up in the Physics collision matrix so only Player collides with Portal. - void OnTriggerEnter(Collider other) - { - // tag check in case you didn't set up the layers and matrix as noted above - if (!other.CompareTag("Player")) return; - - // applies to host client on server and remote clients - if (other.TryGetComponent(out PlayerController playerController)) - playerController.enabled = false; - - if (isServer) - StartCoroutine(SendPlayerToNewScene(other.gameObject)); - } - - [ServerCallback] - IEnumerator SendPlayerToNewScene(GameObject player) - { - if (player.TryGetComponent(out NetworkIdentity identity)) - { - NetworkConnectionToClient conn = identity.connectionToClient; - if (conn == null) yield break; - - // Tell client to unload previous subscene. No custom handling for this. - conn.Send(new SceneMessage { sceneName = gameObject.scene.path, sceneOperation = SceneOperation.UnloadAdditive, customHandling = true }); - - yield return waitForFade; - - NetworkServer.RemovePlayerForConnection(conn, false); - - // reposition player on server and client - player.transform.position = startPosition; - player.transform.LookAt(Vector3.up); - - // Move player to new subscene. - SceneManager.MoveGameObjectToScene(player, SceneManager.GetSceneByPath(destinationScene)); - - // Tell client to load the new subscene with custom handling (see NetworkManager::OnClientChangeScene). - conn.Send(new SceneMessage { sceneName = destinationScene, sceneOperation = SceneOperation.LoadAdditive, customHandling = true }); - - NetworkServer.AddPlayerForConnection(conn, player); - - // host client would have been disabled by OnTriggerEnter above - if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent(out PlayerController playerController)) - playerController.enabled = true; - } - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta deleted file mode 100644 index 92289a9..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0e680878006965146a8f9d85834c4d1c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs deleted file mode 100644 index e82613e..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs +++ /dev/null @@ -1,36 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.AdditiveLevels -{ - public class RandomColor : NetworkBehaviour - { - // 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); - } - - public override void OnStartServer() - { - base.OnStartServer(); - - // This script is on players that are respawned repeatedly - // so once the color has been set, don't change it. - if (color == Color.black) - color = Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f); - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs.meta deleted file mode 100644 index 516f255..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Scripts/RandomColor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a91a718a70d01b347b75cb768a6f1a92 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures.meta b/Assets/Mirror/Examples/AdditiveLevels/Textures.meta deleted file mode 100644 index 9335d0d..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Textures.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: a1ac2873c4eb8d64db33d7df8acb9188 -folderAsset: yes -timeCreated: 1497127550 -licenseType: Store -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Back_Tex.jpeg b/Assets/Mirror/Examples/AdditiveLevels/Textures/Back_Tex.jpeg deleted file mode 100644 index f5d4c11bf1076159b76e975884ef051a67ea76f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68766 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 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta b/Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta deleted file mode 100644 index d04aca2..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta +++ /dev/null @@ -1,92 +0,0 @@ -fileFormatVersion: 2 -guid: 9ffeeee1accdc4b4faf2b3e27b226340 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: -1 - aniso: -1 - mipBias: -100 - wrapU: -1 - wrapV: -1 - wrapW: -1 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg b/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg deleted file mode 100644 index 5e91f3f23b0d1583f50cf4268a7c71ce0a3978c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72964 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 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta b/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta deleted file mode 100644 index 36658d0..0000000 --- a/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta +++ /dev/null @@ -1,92 +0,0 @@ -fileFormatVersion: 2 -guid: ca928ef0e269448ba82388eb41d48544 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: -1 - aniso: -1 - mipBias: -100 - wrapU: -1 - wrapV: -1 - wrapW: -1 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg b/Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg deleted file mode 100644 index 5f7de24d423d12697a8d207d36ad986479daad53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68026 zcmbTdd0bNI-#>g<6g79TaX~Xh1+&Hl6Wl_}4Ha3`8e7KHRHzIz*RsK_g^XOVl#EbW zM6p2%B)OHQ?u1-TISnxocn(6`}KPMdVaqP!SjN14t&nJKHK~KzJ5OX zISJ^K0)hho2m}Cvzz6X21yJOl$w&ZzurR;@000d@4Ppquz%2;)03c?7+P~WXK!TY6 z&o&K$`R{$80C0=}!2f%nXz>5a0MEQ~^nd?{i6H-bMiKP?-5U;wVE?jozP?-v{fUpYHC{@u3ycT-8-9%+}5xgLS~UZFI*I zJT`Cf4+snjCeb4zqqc7QEjliKPeNi6gPD3TEj=SMD?7iS@aVDQC%C0${PHtrD=Gyw zwPJ}>Rwu8&a4c=irCFIvUbVU zK>C$bH+N~;xYFJk$EG~cT8+lNuzkN`+P{|l|1&J_|H`ueG3_v#w#c@`kLgj~|DbQrego6t^>?x0tyV2k2lcXft-MP)wg5|s5s*0zt zqQJu4Rz(yYiU@230{UJ)$$d!Z+Z6gO!d?=Zt%`t{&eqD0FV~%p21t}c6l~B`ZgtD; z)NrX~i#7va%Mvs9tLaT(+i?@z9iz|NAX5Ue|5}0=5A&Yq+!-s)Uksf{f^4HR=1M}n zD4sfYXVY+13JUCtR@kd;qTOxU<^4l?!1N{W`PPHapWQ6T-afRHh+H~YjN1R(`PJ^l z><&k6eO50pO|TVN*A$yY?i=I)dS?&rlL$zYDG|tTK<0c1Rhhd)Pp*lptKnvh?2c-5{Ppr+fAh6N zr<)&#*G=pj_v+XiW0u96-Enbu?%I^TO%8&F(9G#F%h+{GYtOO}+8zeNf^;|NE%8N3 zFd`2xo-O55?6$jKYmB+RyRGC5WS?zSy=z?x=5O>ulNVd!@b$|y<5>4}#G2F5 zYV0I2?B;r?R*I70+XMJ;{n%j>Nl+p?+^S&fgp6$i{J3MX;0Y6YXD!#|4z35h%rcor zt8}8Fo!<3(SjbBV{LCj4!nC3R7LFLJFv=(Q*ZKDNX98DRF@*ZAddi`Z5cH4(<&Y}UYCftG&42l+jv0yT%t2E9ASv0j{PA;vB%qXQ zeAj6Y-fG6+kdeV{1?m#7)_E}&{M;0h72In*GeNoW|jDZzi zmLHlBknSvxL@&`&h{G_vY2PJm#Ahj7G+U+Xu%X-*@DjRGJ}^U7S$!lRQ+B4a?rJY1 zb&;qs7->1UDXP2hbL7YHKBszG;8w;(b;9Mq)c(+cG`E1j-97t*D(8PI>rQG; z8v0mC_HA%}DxVxXT%Q^_j8e3xyWi*>wal8mGS$BBPUK(S+iyk=BvlC#-jWjDF(mZ` zLAuzCh_yFgJ$*~mi=&ot-DySwz%MnlH_W4qB~p)YbfEbMbepLcpPVN>#n`4_8tt+m zrwVgC*?o(?GnB2qN?#a zz}Uj6X_BEA9s0m`%fSe~0%LcFaWAYU*J!;*E#jtE72W?N5t0c5(vhPBYl-MG4q}Ip z|2Znkp|b&NmFMJ(()WGiP~xa#i=^w*@)v{sf#C2*hcCOQO#gBA8teJ_j;q%$J$rIJ zk=Jq;14#Nz#S#P(c&{kCl>|;>T#+CRsUV19^4sV9&2w#$6EigKnV=S`zo#}fFq*Wh zN)Z&L%5nN6Q%09q=L=ke5ZUy%#8qXT_A+08rz&t}*MPo4)I}hL%hWJn@>$CQuS&0x zVg!43Q6q8VPhjt(!zGx4fs)fsa#q_=N`#RTl{RclLDBz|@BiDpxoEm7tv3e)jbZ%b zpwF088u+A!BisNv0%>>;Yld^ZtEk8A+SNal5q$IWpZB3Yz8^PE;lFpBHa135)=o=) zC7qUdp+?{$MOg_opUcJp=fga4T~$WGL?i4H4Mxd-cAW)R1CqX0ar0Ufc z4!#P(mMdv?QhI3K@9VNY)SNwhz|wB#iwx}p)RJSn>Lw;X=971|D2yC+{loV=QYHc& z-!JqF@AWo*y`ZohPzJpt%HIZ2m>oOjbs;Hs+mOwPNsqb5&W#JcdpIgk!*hcvw zLI!8{Y^#%{UZd%t2jlRV&dZ+F26TfBBk3G>gR(Qp7Y|hlVn<-PgBaX-j7ZbB$CD-1 z<*x)|$Z#_MZpt8<`HFWJy^{yAa+yJ`p%&|U6Gdth*v%21a$og-!$sF7ci4Ef`dPe4 zGlk(QNSF??4Y1ve-ShpfM*naq@3BY|ypKtQ#>fY)fe$WpuiDo~=Dpu%HkY#h7ah$i z|7+l1{al6s^uE-E$dvRfnCMle`v2cIel@^9NcCj0G6 z#>F`}i*bC$3~_hw#a3r_(HMn4D>aNylUA-@ePaRs^b~EvH7NRI;mKYi}BEMroT zVR7OfoBC$94A(2goyZ-;n_bk!zGx2J(mh*)>$pnh5$sBK7n%j5UQi(k_9KweFkq{d z(joLHG(4HC7Htg+MmDcxHBg{tfm6clc{&e_Z1(kTzV4ggIy(OYWzVSX* zl@rK3UKEjE!rd%fzC?x5PG?6UO(8sdH~ZJKf6Z+f|8QXcKN5CKm;V!ZAyv#FwGmXFLso3kjVrGkXS>VtE}BDqi_O=h z^}WY_<-a4k?Go3AMrmQh6AlIIkyN6d1y+w5q+>dV1HNHuIOuKSgQZ(&G^JHW3-L1}n#7DriK>-+2xmz}fqj;pNS)H#Sw~|HTQI zm@_A*1h^Ix`j8{3p)%Nb8RRK;+CpC2h^aoolNprwUESbUm2BcOP3W7&-r;UFia$sz z8T7*Rrnpwc{WW&JkBuPhYN1lXD`=K#>v2Mr#(un|Y8(S4F=B`&Gl>^|{|Q8{9nK~J zEN{7LEO2Ls>e5TycKDufKUbAyU$uBZwwLn_3mIIG`{rb+%S;kG|C!#v3b5F$>uaIM zuF8KjIm%+wbX#7-8^}^!ozPjEt9PR)Hk2pF_qDBY)rJ(>i)M1W>>Hib=4q;RG#=lu zuhD~xG16j9=Yt{DkV;j4B(CyD7EE!_7T7zDTXY$dBk)#-Pm({bX6a}7{f4o$VwkaZzXo>*E)5P6!h#;K zw@qE{lJDC7=s9C#;LqpO@0-TyOpBkup5l9Y_kH(_zYc!1H6vgGFh0{r`;{rSRtPb6 zwe*mx<$8l(qcbPzYNks>Lt3ujq$Ef$8#uyn*V;T*%K62vlpD$g!c+@9p$7#n`XZUw zOZGNIv7Y|W1{-d-%@9t22E|qg6<_kNk;%0F8 zZbN$RQkcYoDV)(;DPA(?LlKQ06<}V}0?NE1GlraLpWHCSY=zk#D-EP5b?~=6eWZk; z|FmptC@JZ&f{*4}W-GgQCpA@_{;BxUC-%~c-fKBJ?|RQHJo~sH%e#K{G!7VZgP9#N z%RL1U7j&qlE_%i}r~D>H?uPaW?7F=7I(J3&U&`%^?mr*!#v#o5ZuJ6XCNcq!uRVgb zi#)mgYQOB*w0gZwVq*|Fs^Vhkl^5*|YYX?N&o&0A>|FjfCDffOBQ=KoA*i1+ucF_9 zx>EHS3+hBK?T=y3(RV(EwCBPNHC_c88%;VtN)c6|;%u7xn3M@RTGP4~tsHhUo#On$ z7PSV1tp#UGO^ps2Rjk9 z0?dLSY3n#tt63gL*SQgO@1<4f#m&sCOWzd+UnYLs&x)hOQ}Slc72?gfReEt@nx#hb zVKrQ_9U%v+>SQsNyD@li4Hs}FKMkwl*qZd)OSX3$LTsnTA)8&IyU*Hf)wP^i{W1PD zuGS?9rqh0LrNdg|ZQX*iWzO)FUvTIIoreNg#*ahmc9IL6Teeb-? z{HXGc9&^84mUtMqEy}_lNzcZ%^E+q7t<(7 zI$7pba&|r2Zi-_vO_^XqkVySM+HxXn^EWI3^ z=7e6Eq$%Gh@ROk1cL&7u1o&xRYwBNfpDV-&Bg^gvq#ELec_+9MO>1>atw7wJ}H+1Em~_;7nD^V2i{`rvs#tu&r|AI;cXZnqpJ2sF`UV ze%Ob9uFe2MkmZk8BNRd%Cr4~UP-YMPcY0JDZp7vAd*UMXYPx)NUFl9$fq=A|AkuVU zEHHaY8NoEzhEL#w(awioQTl`JNd!LeguyXaYNpJAJV}E=!>DX zgxQK{jztMck4<^=Nd}uI8pUU8fBW)d{_#rZ^6N@lkieMYSb9X<8>`vnOyjk5`&1#a z_hZoXeS9BrKe*GjYwc|<{P4Xt{#H?xeimyX@@S5#IOmkJc1?w@lXFjy#{-t-jfhIA z77M4n^A1W8Z&vh4BDLOs`#cqc`yu2*ekyRj_mMfNx!s=czigTel>RKX~+4my&gZ>-YPHsp-r<4!!1iWd-cNs-3j^?KuV1O z!n3h@&`N>&35@iOct8@{StTHa=7!nhMlNl#E=zOa?v~r7`Ui$1aH~=xVybf~PmV$e zU&(=NUXMM&%CtaIiG zOXuFDzv%`4+~cYe@pBTu7EJ7F;8V*(Io}Wt6o*RyLUu&H#7S56o-z;J?D+SDO$_B`2wd6u9)ucMy<~GdFG<@ zLQx<4cJY60bh04-9=#uf7X|%sSouxqq2RTw6dt*|?p!mYFu-oR&uBilEZ854(sXlV z@?PxhW~QF8D#j1{mJNshr_~p{U=S-Wm_mY5S$&p)sccHTwKo%CgDRSy$Ts7w0pWp= zGO`XeS%Sc6T+#7Djk1`OBq)U)zKaPNlSTtqdmXlvsW&7~RUNbAY=COYkC84`HfSA+ zD$pAci@mWTa8m0!kihl>3EA)>Scq)_(>(G|HUAErQBOb^5G-WVt^`{?cQ%EIN;07C zHaTOaD0x>G%5s$A?zZvsz5}t3AOXR6n8@@MVmHwU#%0YU)X>KzddKe{qP)ycwwW~< z20kOacz;{+ftL4*S_|yrJaM%sDJo)bVdC*MmDIdu%ln%l!_87T-gJ@2v|^L{rR$86 zamjARgrqjZd;tqz*B6~*8QW|dOy!oIgP*|6Q|DSurFOwI2=_$hjEa*V>KLS(DYnif z4`B>`s($qL*A0`B!!|4|hdZ9C-zeWMA=Tq zQ0kvo+WIG7@XKu`4D}i}a?psIp*qBy4*v7R6JtWnm5B@lKa~9D-&u!@EUf3+mgWnJ zQ7S@@msz!80@vVp8UY4hQxVTf?Vqz5Z~3$r?zBrxYGF zGlizHzyKO>$wE)2*&934&0SD?w#mEt`|)_2JntSLXyxu_5=3CxD!A3M0Avy*b@S5_ zz?~? zve~D1JugfkwYf>2j5l15AHgMZn7>T5n0aZ{JrcFtO~j1^d5z|CkH07C4U(h{Mmz_9 z8}DqTU;LooCuwOI!T&dStpvn$FOwJ|XsuVo`FiUl2t%{Soh`1`W*;E!M@IhMq-aOe z?!iyu9H~m%ZE-eM`47EM80$lb)DadoN!IQgZs<|ld$9}sFcvdoKY*2A zq@7hQUS{pZvpE%V6{SWk4R1m|yTOeymE{Ze5ExGAiS&J)y%~uxZ|8@Xysy(>!Tz?F zI3&-HIN$K2PHM-Z^CYKG4*C!I1j?; z<7cW*oFqZ)VWl7(g4J;FC>8kQU<_8+hVeAF87PFyG8N0#D)?9l7qD!!m+gcu8Kxh>Qe^jPdYU++LLbt93~P=l-MBKYnN}j)GMkD0}yKwNRhl``ws>za;Q z0o~^xn-G9F{E`5uZ=lhAp=ZHj)ZgKgwDxscZ1wG`rG1m%QTpt^l_L~zqOD*183dAb zL8s+Y;G8dV2Y?-pXcK9k#l2%wkIGboN+vzvG91R!O&NZe84`dK9Ndx zL_Dn*RVk0TZ8bg#c|TVBQNLf(c6^Kj5oli0~*R845?e98UH%!sn<*9sfbBhXMAeI?`wYs*w zpy-oa$4RIH#u-)$A^$G0SDPz-FC0xfMZ6zqlmEmx$}AyO+idqd{ra~E9f5z1wWrb- z_fb*C5W`f(OvQ42XNEkt;e;cIw0#WrcL^w?Tss_b>}EicsRbUzVzd-YQs`*A%24e? z53UPho4#c-i}V@HYdTchwey>GI*#nwf7kpaq4&@lKTmFQnDYcFMW`CjoDb&OJgR=& zym3FV@uN}u(Uc#{_BOeleHLLGxmZ5(z2c1hhY6qVGSjbn%=t40{qTcBfnNH0t!@G8 zI&iTE*W&@PV)Bq#T3|S`w-srq>)U0?r}}Gzsd>G_=9lG?V>TP_&ePR!^ZSJbM!(6~ zvM9(Thp!;4+}y!*y#P6^z9(_e~@xf>X(>-$3|Xy^II6E7>y#2zY537-mc z0-=&@YhgP#D0-TFfem_uA#yhRpUk&mA`qIY$x|ZJB*V-dv1g=H zZ6jEfE=K(50;`6L)xbz#H*KRK#KBDxD-#JAGLRHV_=<-C4j{JNyylD~2+GBP^*V|MLPJ1tnmnq;f*C0aE%y&?2#w|+tha40s+s|d$EHAIOBco?#_?Zp zKVmuTAhO!pqS$OL&dewedkk99e){LbAJ@?lVI&P{^JU`4eSWhd`EUCXW; zj%I)evL5M#+?^hhN`%Z)1#Cjyz#w1?(iIa7%|XB&g(~UueO5`zR;FNI!@`Kq%6*u> zSj^`dP?&nZdNbMcLD@>^RV(QdRLXu~2^ zji9g8X@W?kQ<`ifEbpv3Un^~05yM2P;&W(iyE?t+A4%r~+23ff<{?6rWedLm#B({W z;ZiGcAD9d$(wC-9hsl3{=Fo_?VBYxmE{ZL%oP-NR-Cg{J1a@%Mh+W?dwT+Ht6EFF2 zQyMm==cVWMS#TB@#2&y^;+TBGD#O>h=w+~#rN)BT(&N+8d{7{Bw+Rl&FUkM|tw+kp zS{2nFYGhqzZz_qvO#vaT7v zoDGx&%YE&Q_2+4#dcXL4wAFRFJ)UI|LG6R28=vZKtNNYCIB2NYlK)_ge}M#~*&n96 zr%R$hs#0~^h97L25d+_64hf10wn3zCwJ|jr%IbA!{w(i^gI(VB$y5ZV=5O^qIWV!~ zm`=aV%O^#1={bkuWQ3(iWJW{O$B_NF41MQd>$DP+nBu#eu`>o;rZeEwBUGM0*?i9# zeSwyR8wW5eDAr_#G*^&mQ3sifxa;7yNUxiZII%C&*a@XveesDng(P>ZLGGIk(C%Vs zqA=*0_nmL&1@T3-$c7=!X&(Pu%;qAxo+R{kjm=p3u@nzy!4b9f&`lsSd8Hqzn4r6B zF__DGUIA{Ji{$knmk2Nxsbzv3rxEzBPa4sAt#xS=qZC+ZAgFQ#s$Cpq%K zNKrDl)}BK|KA_MP!N@ha+d!M^nv$?nm1NYY7WyO^oa-|b zN=rck|ARC6jNhC1wOhT5)nG*|1eCLOCQT;yo-ddaK*V69fMN%S@8Wll6r8F~=lG)k zB$L^_9_)V@Eg&orviYF|A7_)!7P22&ybtoO6YV$Lbar-A*GyiCK9X_gyAMGnIAf-lmaPUZG-&3O)H_tbc z#WpzLE{L_5rIL3g^)e%Oq>14TJ*1lswz3)Jiju%seW4_k8^-PCe55rJ^W8i~DqM&< z@T)P-_DP+?yI*ohCcuNBL^QRxCQFE7<#Y4>7cjom-F}QYIcR*k^3A|e-1qn3-IhYOr zzW_$LGfJr;($K@*c4E>zRp=3#y4kIRjVN{obDFs}eK`(XCB5TPTi08caZADleA7nK&`c=hf_@)DYt;o6KYTL_*J zoW_g7o)aYl(iyX8_2PD1Werz-1Z-hOExgQR6Z~(hNH@Xif2_`fC$V6F;F#8$pa6e- zYL6|jHCe}-vs1Ed<4ZV4V>~55S@N*xeaZ0HiC?_2<>n9{e=o~X4T1@7@=zpqrkn0e zM&M5M03*k^E)0yQl$e95`^Y_CQ*OiCN|QUqna3aQ+P;^i8=%pL|2!>#haAv;NVmOt zJ*%`oDDrO6q+wPpFli}1a!}=P*EHLp8_Qz9bWzO~*i%&;KobBQce7(%fz`RFsMe zFuLcJ!n9GAwU_j!ut_~gm+fFNC(v(`ElbnfvR7?6bNBPBr;oRcT}XHWSMC%3;X^n5 z?zKJq+{?Jb&s|>ona>V6G_uyMzFXKi?Ug$)EPuNcq=~S}!-AE|O7+5JMLF!yg#Z^W zhra|1MHKk04?u8M49bDvg)3+$d%Ua>c~cLm%`y=)L(52nMIuLAv4UZ&I4nd)kgC3K zV$XeT`Uzb6;C22daO=A;vGV1#&(?QeD|>$eXBz`@lA3fa`QJ_i4~D8ILGCHe_`eOV&<813Pj|qC+%H5HMW*0Rm&X?wb;T)0?>f8$p15kZDmOMtp}b0Gi&TReRIRr&s%! zT9DOuo`buf<*74EtRI99dC+Er*jy{`dLq+pkt|_ZlCkb)yFuw#J%rKzNo(33x*yFS;Qa>m)%c^??NDUdw zcgAux{nrjN!+He}RYEapWcxJDMIVxSb5G*Ef6j8v!wHZvw?Yrn`~`NX~l{z#odFKs$l57J+U z`tex|Ouf-WDfhISRo{ys@tYtlanKfnubGA-NCk}{K>QbRzE$uo)iIlZ#Btp6n3M}0lCIT3N-89XlC z^|@&uzB&wQXVP~QFl0f{?|=oyfA&^%`|~MxU(o?pA2hOoM3}R{41vGx~v> zi52Yps<|I?IDUL-@Jv~0cq7sf`O;LXS`b;^dWkO8`dCtwlG#U?7WUSE0~9UQ6)9g`$3@QTMFcVvl%d zaMr%n-d963uO-A8RwB;)*1u})9>gXmNZXM5ey^etbqwTub5H~nJSm<`T=XFxs;Kr5q+hXQ#6_ZsCb?A4R zlLw_?-{5ba&flt2gSs$R6eHM|l54DkX2$j|o663Jqw(J3r=q7GjB-6yIM2S5a zn@cDw(uzrD@LM1ZGBcFBBAsa$MLEJ~T7_hPk_X+$R%Y~wjvz(H7g}ID>JVeauS50N zA=hgL-7_Sbg(p_glHDv9l3#>sUNiGcr6wbjks2TuSi5^nM0guz-niv1yA=QWNck&N zJjh#Qt4>plh!=I{!LYL4>60jw6smYYe0E1Kx~M3kpp0`UB7Qb+3s_j)eD4pnnGf|c ztGpf&4~v|If!QgX8H2^$KBO=LskzRbs!E(vsL}$Cyp47R$!x6?^?q!s8?YsF(4Qu3 zHL$4vtp+-g3c`2nJl)hM%4fyj>1`UI`eXJS8G-D~1RK7qg5ras(CFfWb@RSG+g1G6 zKIcE|^V<01U1qQIutjPWJxNaPDa1@Fs8O4v>;^rm5v^Wnl4OY;zRE0YLfMAn^4{2- zFbj+;jG*1`UWRN%mpy`%g_=|h5iBWTP zbKI~;>r=9`m+Op=F|R~#T-BuS_v5kE%PUzZZS6STk(Plb{>x?Q10tx&sLP$b0O~~Y zQUh)q{GL+$l0)fidctc^!Gx|4s}ACHTOf998j${`f3Ya>!Y-lklgVPZXp86zC}hyZ zE)T@caCfT4vCrEs1rg-@SdqE}(I$tIlC!xig0vL}ORC{EA=BhYP72Ydx7LEO4A5d| z4~XZqSjcfc1#O32z%mxF&O5?xC`!h~(BjF6iOm~}BDTb+zV=U5rxuM`8DeLzl_%!j zPq9nC^2t1x{xvUfnu_To15=VS_S^t&TnvSX%!Re0wgz5%ak?C}$MfN=ZjyU?#D)KV)ZkFcyE6)4B2_*rbE*Cl6)KEJ+JNt*}Mw0mNyvC<)SkuLzGZ)bmL#G zq0;)9Gh-Jzpw*$uQxv_YLhPcV2Ch|X=}emR06{&6{Hl>hhN{Z7>`-7DS1>bG&N;u$ zJv#IDhd;C~ZJfUK`adQTN9RF`q0zI-A*Rb?`7h5nmIPTwgJ6e%`Mck@8>xdy?qB8m z=253A9@#xi+hdX=xuP4P?-XQR#XMX+i)y2m*5*C^CPc`756=d6Oy`mjH(fzoOu?}a zXwXWHDC1W7V2u1lssfeee)Esysb;$c_Xt~1#u}7vJHhCvcTqj<<=BE8-O0=WposTa zGLd9_!d)wE^L3#v_Bcp4iWBApg{O40>P~LW#&;*TYR=Q^-^NJFGf>HK9PfcS?$HW^ z2V)nw43UOhk8~(vpXbQh_MSjes(=K)%>^?r{KQyAfJ2Nob7QYVvAzMfXjy))aZ3O; z*BEPpPQ<^#MpuxroR&(HL0qf5HD`6+BWYP^zXJTr0XH2e&P0$Yi!|EkolR3fLW0laaWOTYP3ZZt=lr8>&&2u1 zm)t*Ih;(U4{PhfM6(@j5n91d24M8F@PMryQTAN1L8sKm@(C?yHAH+NTqlT~<6wNaF zQMJt>WyBrD)2+6yb{B}}jGz_wK2*h2v4xd#?9p8K`<~frj~|a)9ocLJIo|gk2txQ2 zC?iS&SlJ3ikaVDAC=+jeo+6)~r{xRcPg`M4)?R^3dw)-zC%+A~V05Mu^`g_JVpZM2{!XbqKE=+{67L-B zNreQ)!|1#9e=#U}9>U@@US+ z)JywI=g|vY(y5DT(P<#?Dhhjqk+q~)*IqBa0;LEGpuRTm;dCO}&@(0L2gV3+VN4Yt zltBbQ4ymS=N{7$})c4mus~*68QLmL2gY9&iq^81PQWpVGN!g0r9$=%e1)L5XLj`tn*-~bW-K1T^m+r7xkK5xG)|-cufPWvZ+R;bpC$+FYN=&W5&Pc; zH=$3cPiksu!q~4|*kwGH5C1ZUl&1kN;vKW-8(ZOPCxqc=U!MBU?mt}DpYI@Q7AFSit*aYD}=GcX1{jm;3g> zV@q?Zg9kwdMJ5Sgh+@cU0ogQFC_79epl(pD-sM@jpBdRh>5@w7tq2lR?GDj(lXOVX zs+Y~VCA}#*-nUvhPup=O6jSFE#jpR1XE(*&zFj5=W%q#9x=6jGEX>AuBV@J`WZu)9 zB5IMa&5S1u)s6Jwo1Q26zMUY8AW>z2ed#%0mMo6De?w*uw2d!HD6^0Un&7&F3$@zN z!VK+$b493+C9j=>gLD~5>L8LUji1!L4QeN?#Op{7B;exT#@h$2zDM@$n3bChWy(vE zu3TZ$*A8wik97(9bI|H^i8-F~_v_z$_dH!Hb$ERmS$3m%i`A*)>+};?`9O?oXHs`=z-<7zjpI ztV8hCHYICS<-hTuwL#;O196i%48`4#K_5vyGbJZGEHBplO{jEnmEJdGY4$4b6bB_az&e+nCRrh{1W)iY4wtD}AeeofC zbjL~aIAN;b>KalXZ|h{7TeHU346_W|Gh0ohC8dnQ(@d84t9F=1&z5O#2U=>t5n2VR zY7X@+&PS-yF~CfT$FV>kDV=#2X@}M5l9l!Nb&oi!(xuwUSCI2xYi)1^xr$nm=A8)6 zY(ugeE=BEWxlXxNqSqQKZ~FOZCXh7`BEB@{M((|<^w4YJD z*?2T_o4DlKvnUJSJ~lP~SxsalBti|w0Xo+d26=Eonz_@aX*KfK5Yvq#2=wlb_ZqkAWWYe+1gKP034G_|_ ztCe~l&yLKHKamhsBl^OY+oLw%qBI;VSV|WN0+QlFh&9FEw5W>Q>TbGbPp}FUADMvk zqm^0kAU?imaxx7!W-(7db{3=P*SW{t8^Mlw?Q(k$3~qGccJT*{;YagZd^i7=FETx* zmOZGwi8{}%E4|I#@mX$u_x9IAA6pJQzh-_V_1c;{MR8tp-pvu#4lEmFUMXiy8@0!U zUp3+rGlcD&tt5GjtUE1V8oX9@VXu)%K*n(`O`rKEE&W=j&zWD*yI1V=$Xbg9kMr(L z(w}*n+hN{3`D?iwLE%CC?K03a}G=BIg`*eBVx*j)1T-H?Xsy{DWL)IgY+BOkQOzgeBeeRsQAdAlYBszm*foz4?M3!v2{B30IG?z6X zS#P>U>)dY{$@{zC417JZ>tqYNZY zoZx`B8oYVBjILV_e3qY)98W`-ewG?hXGUt^udJVWDY{$-h?;#(Xx&?%^w4^{{+8GY zbn#Lcw~9_$7tnoc3=Xt;%@GK%ocj=$a!z@@3j*am{a#0qRc2cuwtF%XHJbB_91>wg z?9%YRcFEpJ0gn;J^9`8;mOuVD<;f{G#Z7@-Bn5g@_Qu#4<6W1eS;k<+!!NVMu)pJJ zx>cX*20HDVW-m@ePdvWA|IMV}ng4h+p*C|OnR3Tr(&=t-ASzD-#1UiOj$iaDx!O{( zjZ(EVFkY*44DM5bixHy7eHsqcFw?K!s#>%dtU4N0SxNw6i>k!+uO^&d@QXecaW+Fs zKZXzb8){4io%M{PldUG-ozy$61! zQzk4oLw#T-dnch!&WBSFyM!unY^mJJBon8lg8@c$bQXho%OBLSEyipy2V3-=7rurR zWm*^91G4~Ca&}<=wjcMB$si!HBF#E6vIPJEc$X}>X5EuU0BF~Gwck5C;AkoOV z?8iY&;L7=+9w32Z9L`L`L9w8C;NGcw9dF*4eoMSSem1>;y|3T@(q}$)YY|wry0H89 zU63zQm3^exoyQ<$;Va7Y2DNX;z$Ij!+$c2GDn7UK(`WgfZHlcy;*TZd)x?YEj$Io2 zdTiul=+<=)!fkMh8x#%FPHCZK%QwIeVvo`zx3s||NQza%)rs|kjW=8xT8aZ_G%aa& z`gg?@#@T4p{np<_c$R50TkfSzQTw85)s(fjpLsdH{a)%`&*Fj`j&+5)TTh?CLC)$z zi<}1Tr=C0Dy75-}V8ew?2}|DteqD8{dcAr*Q9J{Di~o??e@OZVMFA}yD8XFRNN|hF87L>tUhm5Je%iP^)1I! zso8^BS;8dg5^Ww)b*g{}F^c^VMF~NVI|My_VLKfwmeT@jwGIBx=LQ-yT;u;%yoTQd zEWd$R9ZAS@CFTZJ%UYdNu)Q3VYq;?qn=2dj)(u*97}bk?c2T;iCkbU4+9=GbYsJC+ zy*fv}*0-svxd>Co%l6~ew$P@lXmlg6rp!ymuZb>U8Vqg=a46zvZ*&QQ7opx|pFW)S zmiPuAd!CX%F4PqHeU>UuvP12Wfb?9O7D#8sjdM`uc0ygI?I#&6#;Zt4M4r1!OnMAk z7hm?ooc%iWAy_Q+fC{O8P#9%tldK2b{Va@!_I| zO*0}-hp}KLl{D*0 z*9f!S+C#o#c2Qj?)Y~7pS2qzc`91<>5Cub}_TYRIt&6yq%*rpo+_pkf`^5-k|BN>F zYuD7t3H1kLpH|C-7c)2U}ma}iL!D?wd zZ6oyPgiEk_*09N()QRb>Qafh!tadSgA)fp;V!4@dtkI`&ThDH{88&lk_?~@Feheto z+t(d`B(>h^_oT{UO~rog9Wxtr0@>p)&3Hly7t3xvu68svpBHdwdQ1?Yv&lJ2Gr-k< z@2kHa{l0J0yW&5Ra?TB$Tl4s@#E*xEu{SRN{q^g{15f_?`_H)pgIvZAc60@($IUO& zP81D4ylKDhNULK!|6M9I&v~93ruqi}Q%Z2l$i+5-y*KCEM?p!Db%jBU@-w$s?X52` z0^jbB`G2T-_jsoJ|BwH@14Ar_DROAB*jBlW(VS{3j2JdlE_DgXT#`c(9j?ux!S2a&E_$3F%CDpnh^>2QQk? zli|+ko7F&Umm%`_FPx_u?Zvz6+wlgHc{g}nW$lhiDZe1%GMKMxGjvghoESs(-8f`} zH|Ca&9{b!rmHi258?^0E681Ayo5PLka8KlY<~Mz*L=G;BV0Ye|IWKmPwHS7s>Z9~I zPI2v5z+f*VlC43A14C(OV&U(|S1m?&=7cA}-@cT{oacY`f7xmM%`|!R%sngTiSnQy zQ_15~hGYK#@qq||>E1E_vw(oeYM$>qd$zS^`$nrMc*D(zf@w9uJBJq=7G2-gP!OX9 zs?l3t)f{miGAoW(b=&Lh+v0m2cWS>kegEI3%}H$4iF@z5yRb_gFqBZhDTIx3^J}zP z4DR@?1LxKVn;FF{Hb+Q+LR&7cWhzO!JHfg~8|SSCCnZWB8!QrD`A^)-gr zlV$8v4wF{}etZ?miJCePHV)>O6E5AXP^=9;OCIp)nB>M8Go!R;7JN~l2BCmro`ZQC zU&6NY{ELm5YqYuI01_ER6Rf2paq^p<9q81=ev{8MRRot68wG$uSY1!xc~=ATk!P3Q z9sR59U2I7A){ON@9i9+64tfpMEcqdeF+aF~J!g>-*}(}4fTpg8A5M3tRzD2jwiJvd zSjo`_$~$!H%4QSaJ3d%U>QK6!?y~e<74qAz8feq`WaH&I9(rVB$Y6jGKiX%gD;#jr z9!-q%BDc&%W_9mA2JwM5UeBU~kU-+l&}ZjWkXk#p>tlmq@G|Nk|uOJ(opcPd%HM zU>NlR)6mvS370_ItZY5$1`E`U09DAJ@GRk%_)3z6oAb|@Mn!hlG@D&H$J(EaoA7TW zq681HoB44lg`Mi#pLTm1wrsdqVlWi3GO*6rXHRcCQsFtp)!1WMyP3jY8dbHEHMIIz z{S#c_H|njCf+@1wti$x|b>_1&!pbM>M)4IHnuixWeGO2!Skp2vF0BboKZ(aG@YhJW z>D+=~kqJRQS+p*hF})$fnE4te2T>%|%8B&74^@rQ%EY{-E+pHxc`}2YGVdphymL}K zxb5WSf5{Hh_Z1Htl5UUho~Cu}5^TEY6cd_Yec-&qdk)`=ec&RLm`C^OlRrFZDC9RTPuars>qMyOyZx1$xbJYWDSA3Pp>6z%g-6Dt-bDw zi$gXg+Im@BNz}sz1?s>h`yMmo$0mgJ@S35}FW{s-mcG%=gryA2$yl>MuMiiylKYA6 zm`x*fe3dO5BIcqATX*rKvE&M)&!8d|Y zMYP()TA|UT@@J8|VFkTS@$1gHZqk$|jR)W@U#sks5k>@^!_*b&q#xk?cX1%0yECV7Bo)Rwavv#4QQu+A^H+I4js_HB&%764Ko4|%K zkpI0n`?zh*-JRR9Le6Va_gB-#=qDqc&Njb!Y#lg%+#X-#{-j0i;LY8k7qCK^fx(*u zA~ueT!`30<5s)x}ItQkjQQD&*r6eAswnD~(p+Kmh&fAfnKWj4Ip!R=w+2gA{nHu|1 z$7*OQ^+NO<;-(AX&6Aq08@ujrhfYx(3{5_yV4!@)6!~qUXWa%>7V$SLrcQBq;)a}B zEW>YIci=W2JT6YXyRCD#e?Yxp`+~Rh@8Ba0?aJECn4@I*>euk^mLA3Q5Xi_%%*XeB z>0TQO*!4Lo7H_goZclC{-`J8DD+#J5Mt+hrP2c~u{axqFIj8s^E~N5Qg`PCq%iU<;(bJ@h$!`HvcG`P1gCh-MgxKOX#y4B|2(z#ku_EcDJStA+u>7>&P>q zs8$ajRCyF3+UH)$_Q{HVLoupEHN*n|vKJj>cf-X|xOp)=ms1HltdrxW$2V>jGSG^8Xs?0?n<}O-(n7w`M#;;@h54P6l=|tNN$>2Z3>NzSSW91Oo@8q;OFfJpo3-m+Ne->4 zl;M=HcRseYRxsnA0g&IouE5;4G~sT9rmx$ zMX3B=6V*R9oW;)X^;s)oCBVi$2o=&qe{r?Ypv{}X%)gR^)97phP+84B$p z!(M0f5<61d8N2kzGC1zHU_TNa0@<684RK&Ff`o$)a17z#^=?$WG4Ck*EIMUHBUlB% z>v)S-ZdO`W3Tg&&>Uhj-uDD7-)pX{@YI#Y+Rpl|pug<%!aH%(3vAURutFDTx9c;6T z^7!Fms)j0S>GJ$u8Y;~Z+?z#U8kiEP5kMLRy;_iL06#{)bT3zDdxa>}MXGl8pbV&? zTAgP2yZOk^#CMY~W4sQIX9k*hIzu}edeo4ipIlyxK{So|<(Gol;|IsSyq!xTl}(U% zAD=rc@}uQPF#fK_52isly6o;SyQz7R-fvK)!_Nlf)kW}N+Z4pnZ;^M6Mk zh%&T_XKVpq;_-%ra)M}U+FGwub_ZF?$!hgm1T>+6soj!g_2!s`8$1M0&w7>Z>`O;W*B*^dors6qyC_U4L8@Z5k1 zQxcnU$9VABSNzECst(SJ7h4XuBDfF2Yu(*hGp&RMm?_cBmT3y6n(YWf9|!WMe|Je? ziA}kv!~E9xMPahI%b5%D^UQ>)fId_)R@@$~oKD>P7ke{=ZnW*_O8V>8Rd=MRy9dg| z!+flSZQW@X+BNv2@9kpe*1e{xD9dsbVjzByO|)*`^JwY%FTMM=0B&BD@8)DC=mRyf z3m)c69#7=PzF~}?C9=bxB@PSwOKwZsj-5Pv{P^h;cl`Dead)>F=cx&bRC7ADtzLOJ z?VF{@XN%0r;KEmdFZ}P;)WhoBm1sohCmV;h>Ezj*jltS$!Dxg%BL(C;4ebVP#$)oA z=c#{IPZ^1VPMkz<-*g0P-De}_S$CP61L8!apy``?ZmHSIe^;MXZFpJ5&{9MF!D_PJ z#`BGjP0?EqH&5?&MnuzjI&0}=0~7@t@@K$C{L*#@Y$)DW9yL!7j>tAHIcvw7stsh@ zmw*pXMY&R+>`%_B_exJY7lt__%Il`|8>8nq-BmDd@V@(O6V_Oi|I4xfY(@S_>7d>~ zDCi~t_9c!*Wa-)o3N1hT>8|sUY)5ypW)feg=o|j#wRKa&2NF%iSyKV)D*bwQA?Vs1XpR=K#}V?-wI&V-X%(TV z9RrB~azF1848>vIIQj?VtX18lckQwbiE-<=d6eO}eYjSOd9FLDBO$H_FK&;ktaSjn z=+AfWJN|4)|C4-aBgiUXE6VPvebIOQ96OO+T19I4-uiK&*Pd-+7PIDaWfoCEAO1JDCH+(#%lTo7cpDcyF?9EoX@e{s6te3aj0r>dZ$%xfvyEOFj& z=7J}C1rM^z_K+{8C*&g!-3;s~rfipYv77Iv4SE`0YqTjcx18ZUX`2~!I(|f@m8L2Z z4IV8yPF=^{Eti-Osk;X`g94fI$liE1wIgM2l&#C@#jLW<#7m(d3@sK3fF6U@DX~5& zQV)Pr!#NAXx!|mQ%-H7M@D}8wCv($SuwIC^)|ElP4Ve!FEM$HakLdC9^|+Dmme%!d zVSo50v23oEzaK5vDYC`me!+1DPRxCj#zBb;guu_3o4Oq%FKr|X8L=R8&o)(e9%9d~ zno?{?T2K@@%yB& z*ItToK{DpV{fX z#W#*`dtdwI+Z~06^XaDtlOIjG^)wM5Ch)Gq)s$)K`X)0&SFR+lzrFa`Dl#{Dq~`Kp z`>e(Sse$0*1wnBTq;VOyRDG#;Jq$1Is*Dps<%E2HAkrGlCyB*;V{eppydPm;yJ zJ0T%#NO%I#TvNZ@Ks7qBN+EBDuM;+0JJsi*Xx#>Z2`Z{2bb+xh44z91QKlZPWx$rM z50^MH23la7F^G~YJ&9_VUsX)Vv*yKo`fA)E z`3hP8c(;Z(<6&Tl{0c7xXO+v9*nf(DO*sFJ9$()1^g{g7HT7!^Jn&uVvFT7ZWy!Rm zLFuH>Iee`0dsIW=EW~-x_$X%Z0StPl$=wSR8YB8VqHh*sNd~wRF0HbEg8gi%8Vx@p z*~D<88eGPiTd`wZJ5MM-pgneoj#f{y%}4QaeY2F`c9#DA->)gB?XzFTH{5sa2?sG{ zVJJW0DNj+S?&UbRxFkKX$}LNO&jF*T4c1Y2lSS9hX!Ey4>VZhWlGxn^g1C{0P(e+SeiP!&2R?8>zg-ilXE<*ml0nQrt=$@NzYA)yP z+lM_HZLp?6gYH7;l(_rWV%NLKzCHNpuiAMin(8W29iYtnF8D&>CD%EyaL<_V1gtw$XfR$wDR`HYeHRD{-uh#lzIwEv9_LAUOU`whr9j z-;9V*0xpXpJ?g?TfRh%eT9%+eCb-wFS*l~3U1&F238A5RVZ@5CgoUVuU@fNk{FnI! zhSE^8XdZ89#%+(g;{fs$xrH^vq^;J=DruZyZix1XvvxE)N7n{sZjLemaByU9c@y{r z3M<mFq!_V7HT)E5nP)u{XTya8;@&N2zeXn@pkcq6>+iKm@af248<|Yd3VVHAL#L ziSO==SqTt@G6^5AJKcy{V_O%9kZp~FzTzf}Zf?UzhAf7)uOmj%({>_UA-{EyQ^`rV_|v$@+%c!^F%x4+w%LzMkO&D#NYaC&Q2xG*^rYp9 zf=wwMM)hAiB{ni>8C3egCrzlQaM=|QqD)9`;E9pA*MCUFGv-al_xpaVqCdRg z73?<8WDDMXhVsr>Ms|L`Dc28YC*CdV?sSd_D=OB;d~64JSbXQT{so4cW?q-srDWTq z2~3qmsN(WMC9^VvFz$ zQr{_uA031RBXU9y>5fV1E$U9EV@3hOyDmxT4G92p^ymLOHOvM*f3`+0UR?ahPnI0> zYF}=g`c9EWr5I>T<%qoUe4Y3=u7)P_K$GOU@J~rjq&sYVAw|Q*HxwVH;e{8&bxNpC zifR!Q-%AL4vVYmqqMXmYX^1EcA>gv4*y&LADP*Fc|E3zR9Fk9c-Wd!LcWYkP7}tLk z`-D4orO`(3Pobpm$p1W(85Hs!`@Rc`I~QW=IdzlTwk%R#$6^q$`^+4; z#p`*bU0z3Ddv*>N2^wzJS8XTByPQH`^< zCK^uY6rcU9UZ`UyZqb|7`MEy)13C1{Rk( zhv{(PTCZeS!~Y=CkH0N1&HyYoJ z4)~tV0mQy4EBx{UvCVswh?wTx0{qj|b`+kLbmpC{HwpWkN0F-Yd-n@0o{x!4&Ti+6=4sRcBUFXRIjCXSKHczdldms(Z8XS>TKP zTjqY(rp6c>n_fVr^UGeN$b;{Cs-LtoodR-qy>oE#aLw!PWDe(?6rrAav|?7djmuT< zs`ADaHorGaNB#aR>AGeD5mi;ho#n=x%wKS+VY3{n%30ri?AZqH1fo~$C=`pA5hQ2v z&^XHj=&URh^fg?_?^IirwJb>)Sp>|%9^Pis2S68>E~-*Flhp1WBn|J^*CFGOZf6M* zTv}OW!2uKXpdh5Sho9@T&U;_ykGt1}9q7h=0=cNVO%-Jg45c5!ktu(dIyeb3l84D_ycz$dMZuC{M0@S3pvT(12?8hOXbl`dy zt2l2sf_WbL&#pia0BqEDdE-^#>0u$Hnj<5aL|5us1m=U2q7uL6IO7{*Ju229yC55d zH61@X1k$#AUqlIhI)PG^qe5}|7K!bxt4nBh+6z%B^Ev8gzj17%Pet1rta zCgv#g!PS`UffWq=G+Aqhv)|^4x#ddqS%b;7NAn!dGjlwe%e? zvM~wNKEOGSmYHP;a%`G{wlu2~M<`u5MEX!1WzkzS0HYr^puLC~Uu;P|W*%v@=Cj`U zaR()!+G=;ZZQ*QICkx(_?o7OXdKda})B0gfykI<(|A>(U7+LBjfbe-oj_DXNFeIVdYq$f zJbuJ3utc%reD9hYPkj<0ae}=5Sf5{_3uhK3IYxUEV@kC#HVrRAMNaSH#K&Xqyu4H< z%7Il=%}Vr48{W7M3RR;o>E@r5A@^LTn5*;BsFs$-Xz4#DC`+zuyAeVIFM&#so8kOK zH#HO&WH4pyK(=4!?W6sFC;iv?ZptWWX`wIm%e)`4kmBd*a)G?O=*ijS&&}+oTzB!% zU$d##N1l<3N7-$??TfP>>oz9`wLQYq1CiOSU-)BJXJbw}mq$bK0qiUAE264&ch4#~ zGq{Yl&v`I(2SK9_2Zy0h*S_o+nv1EAf#uRsu5Vpxv`NdN@}V4bKe>3(lTQ&5>~=TJ zI8Vp(mmSl~Pb>6^aU|-6YAKp+N$?1iB*VJ@no2l#XU$={<37ggx>y#IxcI02k zr5St?hiJwcnijW%li>M}^W>hC4no0bUwp0q_TU_a+Iv?mZ3V5}i&|AsqodwOk-e?B zQ~pWqcG*y~9p7@UtWj@TtXex@`33}<=x&Z5T3l--TKP_5#n-uwu#WAtF_&Pd7BP$bf zUo>skF#5ykHZN(6Z@VD;slP6P=oxmZ3oY4;4_zDg5c|{YTFsvEI4H+(m8sR^j8Dlr zCFUxcZAPi*vGy9%h_<%rh{W`+*DRu=y;dhL2_&Amg3b7wBEriS&m)>1*cs1_gsJK| zLlgBHLw!s`8fP^UsIsai1lq-%$UI9j^yZX<%lXq9NAL>)8QqXv*969}M> zZM~81acabo6l9`C0U=k%fLp(!h2TFZk%~-DA6WShj{{D>O35zAq3c0FbK<=g1mRA| zSR6csymAp(ycd0}SG_jlaN+f)?L>Ro@gj~;+uC;Mv*OR+yo~XYYGXsX`t^6s>)Yn9 z(w~{eGe&L#qesSP29B}>)Z6aS&Uw_Y8=D4=XY&*A2=I19inY8~m{b0nuzyuy?u6u^ z!NYj1rReJ$k6`3eY{?!zE#Q^Ki+i9g?sNs<(Wy$_k^{K-t~|XkdeD_vG)|=$DkGK* zU2KO-g$Yr(bFR{F3FPBM8NqbmEo#lZoMxB1+VKluLN7$KtU>uBsoOd`G>SHf4f3t| zOXuHXM2~9|E!AV6cW z;liqs6TYg~q_I`Vp~060rauWN@=Yh*$o$0a>V8Yiaxcjy4iz1Txk&OAK>-CO-ll7B z7d_e2KYLy;B?D$UsCn*?wP%d|e=ne8V|`RegPl6J^E~012@u;3=%#~Fuf#7zsZFuW z80X|8*%Mc1141LXT#MzoqKeevbC z3)#VkK}x?!Wv>D6`jxX{&FZnTPIKP$u_;UErOs3?7rNq-uX3opD{a>9CJnroQNJ zXdV=B)bD-S>I|w|{wB_GN}`5h6TZ6;*uo*v#{lH7DH21OG4zNq?h>Cp=L68E_0?6A zk~Q3em9_Ag3=TK*uV)u(=4#>1>jqHXObu@S$9DH%&NTx9&pz+~?O>%-se@As-|^(q zl&t!}`U&2dn*Gxp`BFdgt%Hl~-(Cw;aQLP+@jNrf1wSU>Mp?PK(ZbCtYhWFvK#JJ1 zKTWP%nHCpktFXLtn!!wO3Zg#Ixwuu7BjzauLS36UUvJ?_@+gvGZ5iuM?Kb%)Wqivm z8rFT(ky*Ttza~7s&$bVBZai5m3TI0L!nt|1WV1c$X}>1LB~6)}KI(E`_|ym0=y;=0 zfAe-@g&YNfb+~w8`2%(x0)T3+?eL9^-2F3rUs*Mns90+N+igV#vbY!1zQ8#8|7~Dk zhB`U>p;^s~)CISUft8S4$fX(!-&H0zUF-dQGOrfb-83Vkw!2?v20}CQU=cuxIE)(x zylI|(!1ct1@{I>)E9dtL720n# zf!+4g9Fm8n?SDH6O5)#D7hQ2Z^g$Tb-p01A)B8U{R{8mgaW`)Vkt%a2QXJrJxpln; zt;<<35MS==TJFMHuMgRC6T^xo@X-8lQ7_#OoiG+B=A|WgxOVYt9>}bgog-fql{IjBbC{;o;>wNsGd@47|LpFL6v? zx4xbB359(dAV;WKQw;iXpHlP2r#}vIMsB{{$Bhav*@sj>WY{K$1^+9Z7_pvDfTejW zbXmhyHZUnVx$D>N9?df?_roafK}t>XYq2ur;9`aKo=$>JBEkQ4#HPJxX&b$e+w`@` zN>H0WB`QGncH032XHwj=2!Pn>@K04@hS$c&2!atUf%++Tpg7Vv;?)1|oz#4NBoGp!PR4mDbg zTETBHY{)g@3T?xB`L?p=73I`C&FvR>VSzkKRp@ZttYo+d6dLC)WCfn6jsVS%p~lJbbiCAH@|?UvN{j&_Y{B)7O*9z4a>C` zbVQ&2NUta!yn0Yp)OC0PussX(D$~Y;>c+Ho>(6fF+1yY1=XHXv4gI-zm4V#y%Zmt`wx(N!roYx7uD{~&FxEKmOmcNsWtaU3DmX`*zz!>;PosN;V5!3z zIx8Y-&?1as)4ra+UHjL6gvnJh@SrUx`ScR(bjW(4;r^kaxhYc!lRr#HqzoPE{*2}7 zngpV?C=Yn@=DwX}@s4cjrSOh!m|LA^wu>|@IyqaLhF+t|pQ7|q z<$>xp^#)>@+EfWY?R?&7K`Jx8*EycrjiN_Y>6HX7iBN!w@cN^0=D^2KRTG`&SuZ+G zQaX=!urV8e*8X`(j%J|6USqAD4*!D|m>wXx5}mQL)yWW3>~lS9ta(BhK4$V?;tEr6 z$MMdy811CGt{so!+u<0EQ^BFpr=mk00q3;~w&d@HGOTzo;y-vLs_KM{^!s^;^y2O#%fb> z5hr$ffB6C4IyW*nn6!p6>jkA|*i-C=hXyv4o{hGr$Z8szdl6{j{vT-0>hSE2?MuslkPW_gVF}_{DW7pg)))*cy zgj4$&#NBsK$8`I2vSQKWKg66IG)ZWD^cuPRkfVYP=~3(8gJkeDj9}Bs$Vzqd z$}W9wXVzQTretF)U)MZ&KT|HPH>ggCqv8-l=p`&X-gAf%3JjCv&cjZVWk9_dwM!!b zfIg=TF!DHK#cRX&s|#wpfI(tMzS3!M5%bX~p9OvMV|OZ&;=d^sFbGxa*?IWeQ0S!a zS1#4b0-(!fO-x^~i|15u;BUcsA^^Qaj>d^67Tl-Yf8t)4@bq-@5G?EOfj*-4UDdYV#WB(Ey9Vo0p?-C!T323Bs#yGi^$ zq>LD{BMMK5tZ1&H(}S|!y|>M|QMp*2YpA-0%_B|aQNtZVA>%*7Kh^-ta#zC?P_6U4 z9eVexx8(T{QC>b5Z_o+ypAGuGw2Nqz>-chK>w4AAsFH)?_`MAZ+)+%YX+iiABirG; zu;v4<*P(d#@eS(jKJwoK4)hXm%i<2gIEv$I+R#2dS?>CS0R8yL^@3jSEVKJdKvn-s zsI?0Ksx$C2+}ceOzTIs#z2!d`q2z7O+bn1RE~KI2M?r8l+LoUWHA^~JrP2PNY2RtE zEDi)qLnI;<6y`&;BY7(Lj835iN)RUUIrch^GH8?GM5%i>YuBeKS+1vdweRLE~P z)U%3={}P`a|J&&e}*DhrZ=?Joe1urCt=Fl4BG7<1If`&eQc9uBj$I?AgmD=9U1L${*ZH$`8t;FScyzE@YjmWFOz)t&o4 z4M4WF0=a9d0t8cO6Rd{SR-)g#>Zj?MXJSoTQZ^Q{8Ya68HepG~%zhkNyf#LW#)SYZ zkYSD)*AQ}f{N<6|=H|E@(xQ(nj%KN-B~@z!#;<0&fr1%%(_Kgz9lJP|-f!}WvdF(T z1m?WlJp$8)vS>y_5&10~=6N;voR&3jkm^)xF`DpkxJ+Kvu&Kg~AWy=~nw3y$w8JqO z8Yyj6<@stCIsV%vKFif3ew(iyY+kJ)qN+Bi?xF+B%r2*ZQ*-)JKH$**Ss~bG5@p$F zL)#x#GT8N9f21xe$;#KQn_~I`H}&%T86oqx$n}wl*`?<9eSKrX2h#=`X27zFSHqla zDW6qf_9sUD))ARaFHfipJz7^iP<`^~!5#zM<}EpE&CLaZ4iEEMFYCT`s(&}aLEgV6 z@41P~Yg{nN%boC8kmfjNR-)Z|KmQ)L;M1eq#=r&HJbSH%>dCl8j(yrCIY>9K#-=%G zr|6>za^dF{1^kiUV|-H9UbQQy1wXdr*qpsZ{Sh?^6f;-p(dS->pv{}~@okvld8!T& z@>0l3+rXjo`q;@FO~x~|9BnrjcZX_^;9^>b7UXQ_bt_CH-L?)sa&qCNP~)y0L%f?C zq_Ox_mxhtegm-z|tZiEKi6|pAQN^KMVN9!H$xH7i*?;RVEvV?!Q{} zkI?J)5_g#z=yl7NrLwNxpsg&#$KCKCbF$LLp@ugp){W;dko=~3?=dft zJMp6~wpWLXgc^xDZT}H+A5|B9rjN6v7_Bv{WfcopYxYBNsf+#R8X2zKTR!e`9Z$~Q zcv;TJJlDV~hb1xTd)s?13uU+7E9z{k52F64RJHW}wa(Dg2j0swfwxUonCc=h9S)wk`}xM%0P)$ z31E%_Ls%e?4zXzPN-g>V%@wd!cEk*|_DlZ=8XyusF|XVyJiDhfyp9bU<`eK=WKC~D z{mRi_PmvN_wAP~;hopAq-MG>-9oy>RR;P(e8#CRd!;*Gv-IER0tfkCM6&)R)j;Jjb z5A79o){Kc;uGn+f4b&(|UKu4#gQO>Gn)YYI`Hh?PcSQyGJXue)?bxqeD_ivRLZ!w* zep|EPrx8pI*}1s#0K+5VC+%F4AP{2?om1>m=>SS*2YGwBfRuL z3q-XTMQ)H23un? zGc#1W6I?=Sq-446pu`|pbrk@(WZr7MB#X9j+83&$*#AW;;2t*3Hyk+z7{HTe?h!fe zhWlK`GyOYKEIB{P(95Njn8POdw3os4hQ}mzE=hb}pcWQwU7atMXoFcjh*6b<#cQbb z;we&{lCUV9G&f?z%$MxH#G%H^&VR<1rJ53W;jpCG?|<9BJ^L;-{0`}P`Te2AhRo>9 z!=`UYJMJ6w(Zx-$9Wi{oI00B9!g zZTU@8E_jn3Q2>YNo_#!oKV?2FyzFg7-nQeaT*MjXgj|dWcpYsHY~)CKiqwiFzDZ-y z76s}5u>hyM_6=dzih?!uQU*;6j8kyC zm)3CJeufQrkd=r@PCI$`MmOlIlpp;FYanG7?7dYnwUug!MW5}5mnyhGzAdfYJy^x0 zt~D+xN{a&-LW;rse`n`q+$-F|?l8@8{WVq&(sC^;*U3D1a}~wB{25_V6luwI)9v`f zD@3=`CGp3bzn{P)nGbe^tUGiHWjw`?OEm@d3KO;JZ@V;=%2skm2VjzksO+piX9-Z>D4n-Wp+9&0r(T>U`%6onR`jZxN zWMD0QTfjrDR{Gne#q3(I3uZ+nn> zJzU=$ONyo7tWID3*%%OkTM0@JOg7C&&m^jiwUA$Zy7~4q^N+_nqOXOzyw>VQNM`5?G}O7;?=eQ3DFz&_x-HGqn-7TNup()F~`X+E%h)`!_Su8ykdab8SoP$QIn^0XSz1#ovLJlx=N`mp) z?65RjU#B?xIm)-&{QDz|ypvVWMCg2fz#w7d!T7EUHpV#MdRp{`M(rsw>~Q!KTc26^ z`HjEm(7qqZdlDw?_L2T^C2KI^<}++oC-=Otv(e*a)l@y;2eQDa!6znw`ghCCsd^P_ zUci`}ksE1$jYn#%)3e-0(;oGxi`$%ksimzeU&pRrXY0vfW{S5^6L_@F!cSd))*aE$ z|8wPm&9&Qo;|O8mdp~1l&*$=`K_@@jlkd#7$zmYI)4veABt7b^P}y<)$<|GnhrZ@! zIkn{Os2dNinU~!0o1#$qY`qEIZfBD9&57@J97_5!!2<(tJU*%uqZei$3?U?xbf5V= z*G-m%v`>$98ji++FEvnZs~EdUgg>N+lP%39uJl)7?Pfrtoj6<>)ERv6h21`j_Tnzj zjb|$MTrAL?&Lj#|jXvyBMnq_$MJL1zNB;Rz&Cjmn#0RquVJCC98*DykU{i!JAPmL+~H(dG%p7OPGb*KJv~c?E6V9TW#+ z>xqm)Si)MD z*J}jzCO+8NB06i|pv(;QXK=ZTgq^T!F4uwb#c*Ta^`Z3PYIS^NtqZu-!B-S=7wSCy z$Q)dV;dm)Yp1pJYZDcwx>OY_vD9D3(o8xvdtEqqyCmx>oUQ9FAM;at%slXTyS{UZF;`=x zz#Ix_QE|6rT0ygEUW+*_+XY4)GW6tf^)nv?4QA&U>kOmworijwVvF!(+7 z9|4(RPfRepwAIrx*LP=@d-o!Boz7iN;2Wv2MjUe}`XX}UaSLcQ+)m@6iyiE3-(u%m zv;y7(GaP=(PXl3^9J(RP=oVlrqN)@Zc9% z(o{g#G?MtNjO6TZ>zK-spHKqKd4mJO`m6nK)qH9a9%F}W^H|(>~-(zX0 zQyr*;J>aXx=eN}#6^{N*)@XP+FzF*>fB!+{j=G51&$!Z-LB#t-t` zQkT20d@Vio<9px20~Ug+;>%rgTY>6g*`nABr0M5)e}oL|PS)iTZp2eF`v_}N1Keb` z0Y&@Iy>fT60ULOl(Bq)aVIXCgu*>|1`A2K_GgNldQH^_(k=}7BnDD_O+j7E-b~Qu5 z2jrV$9ymQqb0M0M4({7lVH^qWV@ny4<&PR{N<1W)<@Chhcgf?I6P87N-PIA@o!F4LiM5!gL$9(c89Ld;kBd2SVvt!o-^VV-$@L zjYIjmo032MDC?cM@DG?5Pujoh^j5;ko4{T{>GXzhrg!1Ru2on!N61_=SuNme%Cys#h(sws)PUoR6B=cBFpvdRtohc;a^ai@!lkaAx9e)=0Fh5YDhrub@sIp$zEp7>lbpWSJvy`$lcWERnBCO+i0%kkO8m1oe5s+1ZP zsE@^-(06{&G-EK$xKiD1#CGU#Uv(n;9KGm-1TSQ4^@U^sWY}>E=&|57=Z@D>($qE8 z%t53YHO@@T6SO-N7hfiA_3Xw?=bp|@v1riK%{Mk4id6Mx*WSXpR*zW`n&Sc}=^MB^kyQ1Z=E@o|-KZlfeT$o`3)6 zh}fKhX;oR1o9Jq8=x#%_N?MdJ2*1uN=Jy$dh6ZSAsqEp!GaqT~!IU)JegFy@X{(dl2#uBLZKx(^oi?%YK)?W1QMkFu5U12crzn#!=`LCz zDO#3J)hy88m4EhINL`x|-S=_-A?pOn+-S)y&G1&bS)p6fCBsLa_r2Ht1+0(*5uAUY zximYptKdAF$F5Bc7I5HK*`V>BDR4cC#T(+5pp#_H3*`l7R=!@%F5=_wZHS$EwJ${s4#A()>@`fVZEPyZ7NZjA=tS3Jg>`M={vI_hnR@cKT5oC-4UZ*vq@^Qb{r zcc!OmL65!QJj#LmpL}Wd)^ON`(ORF=xF@E}=CqnQC{9Go&WFjN)Ro+nn#~nShyC?N zYc4g*zNQBim8|0?;Bu|`xD?|#4ekNHDjlA73d(y8v*h^4_IpL-+FCq=+2^2VyFtl@ zLRFy*OpD*JS~A_~gv{zSdh4o-WtlQbYt$N;ORtNszFN1P4Hx;;>}KjvPemmPE|d;) zMoOc1?>t@E`|nP7)W#dQvD`5*Hg`glu%Q>#`smhVd@tIn`mQW zOP`I!>6_50c6yqA78i?#G^5?CbjqW24#=8&Y5RurqS_goEA)md?Ho|G_LO@sf?Pg! zwwRx|p`!|Ou2&v4FcouN7UNJZGU;%+1N6Dyc^N1#wL4bl7u24IL{~#|eu}ZqzkV4s z8e%JTWhkxCP;yrg$?2grKl}v=(l8tSXe%3{l@Q8cG1!nVK>@lK?%yVJUGzg2n1R(f zLQ}8;KwOpfiV<+)Lt=pU1#}~s(G9l$STXiE733?^-)OlqG?3rf5QKtGfay`yrUi52 zEp#^flnLL1(lw{}=I6)+Y}PUMjG^6O_Z%RBxf4VF+lqMEe8KZ+9UwE%buS?iu6+mc*b z4V!Rxb85r_-PwM%c@|BAz(DB(gErIg4DBX^zSDEhUH;baDuo#U){a|P>HIX5&|=ad zrn3&HD}SC4q)AJ1Uu^zA2ezvTW)c!3$mj?DzN3UDGNi4p1gd)kM%gUVHG^0Ak@nuo z-=?zPiJ?>!L{pn9rp(tYFk_BTLIYNGxP|2GtF}qj@pr+3pTsejvwtyu3{sHq!a0RI z+0z5aJ(0reUaHZ44H^%W;i?r;pKPM#jHtsUFtZA2blvq1!mfat2F*|dJL|CUPyd1( zu4;n2<8tR+`cmmW&Ap+#(9q8d{V}HpU~O1a#}fF1V;CtXosP?ab(*GsTT#$@;q{1= zL%$Yon}xSPh**b-JYgE81J)1V*zVq6&C8?L(Gxv+Zm}I=lV~$FLz#R3mXtqUrj(v( zl^WU4o%=E6)HIfT=F2r}TsKfCr)K^-DBiX{pVacCyWgiJj>P{42EHJHV8Ol*bU%Ja z?XYr;#>0bwd>`9rG+6m196Fj#)xL$ENZyz8pXcQT6~qx*AemxzQ|eKU4>o2`a#niBq7m&;*YH-yBu-nneq`3PjE!+B_ul zUi7g_6B0`b<#)KmIA}g#nA#eBBxi%3>g8Poo<%(7y!NCm-ko&8JZ{&&qXyMDf&&N< z!R$8165UdqTRHzcwv4BC9uBoOxS3RlV8`dEBhpyJ46@$d{@QIA$e+#}Eq}1{N@VJp z7oESwB&~d=>MXt^1mz2O8g7QBV3{eBirW2WajrBY+w=351 zway0_JWw|Z)62VB%m>q`xqS&+$(lpFi#i(jXOE3tVHw56IXK(D>NjyTWu@0r%4&Yi z;r^fnFjJelH53YJ+rd%O9-UQ#X*x}HZSpKr;XTyw||6}`M zqokX*Eta!$|He7IPE>&PnAQFVy)U=A&LrM7S2#}!c_grNn+OzjMlFnVf54c41sAad zqO&3gWS5j2Px5KF_Q(7G4*O2rnQXS4KBxNJpxgL^YrpgMTtcFNwi`B8a&B^cB;8hc zl(#Zf6~(tNbj!3qAM^i^bly=-W$oKe0)!%+L_q=*2rWSwO2E)G0qF^lgeI1u2_z#( zQ3Na#sv1KHO}dmM5Q>6^;-EA1rU*i8fQnR6K&3ci8Q*XF`~IG_Tw~VpoV}mtzOO6g zZfZ8v?vApw=gN$*zOcjSbYReLUwq!E6S@~+))>8@t)7L~9f-oc+Bo+xIYpyKKj&Gs zAn_}gQdSDNQ#-ulw5e1JjrGI!_0bw=V)kp#fzUPr5B%TwHU0ggq;Sb8wnN^ zo%_rr_7dKVs8K&3M?~7&<{gN#5H9oWaW?)?o=>6{^Vn7z1%oJwWV0_pdDF4Lmm9#) zsJV_bn2?36XuaK~GWR%*rs6#1G-wL8d~)8LcyNI8n&kObLH66Z&~V~1*Y~sGf(6&K zlSapUzMY?3|13C2WhK+r5j)P-)4aLe1TDzBOR2?B#7$I93cHXfFj}WKY>} zO~&x>hqNhsBfTi&4!zv?afvA{qqjCRt*cP=I=vLlOF+nOHQaSQ*Ex0wV@-b!*wjJc zH&V!Xs%>ifj~J6r;@702YU(;fo%bsCM`0L(d|Q>|_9rIKN7fp=CiW6VoRmy;n7zy} zPb!Aw{a`pa_acecW6vC%-Kiff|3p+?WS7J-MoZrNjos<}acq>@qNr30>HdLEBO()~ z<)yG~;N&a;bjn1ZBUd(f&^HB69tKzV~!Y z8yPra_3sK&(*zfYwY{#JU)3m2YsZWzhK$NNo=T#*3EMpuN&bWP%u z2_9P`KzXzeohDXJL{I4GXU%ip6d>~qBVT&?hJ`dKDw@ma))><=yde^xs#hBYadfg{ zd)pf!uUr{3Ww-dYS9CrijFZ1j)dgI5_U%B)QpDm``-h=#M-LwRk5Ctjr(qD2v2=6s z$%{UH53DZTw~a(xdgdip!aAJ#ldDa^KQWIZ5I; zrpEcvLvEOEp6l_U_$cX=pVfeo<(e5<3$JJJ{276xV;X2aXU*-mb#2Q3!huyu$0Y?! z&s>#`McHlm_tQp#8Ce^eIqij+yB3976l%Y9of&SFTrU}3;Wqw#QyL}~6> zp76zsJiJbGVzWjE!c2QP&$E@da##Ym%ka+X@* zgzqf~*nvGG5>mHkvxdsgXmro{1c8M3|5dbkD7h+a-vpsTk@alnYIgZQyLv z9)yLeAVGWmlG8T~;k+RxQTML2RzviQdWX3u{VM5t`CS+ZRA~9ujXI|Ci{n&}tRYCH zr$x?%bAsWj7@OoLx1q~bu|t9T@V)!wp?)}-0*TVfbOk0-%MEbnB(IDaY1Bp4HHZri z(@MRw+d`vEn<0*Ap1ZteJS8UcpVWET&Y_3f@FhtvCuj+Kks}# zaYB(|Cr5->M`#@}G*hK}u=kZT(c4{^3 zJ6F>aXQ_F9>R3G2Z_kBOx9j9N>M=^_#TYQh&5`~aiOSxzb^U&)HGEFdZDcOSdX1pf zSvy>0THNpW;Y(NcrH!#-^`TGEkK(zUP!#Zi2yJ!{)sR*4VF0xV;mtTpLCmjf37;cG zsuu79z}q$&UM@by;ZW0P;D^}{LqC^U76Mq0WrP2;(9=AYT@+~HZF)hmkO!40t-o?E z?So%MH_#V{s8EDHnJAhv?&|&YU0h0#UqwYNJ6I1KeDN`Y-5$ z>Rgu_9}rTl&m`<|=)c;GAl|k&Kscw44~$C)ZWkEY$orF?YdUE%=H$KoCs`QdRf;Zu zI3?Im{Va zy8740^t8^Qe>_Z4Nf@sGNO6Cu zbRnT`MBPn;+Rs*!heE!wV*W5APCOZM&&{>*2?{BQCtlWeLKCd(LOC>qq;emcqa2AG z*&4JJ7mqtmm&C@$p0hai(tXSQo1<;s!vrIz5xa6+hBgaI&D2d%)5e}l_OY!uV4=MD z2doMB$)s(>U{tLx>z6cItZ(1OqIglq>Ewl0!??LmoS>Cz5Y`Hi(->!-NJ8 zt`pkY6J6opUf5y+3;14m~fuwyOu;L8@&R0dhbL@15Vcw*g9KzF- z-=UpmH+Rh*y(z`M6M4Da`X9hkdCoj}*5ap>_N=yTRX-rP&K zPkDADrWPIcpBvpwol@M@kWek`UHn%nJ2(_%pKi`L zPZt1KSKCCgBw^iih86|Br?8eWQN~3aGy1hVv_^{ssRDB$ISS9`-}y3 zSq~y@V~{EcC^V2#co0$-G$BPP$Y4H|0v|2kX)Fgf0{)}w=$Foc+q zIc;)wzh>y2dYpUZoXU;B$RaA{zVj1nbpf6OrXSPlEpriu5;rYo1hHSIoKH0+z4z|m zlLs3+l4}Ch{c@WnmvbdZ7`Z9AuRi~-lW|P0d}g^c0*ROZr@{FYMUYbrt7=im>Q;pg zVK4-Oy~R|U$CgTV%psjptJ26KpR*xN%B<($fC2eDyzoW*?6>gqC3{D$by?gc-c7w2 zE6zqtz2Z^5U}vaAJ2``q;f#Hrx|ge4L|jKj&s)A)LKf>TDm*0W`0L4+%ja6;VfmDU z)*CuUXc}Qz;a(=**`r$Kn!jhD%@-xwZks~~i2@HtivhIVl=Jz?XvByCUyG^SeO6eI z%BTtj#ZmXTCujDM#8eLsJ4_B-jfIb1gxLJT|D1TAv5km)k>?b4CZy@6 z-0j=t$dd$gswrtvTM19sznaa66j(=bFoWNy zJaVDEOQpnN{rEutFNUvQcAWkQ@DZh%fE>a0D|k3i@sMN6%g?i7K@O2PN@Q=>0xGHd zT_l8O;%T2Lb@;<`x;Y3vSyBA*yvks_StfQUukWEGKq|jYg6Ct=CXjBsC-prlpoe%q zdiMKEi}K_I(EDp5uAO}Sy!5H#AP&KfZ0*vmGcVTwt8>5bjSELXdp=>>`yMKRw_CAL@05hGd8S-

+>rMOvL;uV}qp-&>li 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

(iYbRfbpta)i7 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 ImBxSn*> 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%0D_2!&w$???@3A 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 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 deleted file mode 100644 index 470c34f..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 79b44f1..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 563d02e..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity +++ /dev/null @@ -1,2238 +0,0 @@ -%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: 12 - 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_LightingSettings: {fileID: 489442491} ---- !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 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 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.3826836, z: -0, w: -0.92387944} - m_LocalPosition: {x: 20, y: 1, z: -20} - m_LocalScale: {x: 10, y: 10, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 47225731} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 315, 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1727677799} - - {fileID: 62078680} - - {fileID: 589935541} - - {fileID: 34755346} - 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.9238796, z: -0, w: -0.38268325} - m_LocalPosition: {x: 20, y: 1, z: 20} - m_LocalScale: {x: 10, y: 10, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 47225731} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 225, 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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: 2 - 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: Tank - objectReference: {fileID: 0} - - target: {fileID: 160176459, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} - propertyPath: sceneId - value: 1579907432 - 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_ConstrainProportionsScale: 0 - 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!850595691 &489442491 -LightingSettings: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Settings.lighting - serializedVersion: 4 - m_GIWorkflowMode: 0 - m_EnableBakedLightmaps: 0 - m_EnableRealtimeLightmaps: 0 - m_RealtimeEnvironmentLighting: 1 - m_BounceScale: 1 - m_AlbedoBoost: 1 - m_IndirectOutputScale: 1 - m_UsingShadowmask: 0 - m_BakeBackend: 0 - m_LightmapMaxSize: 512 - m_BakeResolution: 10 - m_Padding: 2 - m_LightmapCompression: 3 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAO: 0 - m_MixedBakeMode: 0 - m_LightmapsBakeMode: 1 - m_FilterMode: 1 - m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_RealtimeResolution: 2 - m_ForceWhiteAlbedo: 0 - m_ForceUpdates: 0 - m_FinalGather: 0 - m_FinalGatherRayCount: 256 - m_FinalGatherFiltering: 1 - m_PVRCulling: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 256 - m_PVREnvironmentSampleCount: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_LightProbeSampleCountMultiplier: 4 - m_PVRBounces: 2 - m_PVRMinBounces: 2 - m_PVREnvironmentMIS: 0 - m_PVRFilteringMode: 2 - m_PVRDenoiserTypeDirect: 0 - m_PVRDenoiserTypeIndirect: 0 - m_PVRDenoiserTypeAO: 0 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_PVRTiledBaking: 0 ---- !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_ConstrainProportionsScale: 0 - 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.38268343, z: 0, w: 0.92387956} - m_LocalPosition: {x: -20, y: 1, z: -20} - m_LocalScale: {x: 20, y: 20, z: 20} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 47225731} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 45, 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, type: 3} - propertyPath: m_RootOrder - value: 0 - 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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, type: 3} - propertyPath: sceneId - value: 4277306991 - 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_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 748207075} - - {fileID: 901271863} - - {fileID: 160176456} - - {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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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 &1072006166 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 160176457, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} - m_PrefabInstance: {fileID: 160176455} - m_PrefabAsset: {fileID: 0} ---- !u!114 &1072006167 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1072006166} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b2e242ee38a14076a39934172a19079b, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - visRange: 10 ---- !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_ConstrainProportionsScale: 0 - 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_UseViewFrustumForShadowCasterCull: 1 - 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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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 &1471959939 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1471959942} - - component: {fileID: 1471959941} - - component: {fileID: 1471959940} - m_Layer: 0 - m_Name: EventSystem - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1471959940 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1471959939} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} - m_Name: - m_EditorClassIdentifier: - m_SendPointerHoverToParent: 1 - m_HorizontalAxis: Horizontal - m_VerticalAxis: Vertical - m_SubmitButton: Submit - m_CancelButton: Cancel - m_InputActionsPerSecond: 10 - m_RepeatDelay: 0.5 - m_ForceModuleActive: 0 ---- !u!114 &1471959941 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1471959939} - 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 &1471959942 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1471959939} - 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: 8 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 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_ConstrainProportionsScale: 0 - 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_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 0 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - 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 - m_AdditionalVertexStreams: {fileID: 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_ConstrainProportionsScale: 0 - 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} - - component: {fileID: 1661834282} - 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 - runInBackground: 1 - autoStartServerBuild: 1 - autoConnectClientBuild: 0 - sendRate: 30 - offlineScene: - onlineScene: - transport: {fileID: 1661834280} - networkAddress: localhost - maxConnections: 100 - authenticator: {fileID: 0} - playerPrefab: {fileID: 8872462076811691049, guid: a5bdca0a2315d43499be7dcef473fbc7, type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 1 - spawnPrefabs: [] - timeInterpolationGui: 0 - 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_ConstrainProportionsScale: 0 - 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 - SendWindowSize: 4096 - ReceiveWindowSize: 4096 - MaxRetransmit: 40 - MaximizeSocketBuffers: 1 - ReliableMaxMessageSize: 298449 - UnreliableMaxMessageSize: 1199 - 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: - offsetX: 0 - offsetY: 0 ---- !u!114 &1661834282 -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: 8f60becab051427fbdd3c8ac9ab4712b, type: 3} - m_Name: - m_EditorClassIdentifier: - visRange: 5 - rebuildInterval: 0.1 ---- !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_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: 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 - m_AdditionalVertexStreams: {fileID: 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.92387956, z: 0, w: 0.38268343} - m_LocalPosition: {x: -20, y: 1, z: 20} - m_LocalScale: {x: 10, y: 10, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 47225731} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 135, 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_ConstrainProportionsScale: 0 - 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} - 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 deleted file mode 100644 index a231750..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MainScene.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 37161b3..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity +++ /dev/null @@ -1,937 +0,0 @@ -%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.12731749, g: 0.13414757, b: 0.1210787, 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: 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: VisibleRangeCapsule - 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.92387956, z: 0, w: 0.38268343} - 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: 135, 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_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 &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_RootOrder - value: 1 - 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.w - value: 0.38268343 - 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_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: sceneId - value: 3231330715 - objectReference: {fileID: 0} - - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, - type: 3} - propertyPath: m_SceneId - value: 15452677 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: forceHidden - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: castLayers.m_Bits - value: 256 - 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: VisibleRangeSphere - 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.3826836, z: -0, w: -0.92387944} - 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: 315, 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_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 &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: VisibleRangeCylinder - 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.38268343, z: 0, w: 0.92387956} - 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: 45, 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_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 &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: 21610634} - - {fileID: 222935522} - - {fileID: 507729670} - 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: VisibleRangeCube - 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.9238796, z: -0, w: -0.38268325} - 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: 225, 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_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 &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: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, - type: 3} - propertyPath: m_LocalPosition.x - value: -3 - 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.w - value: -0.92387944 - 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_LocalEulerAnglesHint.y - value: 315 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: forceHidden - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: castLayers.m_Bits - value: 256 - 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: -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.w - value: -0.92387944 - 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_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: sceneId - value: 1396685688 - objectReference: {fileID: 0} - - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, - type: 3} - propertyPath: m_SceneId - value: 11893259 - 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: sceneId - value: 86995073 - objectReference: {fileID: 0} - - target: {fileID: 5623359707189648404, guid: 4ff300cf6bb3c6342a9552c4f18788c8, - type: 3} - propertyPath: m_SceneId - value: 4733130 - 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.z - value: -3 - 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_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_LocalEulerAnglesHint.y - value: 225 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: forceHidden - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: castLayers.m_Bits - value: 256 - 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_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.w - value: -0.38268325 - 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_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_Icon - value: - objectReference: {fileID: 0} - - target: {fileID: 5623359707189648430, guid: 4ff300cf6bb3c6342a9552c4f18788c8, - type: 3} - propertyPath: m_Name - value: Cube - 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_RootOrder - value: 3 - 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.w - value: 0.92387956 - 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_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: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, - type: 3} - propertyPath: sceneId - value: 3262924414 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: forceHidden - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 0} - propertyPath: castLayers.m_Bits - value: 256 - objectReference: {fileID: 0} - - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, - type: 3} - propertyPath: sceneId - value: 3262924414 - 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} - 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 deleted file mode 100644 index 94a2050..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scenes/SubScene.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index cb97b32..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 93e3d54..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Collections; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Mirror.Examples.AdditiveScenes -{ - [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 static new AdditiveNetworkManager singleton { get; private set; } - - ///

- /// Runs on both Server and Client - /// Networking is NOT initialized when this fires - /// - public override void Awake() - { - base.Awake(); - singleton = this; - } - - public override void OnStartServer() - { - base.OnStartServer(); - - // load all subscenes on the server only - StartCoroutine(LoadSubScenes()); - - // Instantiate Zone Handler on server only - Instantiate(Zone); - } - - public override void OnStopServer() - { - StartCoroutine(UnloadScenes()); - } - - public override void OnStopClient() - { - if (mode == NetworkManagerMode.Offline) - StartCoroutine(UnloadScenes()); - } - - IEnumerator LoadSubScenes() - { - Debug.Log("Loading Scenes"); - - foreach (string sceneName in subScenes) - yield return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); - } - - 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); - - yield return Resources.UnloadUnusedAssets(); - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta deleted file mode 100644 index 0df3fb3..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/PlayerCamera.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerCamera.cs deleted file mode 100644 index 2f9e511..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerCamera.cs +++ /dev/null @@ -1,44 +0,0 @@ -using UnityEngine; -using UnityEngine.SceneManagement; - -// This sets up the scene camera for the local player - -namespace Mirror.Examples.AdditiveScenes -{ - public class PlayerCamera : NetworkBehaviour - { - Camera mainCam; - - void Awake() - { - mainCam = Camera.main; - } - - public override void OnStartLocalPlayer() - { - if (mainCam != null) - { - // configure and make camera a child of player with 3rd person offset - mainCam.orthographic = false; - mainCam.transform.SetParent(transform); - mainCam.transform.localPosition = new Vector3(0f, 3f, -8f); - mainCam.transform.localEulerAngles = new Vector3(10f, 0f, 0f); - } - else - Debug.LogWarning("PlayerCamera: Could not find a camera in scene with 'MainCamera' tag."); - } - - public override void OnStopLocalPlayer() - { - if (mainCam != null) - { - mainCam.transform.SetParent(null); - SceneManager.MoveGameObjectToScene(mainCam.gameObject, SceneManager.GetActiveScene()); - mainCam.orthographic = true; - mainCam.orthographicSize = 15f; - mainCam.transform.localPosition = new Vector3(0f, 70f, 0f); - mainCam.transform.localEulerAngles = new Vector3(90f, 0f, 0f); - } - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerCamera.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerCamera.cs.meta deleted file mode 100644 index 36a243f..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerCamera.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 437e9ed1a55931845bef07e2f5ef57e0 -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 deleted file mode 100644 index 683a51e..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs +++ /dev/null @@ -1,185 +0,0 @@ -using UnityEngine; -using UnityEngine.Networking; - -namespace Mirror.Examples.AdditiveScenes -{ - [RequireComponent(typeof(CapsuleCollider))] - [RequireComponent(typeof(CharacterController))] - [RequireComponent(typeof(NetworkTransform))] - [RequireComponent(typeof(Rigidbody))] - public class PlayerController : NetworkBehaviour - { - public enum GroundState : byte { Jumping, Falling, Grounded } - - [Header("Avatar Components")] - public CharacterController characterController; - - [Header("Movement")] - [Range(1, 20)] - public float moveSpeedMultiplier = 8f; - - [Header("Turning")] - [Range(1f, 200f)] - public float maxTurnSpeed = 100f; - [Range(.5f, 5f)] - public float turnDelta = 3f; - - [Header("Jumping")] - [Range(0.1f, 1f)] - public float initialJumpSpeed = 0.2f; - [Range(1f, 10f)] - public float maxJumpSpeed = 5f; - [Range(0.1f, 1f)] - public float jumpDelta = 0.2f; - - [Header("Diagnostics - Do Not Modify")] - public GroundState groundState = GroundState.Grounded; - - [Range(-1f, 1f)] - public float horizontal; - [Range(-1f, 1f)] - public float vertical; - - [Range(-200f, 200f)] - public float turnSpeed; - - [Range(-10f, 10f)] - public float jumpSpeed; - - [Range(-1.5f, 1.5f)] - public float animVelocity; - - [Range(-1.5f, 1.5f)] - public float animRotation; - - public Vector3Int velocity; - public Vector3 direction; - - void OnValidate() - { - if (characterController == null) - characterController = GetComponent(); - - // Override CharacterController default values - characterController.enabled = false; - characterController.skinWidth = 0.02f; - characterController.minMoveDistance = 0f; - - GetComponent().isKinematic = true; - - this.enabled = false; - } - - public override void OnStartAuthority() - { - characterController.enabled = true; - this.enabled = true; - } - - public override void OnStopAuthority() - { - this.enabled = false; - characterController.enabled = false; - } - - void Update() - { - if (!characterController.enabled) - return; - - HandleTurning(); - HandleJumping(); - HandleMove(); - - // Reset ground state - if (characterController.isGrounded) - groundState = GroundState.Grounded; - else if (groundState != GroundState.Jumping) - groundState = GroundState.Falling; - - // Diagnostic velocity...FloorToInt for display purposes - velocity = Vector3Int.FloorToInt(characterController.velocity); - } - - // TODO: Turning works while airborne...feature? - void HandleTurning() - { - // Q and E cancel each other out, reducing the turn to zero. - if (Input.GetKey(KeyCode.Q)) - turnSpeed = Mathf.MoveTowards(turnSpeed, -maxTurnSpeed, turnDelta); - if (Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, maxTurnSpeed, turnDelta); - - // If both pressed, reduce turning speed toward zero. - if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta); - - // If neither pressed, reduce turning speed toward zero. - if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta); - - transform.Rotate(0f, turnSpeed * Time.deltaTime, 0f); - } - - void HandleJumping() - { - // Handle variable force jumping. - // Jump starts with initial power on takeoff, and jumps higher / longer - // as player holds spacebar. Jump power is increased by a diminishing amout - // every frame until it reaches maxJumpSpeed, or player releases the spacebar, - // and then changes to the falling state until it gets grounded. - if (groundState != GroundState.Falling && Input.GetKey(KeyCode.Space)) - { - if (groundState != GroundState.Jumping) - { - // Start jump at initial power. - groundState = GroundState.Jumping; - jumpSpeed = initialJumpSpeed; - } - else - // Jumping has already started...increase power toward maxJumpSpeed over time. - jumpSpeed = Mathf.MoveTowards(jumpSpeed, maxJumpSpeed, jumpDelta); - - // If power has reached maxJumpSpeed, change to falling until grounded. - // This prevents over-applying jump power while already in the air. - if (jumpSpeed == maxJumpSpeed) - groundState = GroundState.Falling; - } - else if (groundState != GroundState.Grounded) - { - // handles running off a cliff and/or player released Spacebar. - groundState = GroundState.Falling; - jumpSpeed = Mathf.Min(jumpSpeed, maxJumpSpeed); - jumpSpeed += Physics.gravity.y * Time.deltaTime; - } - else - jumpSpeed = Physics.gravity.y * Time.deltaTime; - } - - // TODO: Directional input works while airborne...feature? - void HandleMove() - { - // Capture inputs - horizontal = Input.GetAxis("Horizontal"); - vertical = Input.GetAxis("Vertical"); - - // Create initial direction vector without jumpSpeed (y-axis). - direction = new Vector3(horizontal, 0f, vertical); - - // Clamp so diagonal strafing isn't a speed advantage. - direction = Vector3.ClampMagnitude(direction, 1f); - - // Transforms direction from local space to world space. - direction = transform.TransformDirection(direction); - - // Multiply for desired ground speed. - direction *= moveSpeedMultiplier; - - // Add jumpSpeed to direction as last step. - direction.y = jumpSpeed; - - // Finally move the character. - characterController.Move(direction * Time.deltaTime); - } - } -} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs.meta deleted file mode 100644 index 5deced6..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/PlayerController.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index a2d3f9a..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs +++ /dev/null @@ -1,31 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.AdditiveScenes -{ - public class RandomColor : NetworkBehaviour - { - public override void 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 deleted file mode 100644 index 2c0008b..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/RandomColor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 0b49dfa..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs +++ /dev/null @@ -1,59 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.AdditiveScenes -{ - // 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 (NetworkConnectionToClient 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 deleted file mode 100644 index 90771ab..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 040eaa9..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs +++ /dev/null @@ -1,42 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.AdditiveScenes -{ - // 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; - - [ServerCallback] - void OnTriggerEnter(Collider other) - { - // ignore collisions with non-Player objects - if (!other.CompareTag("Player")) return; - - if (other.TryGetComponent(out NetworkIdentity networkIdentity)) - { - SceneMessage message = new SceneMessage { sceneName = subScene, sceneOperation = SceneOperation.LoadAdditive }; - networkIdentity.connectionToClient.Send(message); - } - } - - [ServerCallback] - void OnTriggerExit(Collider other) - { - // ignore collisions with non-Player objects - if (!other.CompareTag("Player")) return; - - if (other.TryGetComponent(out NetworkIdentity networkIdentity)) - { - 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 deleted file mode 100644 index 126d072..0000000 --- a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 653ea78..0000000 --- a/Assets/Mirror/Examples/Basic.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 234c22a..0000000 --- a/Assets/Mirror/Examples/Basic/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index e7d482a..0000000 --- a/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab +++ /dev/null @@ -1,73 +0,0 @@ -%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: 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!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 - _assetId: 3332857900 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - playerUIPrefab: {fileID: 5152941909035078397, guid: 22f1fa3a0aff72b46a371f667bb4fb30, type: 3} - playerNumber: 0 - playerColor: - serializedVersion: 2 - rgba: 4294967295 - playerData: 0 diff --git a/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta deleted file mode 100644 index a943869..0000000 --- a/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 1b21595..0000000 --- a/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab +++ /dev/null @@ -1,256 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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 deleted file mode 100644 index c6a8284..0000000 --- a/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 5b39b3a..0000000 --- a/Assets/Mirror/Examples/Basic/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# 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 deleted file mode 100644 index d4e1715..0000000 --- a/Assets/Mirror/Examples/Basic/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 0c751c6..0000000 --- a/Assets/Mirror/Examples/Basic/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index e0edd3c..0000000 --- a/Assets/Mirror/Examples/Basic/Scenes/Example.unity +++ /dev/null @@ -1,819 +0,0 @@ -%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: 12 - 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_LightingSettings: {fileID: 2034431047} ---- !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 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 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: - 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 - MaxRetransmit: 40 - NonAlloc: 1 - MaximizeSendReceiveBuffersToOSLimit: 1 - ReliableMaxMessageSize: 298449 - UnreliableMaxMessageSize: 1199 - 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 - runInBackground: 1 - autoStartServerBuild: 1 - autoConnectClientBuild: 0 - sendRate: 30 - offlineScene: - onlineScene: - transport: {fileID: 249891955} - networkAddress: localhost - maxConnections: 100 - authenticator: {fileID: 0} - playerPrefab: {fileID: 897184729387425976, guid: dc2c4328591bef748abb8df795c17202, - type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 1 - spawnPrefabs: [] - timeInterpolationGui: 0 ---- !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_ConstrainProportionsScale: 0 - 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} - - component: {fileID: 288173828} - 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &288173828 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 288173824} - 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!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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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: 266fac335be17a243af86e88de84766d, type: 3} - m_Name: - m_EditorClassIdentifier: - mainPanel: {fileID: 1712119861} - playersPanel: {fileID: 379082679} ---- !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 - m_PresetInfoIsWorld: 0 ---- !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_ConstrainProportionsScale: 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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_SendPointerHoverToParent: 1 - 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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 ---- !u!850595691 &2034431047 -LightingSettings: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Settings.lighting - serializedVersion: 4 - m_GIWorkflowMode: 0 - m_EnableBakedLightmaps: 0 - m_EnableRealtimeLightmaps: 0 - m_RealtimeEnvironmentLighting: 1 - m_BounceScale: 1 - m_AlbedoBoost: 1 - m_IndirectOutputScale: 1 - m_UsingShadowmask: 1 - m_BakeBackend: 1 - m_LightmapMaxSize: 1024 - m_BakeResolution: 40 - m_Padding: 2 - m_LightmapCompression: 3 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAO: 0 - m_MixedBakeMode: 2 - m_LightmapsBakeMode: 1 - m_FilterMode: 1 - m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_RealtimeResolution: 2 - m_ForceWhiteAlbedo: 0 - m_ForceUpdates: 0 - m_FinalGather: 0 - m_FinalGatherRayCount: 256 - m_FinalGatherFiltering: 1 - m_PVRCulling: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 500 - m_PVREnvironmentSampleCount: 500 - m_PVREnvironmentReferencePointCount: 2048 - m_LightProbeSampleCountMultiplier: 4 - m_PVRBounces: 2 - m_PVRMinBounces: 2 - m_PVREnvironmentMIS: 0 - m_PVRFilteringMode: 2 - m_PVRDenoiserTypeDirect: 0 - m_PVRDenoiserTypeIndirect: 0 - m_PVRDenoiserTypeAO: 0 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_PVRTiledBaking: 0 diff --git a/Assets/Mirror/Examples/Basic/Scenes/Example.unity.meta b/Assets/Mirror/Examples/Basic/Scenes/Example.unity.meta deleted file mode 100644 index 25c602e..0000000 --- a/Assets/Mirror/Examples/Basic/Scenes/Example.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 5cc0800..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 23b1d2f..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Mirror.Examples.AdditiveScenes; -using UnityEngine; - -namespace Mirror.Examples.Basic -{ - [AddComponentMenu("")] - public class BasicNetManager : NetworkManager - { - public static new BasicNetManager singleton { get; private set; } - - /// - /// Runs on both Server and Client - /// Networking is NOT initialized when this fires - /// - public override void Awake() - { - base.Awake(); - singleton = this; - } - - /// - /// 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(NetworkConnectionToClient 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(NetworkConnectionToClient 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 deleted file mode 100644 index 35918e9..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/CanvasUI.cs b/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs deleted file mode 100644 index 7e7adb9..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs +++ /dev/null @@ -1,28 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.Basic -{ - public class CanvasUI : MonoBehaviour - { - [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; - - // static instance that can be referenced from static methods below. - static CanvasUI instance; - - void Awake() - { - instance = this; - } - - public static void SetActive(bool active) - { - instance.mainPanel.gameObject.SetActive(active); - } - - public static RectTransform GetPlayersPanel() => instance.playersPanel; - } -} diff --git a/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta deleted file mode 100644 index 30ad077..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 266fac335be17a243af86e88de84766d -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 deleted file mode 100644 index 0261fce..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/Player.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror.Examples.Basic -{ - public class Player : NetworkBehaviour - { - // Events that the PlayerUI will subscribe to - public event System.Action OnPlayerNumberChanged; - public event System.Action OnPlayerColorChanged; - public event System.Action OnPlayerDataChanged; - - // Players List to manage playerNumber - static readonly List playersList = new List(); - - [Header("Player UI")] - public GameObject playerUIPrefab; - - GameObject playerUIObject; - PlayerUI playerUI = null; - - #region SyncVars - - [Header("SyncVars")] - - /// - /// This is appended to the player name text, e.g. "Player 01" - /// - [SyncVar(hook = nameof(PlayerNumberChanged))] - public byte playerNumber = 0; - - /// - /// Random color for the playerData text, assigned in OnStartServer - /// - [SyncVar(hook = nameof(PlayerColorChanged))] - public Color32 playerColor = Color.white; - - /// - /// This is updated by UpdateData which is called from OnStartServer via InvokeRepeating - /// - [SyncVar(hook = nameof(PlayerDataChanged))] - public ushort playerData = 0; - - // This is called by the hook of playerNumber SyncVar above - void PlayerNumberChanged(byte _, byte newPlayerNumber) - { - OnPlayerNumberChanged?.Invoke(newPlayerNumber); - } - - // This is called by the hook of playerColor SyncVar above - void PlayerColorChanged(Color32 _, Color32 newPlayerColor) - { - OnPlayerColorChanged?.Invoke(newPlayerColor); - } - - // This is called by the hook of playerData SyncVar above - void PlayerDataChanged(ushort _, ushort newPlayerData) - { - OnPlayerDataChanged?.Invoke(newPlayerData); - } - - #endregion - - #region Server - - /// - /// 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); - - // set the initial player data - playerData = (ushort)Random.Range(100, 1000); - - // Start generating updates - InvokeRepeating(nameof(UpdateData), 1, 1); - } - - // This is called from BasicNetManager OnServerAddPlayer and OnServerDisconnect - // Player numbers are reset whenever a player joins / leaves - [ServerCallback] - internal static void ResetPlayerNumbers() - { - byte playerNumber = 0; - foreach (Player player in playersList) - player.playerNumber = playerNumber++; - } - - // This only runs on the server, called from OnStartServer via InvokeRepeating - [ServerCallback] - void UpdateData() - { - playerData = (ushort)Random.Range(100, 1000); - } - - /// - /// 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); - } - - #endregion - - #region Client - - /// - /// 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() - { - // Instantiate the player UI as child of the Players Panel - playerUIObject = Instantiate(playerUIPrefab, CanvasUI.GetPlayersPanel()); - playerUI = playerUIObject.GetComponent(); - - // wire up all events to handlers in PlayerUI - OnPlayerNumberChanged = playerUI.OnPlayerNumberChanged; - OnPlayerColorChanged = playerUI.OnPlayerColorChanged; - OnPlayerDataChanged = playerUI.OnPlayerDataChanged; - - // Invoke all event handlers with the initial data from spawn payload - OnPlayerNumberChanged.Invoke(playerNumber); - OnPlayerColorChanged.Invoke(playerColor); - OnPlayerDataChanged.Invoke(playerData); - } - - /// - /// Called when the local player object has been set up. - /// This happens after OnStartClient(), as it is triggered by an ownership message from the server. This is an appropriate place to activate components or functionality that should only be active for the local player, such as cameras and input. - /// - public override void OnStartLocalPlayer() - { - // Set isLocalPlayer for this Player in UI for background shading - playerUI.SetLocalPlayer(); - - // Activate the main panel - CanvasUI.SetActive(true); - } - - /// - /// Called when the local player object is being stopped. - /// This happens before OnStopClient(), as it may be triggered by an ownership message from the server, or because the player object is being destroyed. This is an appropriate place to deactivate components or functionality that should only be active for the local player, such as cameras and input. - /// - public override void OnStopLocalPlayer() - { - // Disable the main panel for local player - CanvasUI.SetActive(false); - } - - /// - /// 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() - { - // disconnect event handlers - OnPlayerNumberChanged = null; - OnPlayerColorChanged = null; - OnPlayerDataChanged = null; - - // Remove this player's UI object - Destroy(playerUIObject); - } - - #endregion - } -} diff --git a/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta deleted file mode 100644 index cf15827..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index e3fe6c9..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs +++ /dev/null @@ -1,41 +0,0 @@ -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; - - // Sets a highlight color for the local player - public void SetLocalPlayer() - { - // add a visual background for the local player in the UI - image.color = new Color(1f, 1f, 1f, 0.1f); - } - - // This value can change as clients leave and join - public void OnPlayerNumberChanged(byte newPlayerNumber) - { - playerNameText.text = string.Format("Player {0:00}", newPlayerNumber); - } - - // Random color set by Player::OnStartServer - public void OnPlayerColorChanged(Color32 newPlayerColor) - { - playerNameText.color = newPlayerColor; - } - - // This updates from Player::UpdateData via InvokeRepeating on server - public void OnPlayerDataChanged(ushort 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 deleted file mode 100644 index b7c07b7..0000000 --- a/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 73801df..0000000 --- a/Assets/Mirror/Examples/Benchmark.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 12a3156..0000000 --- a/Assets/Mirror/Examples/Benchmark/Materials.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 5c24968..0000000 --- a/Assets/Mirror/Examples/Benchmark/Materials/Red.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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 deleted file mode 100644 index 9e65288..0000000 --- a/Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index aaf3087..0000000 --- a/Assets/Mirror/Examples/Benchmark/Materials/White.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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 deleted file mode 100644 index 0a9db55..0000000 --- a/Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 2cdde64..0000000 --- a/Assets/Mirror/Examples/Benchmark/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 2617fa1..0000000 --- a/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab +++ /dev/null @@ -1,151 +0,0 @@ -%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_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: 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_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: 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 - 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 - _assetId: 3853995854 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 0 - syncMode: 0 - syncInterval: 0 - target: {fileID: 2697352357490696306} - clientAuthority: 0 - syncPosition: 1 - syncRotation: 0 - syncScale: 0 - showGizmos: 0 - showOverlay: 0 - overlayColor: {r: 0, g: 0, b: 0, a: 0.5} - onlySyncOnChange: 0 - bufferResetMultiplier: 5 - positionSensitivity: 0.01 - rotationSensitivity: 0.01 - scaleSensitivity: 0.01 ---- !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: - syncDirection: 0 - 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 deleted file mode 100644 index 766ed77..0000000 --- a/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index c2aaed7..0000000 --- a/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab +++ /dev/null @@ -1,149 +0,0 @@ -%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 - _assetId: 242745736 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 1 - syncMode: 0 - syncInterval: 0 - target: {fileID: 2697352357490696306} - clientAuthority: 0 - syncPosition: 1 - syncRotation: 0 - syncScale: 0 - showGizmos: 1 - showOverlay: 1 - overlayColor: {r: 0, g: 0, b: 0, a: 0.5} - onlySyncOnChange: 0 - bufferResetMultiplier: 5 - positionSensitivity: 0.01 - rotationSensitivity: 0.01 - scaleSensitivity: 0.01 ---- !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: - syncDirection: 0 - 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 deleted file mode 100644 index cb898f8..0000000 --- a/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index f73c636..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index b9e8b71..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity +++ /dev/null @@ -1,487 +0,0 @@ -%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: 12 - 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: 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: 0 - 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: 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} - - component: {fileID: 88936778} - 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_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: 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} ---- !u!114 &88936778 -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: 6635375fbc6be456ea640b75add6378e, type: 3} - m_Name: - m_EditorClassIdentifier: - showGUI: 1 - showLog: 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: - 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 - PersistNetworkManagerToOfflineScene: 0 - runInBackground: 1 - autoStartServerBuild: 1 - serverTickRate: 30 - offlineScene: - onlineScene: - transport: {fileID: 1282001521} - networkAddress: localhost - maxConnections: 1000 - authenticator: {fileID: 0} - playerPrefab: {fileID: 449802645721213856, guid: e1299008405d14b17b1ca459a6cd44a2, - type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 1 - spawnPrefabs: - - {fileID: 449802645721213856, guid: 30b8f251d03d84284b70601e691d474f, type: 3} - timeInterpolationGui: 1 - 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 - 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 &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: 30 - 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: 10 - m_Type: 1 - m_Shape: 0 - m_Color: {r: 1, g: 1, b: 1, 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: 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 &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 deleted file mode 100644 index 4a3c47e..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 7247026..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 786369f..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs +++ /dev/null @@ -1,52 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.Benchmark -{ - [AddComponentMenu("")] - 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 deleted file mode 100644 index 6355efe..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index fd7d377..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs +++ /dev/null @@ -1,50 +0,0 @@ -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); - - // set destination on random pos in a circle around start. - // (don't want to wander off) - destination = start + dir * movementDistance; - moving = true; - } - } - } - } -} diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta deleted file mode 100644 index e4aea03..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 6865123..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index a520ac7..0000000 --- a/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c482338c8cc6d4a3cba81934c0151972 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU.meta b/Assets/Mirror/Examples/CCU.meta deleted file mode 100644 index 667a616..0000000 --- a/Assets/Mirror/Examples/CCU.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c1224ecd334304d359f5930d0e7d85fc -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/CCU.unity b/Assets/Mirror/Examples/CCU/CCU.unity deleted file mode 100644 index a04b0bf..0000000 --- a/Assets/Mirror/Examples/CCU/CCU.unity +++ /dev/null @@ -1,527 +0,0 @@ -%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: 12 - 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: 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: 0 - 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_LightingSettings: {fileID: 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 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 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} - - component: {fileID: 88936778} - 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, g: 0, b: 0, a: 1} - 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: 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: 600, z: -800} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} ---- !u!114 &88936778 -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: 6635375fbc6be456ea640b75add6378e, type: 3} - m_Name: - m_EditorClassIdentifier: - showGUI: 1 - showLog: 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_ConstrainProportionsScale: 0 - 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} - - component: {fileID: 1282001523} - 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_ConstrainProportionsScale: 0 - 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: - 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: b0ff29cd45bcd43128c4cc79f25fd658, type: 3} - m_Name: - m_EditorClassIdentifier: - dontDestroyOnLoad: 1 - runInBackground: 1 - autoStartServerBuild: 1 - autoConnectClientBuild: 0 - sendRate: 30 - offlineScene: - onlineScene: - transport: {fileID: 1282001521} - networkAddress: localhost - maxConnections: 1000 - authenticator: {fileID: 0} - playerPrefab: {fileID: 449802645721213856, guid: 614e28b6213c14195b8661c153bf4ee4, - type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 1 - spawnPrefabs: - - {fileID: 449802645721213856, guid: d0f3b049f6bef4cc6930c57a2146ca52, type: 3} - timeInterpolationGui: 0 - spawnAmount: 10000 - interleave: 10 - spawnPrefab: {fileID: 449802645721213856, guid: d0f3b049f6bef4cc6930c57a2146ca52, - type: 3} - spawnPositionRatio: 0.01 ---- !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 - DualMode: 1 - NoDelay: 1 - Interval: 10 - Timeout: 10000 - FastResend: 2 - CongestionWindow: 0 - SendWindowSize: 4096 - ReceiveWindowSize: 4096 - MaxRetransmit: 40 - NonAlloc: 1 - MaximizeSendReceiveBuffersToOSLimit: 1 - ReliableMaxMessageSize: 298449 - UnreliableMaxMessageSize: 1199 - 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: 30 - rebuildInterval: 1 - checkMethod: 0 - showSlider: 0 ---- !u!114 &1282001523 -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: 6d7da4e566d24ea7b0e12178d934b648, type: 3} - m_Name: - m_EditorClassIdentifier: - clientIntervalReceivedPackets: 0 - clientIntervalReceivedBytes: 0 - clientIntervalSentPackets: 0 - clientIntervalSentBytes: 0 - clientReceivedPacketsPerSecond: 0 - clientReceivedBytesPerSecond: 0 - clientSentPacketsPerSecond: 0 - clientSentBytesPerSecond: 0 - serverIntervalReceivedPackets: 0 - serverIntervalReceivedBytes: 0 - serverIntervalSentPackets: 0 - serverIntervalSentBytes: 0 - serverReceivedPacketsPerSecond: 0 - serverReceivedBytesPerSecond: 0 - serverSentPacketsPerSecond: 0 - serverSentBytesPerSecond: 0 ---- !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: 10 - m_Type: 1 - m_Shape: 0 - m_Color: {r: 1, g: 1, b: 1, 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: 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_UseViewFrustumForShadowCasterCull: 1 - 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Mirror/Examples/CCU/CCU.unity.meta b/Assets/Mirror/Examples/CCU/CCU.unity.meta deleted file mode 100644 index 93790ee..0000000 --- a/Assets/Mirror/Examples/CCU/CCU.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a692de27a26e74566b797df05d9b3385 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs b/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs deleted file mode 100644 index 3891eee..0000000 --- a/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs +++ /dev/null @@ -1,93 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.CCU -{ - [AddComponentMenu("")] - public class CCUNetworkManager : NetworkManager - { - [Header("Spawns")] - public int spawnAmount = 10_000; - public float interleave = 1; - public GameObject spawnPrefab; - - // player spawn positions should be spread across the world. - // not all at one place. - // but _some_ at the same place. - // => deterministic random is ideal - [Range(0, 1)] public float spawnPositionRatio = 0.01f; - - System.Random random = new System.Random(42); - - void SpawnAll() - { - // clear previous player spawn positions in case we start twice - foreach (Transform position in startPositions) - Destroy(position.gameObject); - - startPositions.Clear(); - - // 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) - { - // spawn & position - GameObject go = Instantiate(spawnPrefab); - float x = offset + spawnX * interleave; - float z = offset + spawnZ * interleave; - Vector3 position = new Vector3(x, 0, z); - go.transform.position = position; - - // spawn - NetworkServer.Spawn(go); - ++spawned; - - // add random spawn position for players. - // don't have them all in the same place. - if (random.NextDouble() <= spawnPositionRatio) - { - GameObject spawnGO = new GameObject("Spawn"); - spawnGO.transform.position = position; - spawnGO.AddComponent(); - } - } - } - } - } - - // overwrite random spawn position selection: - // - needs to be deterministic so every CCU test results in the same - // - needs to be random so not only are the spawn positions spread out - // randomly, we also have a random amount of players per spawn position - public override Transform GetStartPosition() - { - // first remove any dead transforms - startPositions.RemoveAll(t => t == null); - - if (startPositions.Count == 0) - return null; - - // pick a random one - int index = random.Next(0, startPositions.Count); // DETERMINISTIC - return startPositions[index]; - } - - public override void OnStartServer() - { - base.OnStartServer(); - SpawnAll(); - } - } -} diff --git a/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta b/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta deleted file mode 100644 index 120e6c9..0000000 --- a/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b0ff29cd45bcd43128c4cc79f25fd658 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/Monster.cs b/Assets/Mirror/Examples/CCU/Monster.cs deleted file mode 100644 index 420c487..0000000 --- a/Assets/Mirror/Examples/CCU/Monster.cs +++ /dev/null @@ -1,55 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.CCU -{ - public class Monster : NetworkBehaviour - { - public float speed = 1; - public float movementProbability = 0.5f; - public float movementDistance = 20; - - bool moving; - Vector3 start; - Vector3 destination; - - // cache .transform for benchmark demo. - // Component.get_transform shows in profiler otherwise. - Transform tf; - - public override void OnStartServer() - { - tf = transform; - start = tf.position; - } - - [ServerCallback] - void Update() - { - if (moving) - { - if (Vector3.Distance(tf.position, destination) <= 0.01f) - { - moving = false; - } - else - { - tf.position = Vector3.MoveTowards(tf.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); - - // set destination on random pos in a circle around start. - // (don't want to wander off) - destination = start + dir * movementDistance; - moving = true; - } - } - } - } -} diff --git a/Assets/Mirror/Examples/CCU/Monster.cs.meta b/Assets/Mirror/Examples/CCU/Monster.cs.meta deleted file mode 100644 index f8b4b6e..0000000 --- a/Assets/Mirror/Examples/CCU/Monster.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b3a6fbf45e1c94ce6b2c1a2d08519a11 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/Monster.prefab b/Assets/Mirror/Examples/CCU/Monster.prefab deleted file mode 100644 index 7d56738..0000000 --- a/Assets/Mirror/Examples/CCU/Monster.prefab +++ /dev/null @@ -1,151 +0,0 @@ -%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: -3181616459286004871} - 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_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: 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_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: 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 - 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 - _assetId: 204484799 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 0 - syncMode: 0 - syncInterval: 0 - target: {fileID: 2697352357490696306} - clientAuthority: 0 - syncPosition: 1 - syncRotation: 0 - syncScale: 0 - showGizmos: 0 - showOverlay: 0 - overlayColor: {r: 0, g: 0, b: 0, a: 0.5} - onlySyncOnChange: 1 - bufferResetMultiplier: 5 - positionSensitivity: 0.01 - rotationSensitivity: 0.01 - scaleSensitivity: 0.01 ---- !u!114 &-3181616459286004871 -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: b3a6fbf45e1c94ce6b2c1a2d08519a11, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - speed: 1 - movementProbability: 0.5 - movementDistance: 20 diff --git a/Assets/Mirror/Examples/CCU/Monster.prefab.meta b/Assets/Mirror/Examples/CCU/Monster.prefab.meta deleted file mode 100644 index a949771..0000000 --- a/Assets/Mirror/Examples/CCU/Monster.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: d0f3b049f6bef4cc6930c57a2146ca52 -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/Player.cs b/Assets/Mirror/Examples/CCU/Player.cs deleted file mode 100644 index dd98ca8..0000000 --- a/Assets/Mirror/Examples/CCU/Player.cs +++ /dev/null @@ -1,99 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.CCU -{ - public class Player : NetworkBehaviour - { - public Vector3 cameraOffset = new Vector3(0, 40, -40); - - // automated movement. - // player may switch to manual movement any time - [Header("Automated Movement")] - public bool autoMove = true; - public float autoSpeed = 2; - public float movementProbability = 0.5f; - public float movementDistance = 20; - bool moving; - Vector3 start; - Vector3 destination; - - [Header("Manual Movement")] - public float manualSpeed = 10; - - // cache .transform for benchmark demo. - // Component.get_transform shows in profiler otherwise. - Transform tf; - - public override void OnStartLocalPlayer() - { - tf = transform; - start = tf.position; - - // make camera follow - Camera.main.transform.SetParent(transform, false); - Camera.main.transform.localPosition = cameraOffset; - } - - public override void OnStopLocalPlayer() - { - // free the camera so we don't destroy it too - Camera.main.transform.SetParent(null, true); - } - - void AutoMove() - { - if (moving) - { - if (Vector3.Distance(tf.position, destination) <= 0.01f) - { - moving = false; - } - else - { - tf.position = Vector3.MoveTowards(tf.position, destination, autoSpeed * Time.deltaTime); - } - } - else - { - float r = Random.value; - if (r < movementProbability * Time.deltaTime) - { - // calculate a random position in a circle - float circleX = Mathf.Cos(Random.value * Mathf.PI); - float circleZ = Mathf.Sin(Random.value * Mathf.PI); - Vector2 circlePos = new Vector2(circleX, circleZ); - Vector3 dir = new Vector3(circlePos.x, 0, circlePos.y); - - // set destination on random pos in a circle around start. - // (don't want to wander off) - destination = start + dir * movementDistance; - moving = true; - } - } - } - - void ManualMove() - { - float h = Input.GetAxis("Horizontal"); - float v = Input.GetAxis("Vertical"); - - Vector3 direction = new Vector3(h, 0, v); - transform.position += direction.normalized * (Time.deltaTime * manualSpeed); - } - - static bool Interrupted() => - Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0; - - void Update() - { - if (!isLocalPlayer) return; - - // player may interrupt auto movement to switch to manual - if (Interrupted()) autoMove = false; - - // move - if (autoMove) AutoMove(); - else ManualMove(); - } - } -} diff --git a/Assets/Mirror/Examples/CCU/Player.cs.meta b/Assets/Mirror/Examples/CCU/Player.cs.meta deleted file mode 100644 index 792483e..0000000 --- a/Assets/Mirror/Examples/CCU/Player.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2c936c3d1cc664f15a92190fc35fd7dd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/Player.prefab b/Assets/Mirror/Examples/CCU/Player.prefab deleted file mode 100644 index 67a4648..0000000 --- a/Assets/Mirror/Examples/CCU/Player.prefab +++ /dev/null @@ -1,174 +0,0 @@ -%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: 8691745481282286165} - - component: {fileID: 8079286830074380037} - 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 - _assetId: 1350054018 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 1 - syncMode: 0 - syncInterval: 0 - target: {fileID: 2697352357490696306} - clientAuthority: 0 - syncPosition: 1 - syncRotation: 0 - syncScale: 0 - showGizmos: 0 - showOverlay: 0 - overlayColor: {r: 0, g: 0, b: 0, a: 0.5} - onlySyncOnChange: 1 - bufferResetMultiplier: 5 - positionSensitivity: 0.01 - rotationSensitivity: 0.01 - scaleSensitivity: 0.01 ---- !u!114 &8691745481282286165 -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: 2c936c3d1cc664f15a92190fc35fd7dd, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - cameraOffset: {x: 0, y: 40, z: -40} - autoMove: 1 - autoSpeed: 2 - movementProbability: 0.5 - movementDistance: 20 - manualSpeed: 10 ---- !u!114 &8079286830074380037 -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: ba360e4ff6b44fc6898f56322b90c6c8, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 1 - syncInterval: 0.1 - sendInterval: 1 - showGui: 0 - hotKey: 292 - passwordFile: remote_statistics.txt diff --git a/Assets/Mirror/Examples/CCU/Player.prefab.meta b/Assets/Mirror/Examples/CCU/Player.prefab.meta deleted file mode 100644 index 1fd32ad..0000000 --- a/Assets/Mirror/Examples/CCU/Player.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 614e28b6213c14195b8661c153bf4ee4 -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/Red.mat b/Assets/Mirror/Examples/CCU/Red.mat deleted file mode 100644 index 5c24968..0000000 --- a/Assets/Mirror/Examples/CCU/Red.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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/CCU/Red.mat.meta b/Assets/Mirror/Examples/CCU/Red.mat.meta deleted file mode 100644 index 51eef59..0000000 --- a/Assets/Mirror/Examples/CCU/Red.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7b742246ea1d249358a8a8e039bd4b17 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 2100000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/White.mat b/Assets/Mirror/Examples/CCU/White.mat deleted file mode 100644 index aaf3087..0000000 --- a/Assets/Mirror/Examples/CCU/White.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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/CCU/White.mat.meta b/Assets/Mirror/Examples/CCU/White.mat.meta deleted file mode 100644 index f673848..0000000 --- a/Assets/Mirror/Examples/CCU/White.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ae32f0609a5e9453b95ec3b9e28c2ac8 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 2100000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/Chat.meta b/Assets/Mirror/Examples/Chat.meta deleted file mode 100644 index 1b51dde..0000000 --- a/Assets/Mirror/Examples/Chat.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index f3f82c4..0000000 --- a/Assets/Mirror/Examples/Chat/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 5e910fa..0000000 --- a/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab +++ /dev/null @@ -1,68 +0,0 @@ -%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: 114398755512196590} - - component: {fileID: 718303009120396421} - 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !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: - sceneId: 0 - _assetId: 725701738 - serverOnly: 0 - visible: 0 - hasSpawned: 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: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - playerName: diff --git a/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta deleted file mode 100644 index 0429ce4..0000000 --- a/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index ac2b33e..0000000 --- a/Assets/Mirror/Examples/Chat/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index b138484..0000000 --- a/Assets/Mirror/Examples/Chat/Scenes/Main.unity +++ /dev/null @@ -1,3799 +0,0 @@ -%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.012745098, g: 0.07450981, b: 0.19901961, 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: 12 - 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_LightingSettings: {fileID: 212571282} ---- !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 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 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.5} - 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.39215687} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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} - m_Layer: 5 - m_Name: ChatPanel - m_TagString: ChatWindow - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !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: 1731300362} - - {fileID: 1863915625} - - {fileID: 1231350850} - - {fileID: 1286463573} - m_Father: {fileID: 719573003} - 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: -40.000008, 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.5019608} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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!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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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, g: 0.5019608, b: 0, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: Start Client ---- !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!850595691 &212571282 -LightingSettings: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Settings.lighting - serializedVersion: 3 - m_GIWorkflowMode: 0 - m_EnableBakedLightmaps: 0 - m_EnableRealtimeLightmaps: 0 - m_RealtimeEnvironmentLighting: 1 - m_BounceScale: 1 - m_AlbedoBoost: 1 - m_IndirectOutputScale: 1 - m_UsingShadowmask: 1 - m_BakeBackend: 1 - m_LightmapMaxSize: 1024 - m_BakeResolution: 40 - m_Padding: 2 - m_TextureCompression: 1 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAO: 0 - m_MixedBakeMode: 2 - m_LightmapsBakeMode: 1 - m_FilterMode: 1 - m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_RealtimeResolution: 2 - m_ForceWhiteAlbedo: 0 - m_ForceUpdates: 0 - m_FinalGather: 0 - m_FinalGatherRayCount: 256 - m_FinalGatherFiltering: 1 - m_PVRCulling: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 500 - m_PVREnvironmentSampleCount: 500 - m_PVREnvironmentReferencePointCount: 2048 - m_LightProbeSampleCountMultiplier: 4 - m_PVRBounces: 2 - m_PVRMinBounces: 2 - m_PVREnvironmentMIS: 0 - m_PVRFilteringMode: 2 - m_PVRDenoiserTypeDirect: 0 - m_PVRDenoiserTypeIndirect: 0 - m_PVRDenoiserTypeAO: 0 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 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_WrapAround: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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.5} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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.5} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 &637644698 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 637644699} - - component: {fileID: 637644701} - - component: {fileID: 637644700} - m_Layer: 5 - m_Name: Text - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &637644699 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 637644698} - 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: 1731300362} - 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 &637644700 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 637644698} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: X ---- !u!222 &637644701 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 637644698} - m_CullTransparentMesh: 1 ---- !u!1 &719572997 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 719573003} - - component: {fileID: 719573002} - - component: {fileID: 719573001} - - component: {fileID: 719573000} - - component: {fileID: 719572999} - - component: {fileID: 719572998} - m_Layer: 5 - m_Name: ChatUI - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &719572998 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 719572997} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2c102f62d739545269250f48327d4429, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - chatHistory: {fileID: 827598817} - scrollbar: {fileID: 423302021} - chatMessage: {fileID: 1231350851} - sendButton: {fileID: 1286463574} ---- !u!114 &719572999 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 719572997} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 2564614208 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 0 ---- !u!114 &719573000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 719572997} - 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: 823 ---- !u!114 &719573001 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 719572997} - 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 - m_PresetInfoIsWorld: 0 ---- !u!223 &719573002 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 719572997} - 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 &719573003 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 719572997} - 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: 75860996} - m_Father: {fileID: 0} - m_RootOrder: 4 - 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 &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.39215687} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 and press Enter or click Send... ---- !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, y: -30} - m_SizeDelta: {x: 1211, 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, g: 0, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: 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: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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: 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: 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: 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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: 1499096249} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 381, y: -175} - m_SizeDelta: {x: 250, 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_WrapAround: 0 - 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: 1783103024} - m_TargetAssemblyTypeName: - m_MethodName: SetPlayername - 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_Target: {fileID: 1453327789} - m_TargetAssemblyTypeName: - m_MethodName: ToggleButtons - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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, g: 0.5019608, b: 0, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 381, y: -126} - m_SizeDelta: {x: 250, 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_WrapAround: 0 - 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_TargetAssemblyTypeName: - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: 6 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 415, y: -254} - m_SizeDelta: {x: 220, y: 60} - 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_WrapAround: 0 - 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: 0 - m_TargetGraphic: {fileID: 1063265581} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 1453327784} - m_TargetAssemblyTypeName: - 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_TargetAssemblyTypeName: - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 &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.5} - 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.39215687} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: 3 - 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_WrapAround: 0 - 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_Target: {fileID: 719572998} - m_TargetAssemblyTypeName: - m_MethodName: OnEndEdit - 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_OnValueChanged: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 719572998} - m_TargetAssemblyTypeName: Mirror.Examples.Chat.ChatUI, Mirror.Examples - m_MethodName: ToggleButton - 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 &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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 &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: 4 - 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_WrapAround: 0 - 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: 0 - m_TargetGraphic: {fileID: 1286463575} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 719572998} - m_TargetAssemblyTypeName: - m_MethodName: SendMessage - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: 0} - 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 - m_ReverseArrangement: 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} - - component: {fileID: 1453327789} - m_Layer: 5 - m_Name: LoginUI - 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: 823 ---- !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 - m_PresetInfoIsWorld: 0 ---- !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: 1499096249} - 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!114 &1453327789 -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: 7a77ca56c9d91af4b81b73a9907d6112, type: 3} - m_Name: - m_EditorClassIdentifier: - usernameInput: {fileID: 851154181} - hostButton: {fileID: 1904406266} - clientButton: {fileID: 1063265580} - errorText: {fileID: 1580038555} ---- !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: UsernameLabel - 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: 1499096249} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 172, y: -175} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: LoginPanel - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !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: 1481045373} - - {fileID: 851154180} - - {fileID: 1904406265} - - {fileID: 1063265579} - - {fileID: 1580038557} - 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 &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: 10, y: -10} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 &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, g: 0.5019608, b: 0, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: Start Host ---- !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 &1580038554 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1580038557} - - component: {fileID: 1580038556} - - component: {fileID: 1580038555} - m_Layer: 5 - m_Name: ErrorText - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!114 &1580038555 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1580038554} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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: 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: ---- !u!222 &1580038556 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1580038554} - m_CullTransparentMesh: 0 ---- !u!224 &1580038557 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1580038554} - 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: 7 - 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: -340} - m_SizeDelta: {x: 440, y: 40} - m_Pivot: {x: 0.5, y: 0.5} ---- !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: 0, y: 0} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: 0 ---- !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_UseViewFrustumForShadowCasterCull: 1 - 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 &1731300361 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1731300362} - - component: {fileID: 1731300365} - - component: {fileID: 1731300364} - - component: {fileID: 1731300363} - m_Layer: 5 - m_Name: ExitButton - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1731300362 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1731300361} - 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: 637644699} - m_Father: {fileID: 75860996} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 1, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: -20, y: -20} - m_SizeDelta: {x: 25, y: 25} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1731300363 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1731300361} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - 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: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1731300364} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 719572998} - m_TargetAssemblyTypeName: Mirror.Examples.Chat.ChatUI, Mirror.Examples - m_MethodName: ExitButtonOnClick - 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 &1731300364 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1731300361} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 &1731300365 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1731300361} - m_CullTransparentMesh: 1 ---- !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} - - component: {fileID: 1783103024} - 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 - MaxRetransmit: 40 - NonAlloc: 1 - MaximizeSendReceiveBuffersToOSLimit: 1 - ReliableMaxMessageSize: 298449 - UnreliableMaxMessageSize: 1199 - debugLog: 0 - statisticsGUI: 0 - statisticsLog: 0 ---- !u!114 &1783103024 -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: 6e2e6b40604520d408bef0a5243a58cd, type: 3} - m_Name: - m_EditorClassIdentifier: - OnServerAuthenticated: - m_PersistentCalls: - m_Calls: [] - OnClientAuthenticated: - m_PersistentCalls: - m_Calls: [] - playerName: ---- !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: 0 - runInBackground: 1 - autoStartServerBuild: 1 - serverTickRate: 30 - offlineScene: - onlineScene: - transport: {fileID: 1783103023} - networkAddress: localhost - maxConnections: 100 - authenticator: {fileID: 1783103024} - playerPrefab: {fileID: 5075528875289742095, guid: e5905ffa27de84009b346b49d518ba03, type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 0 - spawnPrefabs: [] ---- !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: 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: 5} - m_SizeDelta: {x: -51.999992, y: -110} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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.01 - m_Inertia: 1 - m_DecelerationRate: 0.135 - m_ScrollSensitivity: 100 - 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: 2 - m_BackGroundColor: {r: 0.19215688, g: 0.3019608, b: 0.47450984, a: 1} - 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: 5 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 185, y: -254} - m_SizeDelta: {x: 220, y: 60} - 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_WrapAround: 0 - 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: 0 - m_TargetGraphic: {fileID: 1904406267} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 1453327784} - m_TargetAssemblyTypeName: - 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_TargetAssemblyTypeName: - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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, y: -55} - m_SizeDelta: {x: 350, 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, g: 0, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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: 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: 5 - 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: ServerLabel - 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, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 172, y: -126} - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 deleted file mode 100644 index d381d8c..0000000 --- a/Assets/Mirror/Examples/Chat/Scenes/Main.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 71858f4..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 81da49d71176c41169a24259df78e50a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs deleted file mode 100644 index c1265dd..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -/* - Documentation: https://mirror-networking.gitbook.io/docs/components/network-authenticators - API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkAuthenticator.html -*/ - -namespace Mirror.Examples.Chat -{ - [AddComponentMenu("")] - public class ChatAuthenticator : NetworkAuthenticator - { - readonly HashSet connectionsPendingDisconnect = new HashSet(); - - [Header("Client Username")] - public string playerName; - - #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 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 OnServerConnectInternal when a client needs to authenticate - /// - /// Connection to client. - public override void OnServerAuthenticate(NetworkConnectionToClient 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(NetworkConnectionToClient conn, AuthRequestMessage msg) - { - Debug.Log($"Authentication Request: {msg.authUsername}"); - - if (connectionsPendingDisconnect.Contains(conn)) return; - - // check the credentials by calling your web server, database table, playfab api, or any method appropriate. - if (!Player.playerNames.Contains(msg.authUsername)) - { - // Add the name to the HashSet - Player.playerNames.Add(msg.authUsername); - - // Store username in authenticationData - // This will be read in Player.OnStartServer - // to set the playerName SyncVar. - conn.authenticationData = msg.authUsername; - - // 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 - { - connectionsPendingDisconnect.Add(conn); - - // create and send msg to client so it knows to disconnect - AuthResponseMessage authResponseMessage = new AuthResponseMessage - { - code = 200, - message = "Username already in use...try again" - }; - - 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, 1f)); - } - } - - IEnumerator DelayedDisconnect(NetworkConnectionToClient conn, float waitTime) - { - yield return new WaitForSeconds(waitTime); - - // Reject the unsuccessful authentication - ServerReject(conn); - - yield return null; - - // remove conn from pending connections - connectionsPendingDisconnect.Remove(conn); - } - - #endregion - - #region Client - - // Called by UI element UsernameInput.OnValueChanged - public void SetPlayername(string username) - { - playerName = username; - LoginUI.instance.errorText.text = string.Empty; - LoginUI.instance.errorText.gameObject.SetActive(false); - } - - /// - /// 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(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 OnClientConnectInternal when a client needs to authenticate - /// - public override void OnClientAuthenticate() - { - AuthRequestMessage authRequestMessage = new AuthRequestMessage - { - authUsername = playerName, - }; - - NetworkClient.Send(authRequestMessage); - } - - /// - /// Called on client when the server's AuthResponseMessage arrives - /// - /// The message payload - public void OnAuthResponseMessage(AuthResponseMessage msg) - { - if (msg.code == 100) - { - Debug.Log($"Authentication Response: {msg.code} {msg.message}"); - - // Authentication has been accepted - ClientAccept(); - } - else - { - Debug.LogError($"Authentication Response: {msg.code} {msg.message}"); - - // Authentication has been rejected - // StopHost works for both host client and remote clients - NetworkManager.singleton.StopHost(); - - // Do this AFTER StopHost so it doesn't get cleared / hidden by OnClientDisconnect - LoginUI.instance.errorText.text = msg.message; - LoginUI.instance.errorText.gameObject.SetActive(true); - } - } - - #endregion - } -} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta deleted file mode 100644 index eb06fd1..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6e2e6b40604520d408bef0a5243a58cd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs deleted file mode 100644 index 947a5f1..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs +++ /dev/null @@ -1,46 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.Chat -{ - [AddComponentMenu("")] - public class ChatNetworkManager : NetworkManager - { - public static new ChatNetworkManager singleton { get; private set; } - - /// - /// Runs on both Server and Client - /// Networking is NOT initialized when this fires - /// - public override void Awake() - { - base.Awake(); - singleton = this; - } - - // Called by UI element NetworkAddressInput.OnValueChanged - public void SetHostname(string hostname) - { - networkAddress = hostname; - } - - public override void OnServerDisconnect(NetworkConnectionToClient conn) - { - // remove player name from the HashSet - if (conn.authenticationData != null) - Player.playerNames.Remove((string)conn.authenticationData); - - // remove connection from Dictionary of conn > names - ChatUI.connNames.Remove(conn); - - base.OnServerDisconnect(conn); - } - - public override void OnClientDisconnect() - { - base.OnClientDisconnect(); - LoginUI.instance.gameObject.SetActive(true); - LoginUI.instance.usernameInput.text = ""; - LoginUI.instance.usernameInput.ActivateInputField(); - } - } -} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta deleted file mode 100644 index cbc4ca7..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/ChatUI.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs deleted file mode 100644 index e8c8d0f..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.UI; - -namespace Mirror.Examples.Chat -{ - public class ChatUI : NetworkBehaviour - { - [Header("UI Elements")] - [SerializeField] Text chatHistory; - [SerializeField] Scrollbar scrollbar; - [SerializeField] InputField chatMessage; - [SerializeField] Button sendButton; - - // This is only set on client to the name of the local player - internal static string localPlayerName; - - // Server-only cross-reference of connections to player names - internal static readonly Dictionary connNames = new Dictionary(); - - public override void OnStartServer() - { - connNames.Clear(); - } - - public override void OnStartClient() - { - chatHistory.text = ""; - } - - [Command(requiresAuthority = false)] - void CmdSend(string message, NetworkConnectionToClient sender = null) - { - if (!connNames.ContainsKey(sender)) - connNames.Add(sender, sender.identity.GetComponent().playerName); - - if (!string.IsNullOrWhiteSpace(message)) - RpcReceive(connNames[sender], message.Trim()); - } - - [ClientRpc] - void RpcReceive(string playerName, string message) - { - string prettyMessage = playerName == localPlayerName ? - $"{playerName}: {message}" : - $"{playerName}: {message}"; - AppendMessage(prettyMessage); - } - - 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; - } - - // Called by UI element ExitButton.OnClick - public void ExitButtonOnClick() - { - // StopHost calls both StopClient and StopServer - // StopServer does nothing on remote clients - NetworkManager.singleton.StopHost(); - } - - // Called by UI element MessageField.OnValueChanged - public void ToggleButton(string input) - { - sendButton.interactable = !string.IsNullOrWhiteSpace(input); - } - - // Called by UI element MessageField.OnEndEdit - public void OnEndEdit(string input) - { - if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter) || Input.GetButtonDown("Submit")) - SendMessage(); - } - - // Called by OnEndEdit above and UI element SendButton.OnClick - public void SendMessage() - { - if (!string.IsNullOrWhiteSpace(chatMessage.text)) - { - CmdSend(chatMessage.text.Trim()); - chatMessage.text = string.Empty; - chatMessage.ActivateInputField(); - } - } - } -} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta deleted file mode 100644 index 9b9bd1f..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/LoginUI.cs b/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs deleted file mode 100644 index a42f984..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs +++ /dev/null @@ -1,28 +0,0 @@ -using UnityEngine; -using UnityEngine.UI; - -namespace Mirror.Examples.Chat -{ - public class LoginUI : MonoBehaviour - { - [Header("UI Elements")] - [SerializeField] internal InputField usernameInput; - [SerializeField] internal Button hostButton; - [SerializeField] internal Button clientButton; - [SerializeField] internal Text errorText; - - public static LoginUI instance; - - void Awake() - { - instance = this; - } - - // Called by UI element UsernameInput.OnValueChanged - public void ToggleButtons(string username) - { - hostButton.interactable = !string.IsNullOrWhiteSpace(username); - clientButton.interactable = !string.IsNullOrWhiteSpace(username); - } - } -} diff --git a/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta deleted file mode 100644 index 920dda4..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7a77ca56c9d91af4b81b73a9907d6112 -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 deleted file mode 100644 index 253c004..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/Player.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror.Examples.Chat -{ - public class Player : NetworkBehaviour - { - internal static readonly HashSet playerNames = new HashSet(); - - [SerializeField, SyncVar] - internal string playerName; - - // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload - [UnityEngine.RuntimeInitializeOnLoadMethod] - static void ResetStatics() - { - playerNames.Clear(); - } - - public override void OnStartServer() - { - playerName = (string)connectionToClient.authenticationData; - } - - public override void OnStartLocalPlayer() - { - ChatUI.localPlayerName = playerName; - } - } -} diff --git a/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta deleted file mode 100644 index 610ee4c..0000000 --- a/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3addc5ad220944ed6888319897606739 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/Common.meta b/Assets/Mirror/Examples/Common.meta deleted file mode 100644 index ae8aef4..0000000 --- a/Assets/Mirror/Examples/Common.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: fed3df1a3855f414b913671efe3df42a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Examples/Common/FPS.cs b/Assets/Mirror/Examples/Common/FPS.cs deleted file mode 100644 index ac44bac..0000000 --- a/Assets/Mirror/Examples/Common/FPS.cs +++ /dev/null @@ -1,37 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.Common -{ - public class FPS : MonoBehaviour - { - // fps accessible to the outside - public int framesPerSecond { get; private set; } - - // configuration - public bool showGUI = true; - public bool showLog = false; - - // helpers - int count; - double startTime; - - protected void Update() - { - ++count; - if (Time.time >= startTime + 1) - { - framesPerSecond = count; - startTime = Time.time; - count = 0; - if (showLog) Debug.Log($"FPS: {framesPerSecond}"); - } - } - - protected void OnGUI() - { - if (!showGUI) return; - - GUI.Label(new Rect(Screen.width - 70, 0, 70, 25), $"FPS: {framesPerSecond}"); - } - } -} \ No newline at end of file diff --git a/Assets/Mirror/Examples/Common/FPS.cs.meta b/Assets/Mirror/Examples/Common/FPS.cs.meta deleted file mode 100644 index b7d2ac4..0000000 --- a/Assets/Mirror/Examples/Common/FPS.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6635375fbc6be456ea640b75add6378e -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 deleted file mode 100644 index 85a73ff..0000000 --- a/Assets/Mirror/Examples/Discovery.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index ef0083d..0000000 --- a/Assets/Mirror/Examples/Discovery/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index a380a2b..0000000 --- a/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab +++ /dev/null @@ -1,118 +0,0 @@ -%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: 1410032569926419539} - - component: {fileID: 8188542106662419882} - 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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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: - sceneId: 0 - _assetId: 2863436854 - serverOnly: 0 - visible: 0 - hasSpawned: 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} diff --git a/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta deleted file mode 100644 index 1c818fa..0000000 --- a/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index ed0ba64..0000000 --- a/Assets/Mirror/Examples/Discovery/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 658d03b..0000000 --- a/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity +++ /dev/null @@ -1,731 +0,0 @@ -%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 deleted file mode 100644 index b02433f..0000000 --- a/Assets/Mirror/Examples/Discovery/Scenes/Scene.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 108d871..0000000 --- a/Assets/Mirror/Examples/Mirror.Examples.asmdef +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "Mirror.Examples", - "rootNamespace": "", - "references": [ - "GUID:30817c1a0e6d646d99c048fc403f5979", - "GUID:72872094b21c16e48b631b2224833d49", - "GUID:6055be8ebefd69e48b49212b09b47b2f" - ], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes.meta deleted file mode 100644 index bbe9ba2..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 7a4a337..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index a372565..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index d350850..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial +++ /dev/null @@ -1,14 +0,0 @@ -%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 deleted file mode 100644 index 0403873..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index bd2d613..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial +++ /dev/null @@ -1,14 +0,0 @@ -%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 deleted file mode 100644 index 40322e3..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 43d6617..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial +++ /dev/null @@ -1,14 +0,0 @@ -%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 deleted file mode 100644 index 02a172b..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 0953148..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index f39520d..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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 deleted file mode 100644 index ab00bc8..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index a394fe1..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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 deleted file mode 100644 index d890edb..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 08f5003..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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 deleted file mode 100644 index 3df4a27..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index fbeb501..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 5a41527..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index c6dcf15..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj +++ /dev/null @@ -1,119 +0,0 @@ -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 deleted file mode 100644 index e72ff2c..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta +++ /dev/null @@ -1,104 +0,0 @@ -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 deleted file mode 100644 index 1eb00d1..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index e01a611..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat +++ /dev/null @@ -1,77 +0,0 @@ -%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 deleted file mode 100644 index 3e1c3b8..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 6d235af..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 238287b..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab +++ /dev/null @@ -1,233 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 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_ConstrainProportionsScale: 0 - 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 - _assetId: 4214084439 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 0 - syncMode: 0 - syncInterval: 0 - target: {fileID: 5513112217680897778} - clientAuthority: 0 - syncPosition: 1 - syncRotation: 1 - syncScale: 0 - showGizmos: 0 - showOverlay: 0 - overlayColor: {r: 0, g: 0, b: 0, a: 0.5} - onlySyncOnChange: 1 - bufferResetMultiplier: 5 - positionSensitivity: 0.01 - rotationSensitivity: 0.01 - scaleSensitivity: 0.01 ---- !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: - syncDirection: 0 - 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: - syncDirection: 0 - 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 deleted file mode 100644 index 2d5d382..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index e6ac932..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab +++ /dev/null @@ -1,388 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - 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 - m_AdditionalVertexStreams: {fileID: 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: 8715117357206038899} - - component: {fileID: 114892629901890886} - - component: {fileID: 143011667059871024} - - component: {fileID: 4839740653866577337} - - component: {fileID: 115187108610643062} - - component: {fileID: 1849877933717427647} - - component: {fileID: 6261579163786439309} - 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.08, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - 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 - _assetId: 1707196853 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 1 - syncMode: 0 - syncInterval: 0 - target: {fileID: 4822224316094678} - clientAuthority: 0 - syncPosition: 1 - syncRotation: 1 - syncScale: 0 - showGizmos: 0 - showOverlay: 0 - overlayColor: {r: 0, g: 0, b: 0, a: 0.5} - onlySyncOnChange: 1 - bufferResetMultiplier: 5 - positionSensitivity: 0.01 - rotationSensitivity: 0.01 - scaleSensitivity: 0.01 ---- !u!114 &8715117357206038899 -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: 6cac48dc20f866148b44d0f9b5850761, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 ---- !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: 0 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 479a5196564ede84791870b414a13645, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - characterController: {fileID: 143011667059871024} - controlsCanvas: {fileID: 0} - moveSpeedMultiplier: 8 - maxTurnSpeed: 100 - turnDelta: 1 - initialJumpSpeed: 0.2 - maxJumpSpeed: 5 - jumpDelta: 0.2 - groundState: 2 - horizontal: 0 - vertical: 0 - turnSpeed: 0 - jumpSpeed: 0 - animVelocity: 0 - animRotation: 0 - velocity: {x: 0, y: 0, z: 0} - direction: {x: 0, y: 0, z: 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.02 - m_MinMoveDistance: 0 - 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!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: - syncDirection: 0 - syncMode: 0 - syncInterval: 0 - playerNumber: 0 - scoreIndex: 0 - matchIndex: 0 - score: 0 - clientMatchIndex: -1 ---- !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 &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: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - color: - serializedVersion: 2 - rgba: 4278190080 ---- !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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 0} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab.meta deleted file mode 100644 index 2aa9fe4..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Player.prefab.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 10884a4..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab +++ /dev/null @@ -1,203 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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 - _assetId: 2803719529 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 0 - 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: - syncDirection: 0 - 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_ConstrainProportionsScale: 0 - 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_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: 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 - m_AdditionalVertexStreams: {fileID: 0} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab.meta deleted file mode 100644 index b0e7226..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Prize.prefab.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 29fd22a..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# 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 deleted file mode 100644 index 668fabd..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index d749d32..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 0254722..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity +++ /dev/null @@ -1,753 +0,0 @@ -%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} - - component: {fileID: 1305256746} - 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!114 &1305256746 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1305256737} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 3504801306 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 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 deleted file mode 100644 index dae050d..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Game.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index b401e19..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity +++ /dev/null @@ -1,944 +0,0 @@ -%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: 12 - 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_LightingSettings: {fileID: 2039419912} ---- !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 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 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_ConstrainProportionsScale: 0 - 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: - 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 - runInBackground: 1 - autoStartServerBuild: 1 - autoConnectClientBuild: 0 - sendRate: 30 - offlineScene: - onlineScene: - transport: {fileID: 69965671} - networkAddress: localhost - maxConnections: 100 - authenticator: {fileID: 0} - playerPrefab: {fileID: 1480027675339556, guid: 1f4d376d8ca693049abd1744e4c79fad, type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 1 - spawnPrefabs: - - {fileID: 1139254171913846, guid: 8cec47ed46e0eff45966a5173d3aa0d3, type: 3} - timeInterpolationGui: 0 - 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_ConstrainProportionsScale: 0 - 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 - SendWindowSize: 4096 - ReceiveWindowSize: 4096 - MaxRetransmit: 40 - MaximizeSocketBuffers: 1 - ReliableMaxMessageSize: 298449 - UnreliableMaxMessageSize: 1199 - 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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_UseViewFrustumForShadowCasterCull: 1 - 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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 &1067574963 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1067574966} - - component: {fileID: 1067574965} - - component: {fileID: 1067574964} - m_Layer: 0 - m_Name: EventSystem - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1067574964 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1067574963} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} - m_Name: - m_EditorClassIdentifier: - m_SendPointerHoverToParent: 1 - m_HorizontalAxis: Horizontal - m_VerticalAxis: Vertical - m_SubmitButton: Submit - m_CancelButton: Cancel - m_InputActionsPerSecond: 10 - m_RepeatDelay: 0.5 - m_ForceModuleActive: 0 ---- !u!114 &1067574965 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1067574963} - 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 &1067574966 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1067574963} - 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: 4 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 0 - 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!850595691 &2039419912 -LightingSettings: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Settings.lighting - serializedVersion: 4 - m_GIWorkflowMode: 0 - m_EnableBakedLightmaps: 0 - m_EnableRealtimeLightmaps: 0 - m_RealtimeEnvironmentLighting: 1 - m_BounceScale: 1 - m_AlbedoBoost: 1 - m_IndirectOutputScale: 1 - m_UsingShadowmask: 1 - m_BakeBackend: 1 - m_LightmapMaxSize: 1024 - m_BakeResolution: 40 - m_Padding: 2 - m_LightmapCompression: 3 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAO: 0 - m_MixedBakeMode: 2 - m_LightmapsBakeMode: 1 - m_FilterMode: 1 - m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_RealtimeResolution: 2 - m_ForceWhiteAlbedo: 0 - m_ForceUpdates: 0 - m_FinalGather: 0 - m_FinalGatherRayCount: 256 - m_FinalGatherFiltering: 1 - m_PVRCulling: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 500 - m_PVREnvironmentSampleCount: 500 - m_PVREnvironmentReferencePointCount: 2048 - m_LightProbeSampleCountMultiplier: 4 - m_PVRBounces: 2 - m_PVRMinBounces: 2 - m_PVREnvironmentMIS: 0 - m_PVRFilteringMode: 2 - m_PVRDenoiserTypeDirect: 0 - m_PVRDenoiserTypeIndirect: 0 - m_PVRDenoiserTypeAO: 0 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_PVRTiledBaking: 0 ---- !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_ConstrainProportionsScale: 0 - 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 deleted file mode 100644 index 036bc0d..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/Main.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index bcb2ac2..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index a63e905..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs +++ /dev/null @@ -1,157 +0,0 @@ -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; - - public static new MultiSceneNetManager singleton { get; private set; } - - /// - /// Runs on both Server and Client - /// Networking is NOT initialized when this fires - /// - public override void Awake() - { - base.Awake(); - singleton = this; - } - - #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(NetworkConnectionToClient 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(NetworkConnectionToClient 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; - - // 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]); - - clientIndex++; - } - - #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++) - if (subScenes[index].IsValid()) - 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 ServerOnly mode now after stopping host client - if (mode == NetworkManagerMode.Offline) - 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 deleted file mode 100644 index dbca140..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 221c00b..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs +++ /dev/null @@ -1,44 +0,0 @@ -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 deleted file mode 100644 index 2343563..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 86008a7..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs +++ /dev/null @@ -1,39 +0,0 @@ -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; - } - } - - [ServerCallback] - void FixedUpdate() - { - 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 deleted file mode 100644 index a48884d..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsSimulator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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/PlayerCamera.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerCamera.cs deleted file mode 100644 index 232a9df..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerCamera.cs +++ /dev/null @@ -1,44 +0,0 @@ -using UnityEngine; -using UnityEngine.SceneManagement; - -// This sets up the scene camera for the local player - -namespace Mirror.Examples.MultipleAdditiveScenes -{ - public class PlayerCamera : NetworkBehaviour - { - Camera mainCam; - - void Awake() - { - mainCam = Camera.main; - } - - public override void OnStartLocalPlayer() - { - if (mainCam != null) - { - // configure and make camera a child of player with 3rd person offset - mainCam.orthographic = false; - mainCam.transform.SetParent(transform); - mainCam.transform.localPosition = new Vector3(0f, 3f, -8f); - mainCam.transform.localEulerAngles = new Vector3(10f, 0f, 0f); - } - else - Debug.LogWarning("PlayerCamera: Could not find a camera in scene with 'MainCamera' tag."); - } - - public override void OnStopLocalPlayer() - { - if (mainCam != null) - { - mainCam.transform.SetParent(null); - SceneManager.MoveGameObjectToScene(mainCam.gameObject, SceneManager.GetActiveScene()); - mainCam.orthographic = true; - mainCam.orthographicSize = 15f; - mainCam.transform.localPosition = new Vector3(0f, 70f, 0f); - mainCam.transform.localEulerAngles = new Vector3(90f, 0f, 0f); - } - } - } -} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerCamera.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerCamera.cs.meta deleted file mode 100644 index 6d4a9c9..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerCamera.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6cac48dc20f866148b44d0f9b5850761 -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 deleted file mode 100644 index 5d221bc..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs +++ /dev/null @@ -1,184 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.MultipleAdditiveScenes -{ - [RequireComponent(typeof(CapsuleCollider))] - [RequireComponent(typeof(CharacterController))] - [RequireComponent(typeof(NetworkTransform))] - [RequireComponent(typeof(Rigidbody))] - public class PlayerController : NetworkBehaviour - { - public enum GroundState : byte { Jumping, Falling, Grounded } - - [Header("Avatar Components")] - public CharacterController characterController; - - [Header("Movement")] - [Range(1, 20)] - public float moveSpeedMultiplier = 8f; - - [Header("Turning")] - [Range(1f, 200f)] - public float maxTurnSpeed = 100f; - [Range(.5f, 5f)] - public float turnDelta = 3f; - - [Header("Jumping")] - [Range(0.1f, 1f)] - public float initialJumpSpeed = 0.2f; - [Range(1f, 10f)] - public float maxJumpSpeed = 5f; - [Range(0.1f, 1f)] - public float jumpDelta = 0.2f; - - [Header("Diagnostics - Do Not Modify")] - public GroundState groundState = GroundState.Grounded; - - [Range(-1f, 1f)] - public float horizontal; - [Range(-1f, 1f)] - public float vertical; - - [Range(-200f, 200f)] - public float turnSpeed; - - [Range(-10f, 10f)] - public float jumpSpeed; - - [Range(-1.5f, 1.5f)] - public float animVelocity; - - [Range(-1.5f, 1.5f)] - public float animRotation; - - public Vector3Int velocity; - public Vector3 direction; - - void OnValidate() - { - if (characterController == null) - characterController = GetComponent(); - - // Override CharacterController default values - characterController.enabled = false; - characterController.skinWidth = 0.02f; - characterController.minMoveDistance = 0f; - - GetComponent().isKinematic = true; - - this.enabled = false; - } - - public override void OnStartAuthority() - { - characterController.enabled = true; - this.enabled = true; - } - - public override void OnStopAuthority() - { - this.enabled = false; - characterController.enabled = false; - } - - void Update() - { - if (!characterController.enabled) - return; - - HandleTurning(); - HandleJumping(); - HandleMove(); - - // Reset ground state - if (characterController.isGrounded) - groundState = GroundState.Grounded; - else if (groundState != GroundState.Jumping) - groundState = GroundState.Falling; - - // Diagnostic velocity...FloorToInt for display purposes - velocity = Vector3Int.FloorToInt(characterController.velocity); - } - - // TODO: Turning works while airborne...feature? - void HandleTurning() - { - // Q and E cancel each other out, reducing the turn to zero. - if (Input.GetKey(KeyCode.Q)) - turnSpeed = Mathf.MoveTowards(turnSpeed, -maxTurnSpeed, turnDelta); - if (Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, maxTurnSpeed, turnDelta); - - // If both pressed, reduce turning speed toward zero. - if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta); - - // If neither pressed, reduce turning speed toward zero. - if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E)) - turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta); - - transform.Rotate(0f, turnSpeed * Time.deltaTime, 0f); - } - - void HandleJumping() - { - // Handle variable force jumping. - // Jump starts with initial power on takeoff, and jumps higher / longer - // as player holds spacebar. Jump power is increased by a diminishing amout - // every frame until it reaches maxJumpSpeed, or player releases the spacebar, - // and then changes to the falling state until it gets grounded. - if (groundState != GroundState.Falling && Input.GetKey(KeyCode.Space)) - { - if (groundState != GroundState.Jumping) - { - // Start jump at initial power. - groundState = GroundState.Jumping; - jumpSpeed = initialJumpSpeed; - } - else - // Jumping has already started...increase power toward maxJumpSpeed over time. - jumpSpeed = Mathf.MoveTowards(jumpSpeed, maxJumpSpeed, jumpDelta); - - // If power has reached maxJumpSpeed, change to falling until grounded. - // This prevents over-applying jump power while already in the air. - if (jumpSpeed == maxJumpSpeed) - groundState = GroundState.Falling; - } - else if (groundState != GroundState.Grounded) - { - // handles running off a cliff and/or player released Spacebar. - groundState = GroundState.Falling; - jumpSpeed = Mathf.Min(jumpSpeed, maxJumpSpeed); - jumpSpeed += Physics.gravity.y * Time.deltaTime; - } - else - jumpSpeed = Physics.gravity.y * Time.deltaTime; - } - - // TODO: Directional input works while airborne...feature? - void HandleMove() - { - // Capture inputs - horizontal = Input.GetAxis("Horizontal"); - vertical = Input.GetAxis("Vertical"); - - // Create initial direction vector without jumpSpeed (y-axis). - direction = new Vector3(horizontal, 0f, vertical); - - // Clamp so diagonal strafing isn't a speed advantage. - direction = Vector3.ClampMagnitude(direction, 1f); - - // Transforms direction from local space to world space. - direction = transform.TransformDirection(direction); - - // Multiply for desired ground speed. - direction *= moveSpeedMultiplier; - - // Add jumpSpeed to direction as last step. - direction.y = jumpSpeed; - - // Finally move the character. - characterController.Move(direction * Time.deltaTime); - } - } -} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs.meta deleted file mode 100644 index c3bad11..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerController.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 08238b2..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index 3b9c9dd..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 02ad1b5..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs +++ /dev/null @@ -1,31 +0,0 @@ -using UnityEngine; - -namespace Mirror.Examples.MultipleAdditiveScenes -{ - public class RandomColor : NetworkBehaviour - { - public override void 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 deleted file mode 100644 index 2bef2a6..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/RandomColor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index e06a52c..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs +++ /dev/null @@ -1,52 +0,0 @@ -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 - [ServerCallback] - 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); - - // 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 deleted file mode 100644 index 1bb7ea3..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index ad2ecb6..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs +++ /dev/null @@ -1,24 +0,0 @@ -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Mirror.Examples.MultipleAdditiveScenes -{ - internal class Spawner - { - [ServerCallback] - internal static void InitialSpawn(Scene scene) - { - for (int i = 0; i < 10; i++) - SpawnReward(scene); - } - - [ServerCallback] - internal static void SpawnReward(Scene scene) - { - 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 deleted file mode 100644 index 9d9b2b1..0000000 --- a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index c8788e5..0000000 --- a/Assets/Mirror/Examples/MultipleMatches.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 7d19e91..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index ab42641..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab +++ /dev/null @@ -1,153 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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: 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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 &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: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - 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: 2985632515421915780} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 2439948753870522382} - m_TargetAssemblyTypeName: - 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 deleted file mode 100644 index 8ddee88..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 0e5cd3a..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab +++ /dev/null @@ -1,1967 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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_ConstrainProportionsScale: 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 - m_PresetInfoIsWorld: 0 ---- !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 - _assetId: 1992174301 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 0 - 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: - syncDirection: 0 - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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_WrapAround: 0 - 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_TargetAssemblyTypeName: - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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_WrapAround: 0 - 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_TargetAssemblyTypeName: - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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_ConstrainProportionsScale: 0 - 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - 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 deleted file mode 100644 index e358fcc..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index bb96954..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab +++ /dev/null @@ -1,307 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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: 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_ConstrainProportionsScale: 0 - 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: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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 &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: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - 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_SelectedColor: {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_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: 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_ConstrainProportionsScale: 0 - 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: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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: 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 deleted file mode 100644 index 3308e2c..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index a3dab28..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab +++ /dev/null @@ -1,67 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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 - _assetId: 4232591090 - serverOnly: 0 - visible: 0 - 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: - syncDirection: 0 - 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 deleted file mode 100644 index 66f3795..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index a3370cb..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab +++ /dev/null @@ -1,189 +0,0 @@ -%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_ConstrainProportionsScale: 0 - 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: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 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 &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_ConstrainProportionsScale: 0 - 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: 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_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 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: 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 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta deleted file mode 100644 index 27639dc..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index a6da1e3..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# 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/Scenes.meta b/Assets/Mirror/Examples/MultipleMatches/Scenes.meta deleted file mode 100644 index af27542..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 993ff0b..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity +++ /dev/null @@ -1,2982 +0,0 @@ -%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 deleted file mode 100644 index 234a173..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scenes/Main.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index bc1a9c0..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index ff63f50..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs +++ /dev/null @@ -1,652 +0,0 @@ -using System; -using System.Collections; -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; - - // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] - static void ResetStatics() - { - playerMatches.Clear(); - openMatches.Clear(); - matchConnections.Clear(); - playerInfos.Clear(); - waitingConnections.Clear(); - } - - #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 - /// - /// - [ClientCallback] - public void SelectMatch(Guid matchId) - { - 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 - /// - [ClientCallback] - public void RequestCreateMatch() - { - NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Create }); - } - - /// - /// Assigned in inspector to Join button - /// - [ClientCallback] - public void RequestJoinMatch() - { - if (selectedMatch == Guid.Empty) return; - - NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Join, matchId = selectedMatch }); - } - - /// - /// Assigned in inspector to Leave button - /// - [ClientCallback] - public void RequestLeaveMatch() - { - if (localJoinedMatch == Guid.Empty) return; - - NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Leave, matchId = localJoinedMatch }); - } - - /// - /// Assigned in inspector to Cancel button - /// - [ClientCallback] - public void RequestCancelMatch() - { - if (localPlayerMatch == Guid.Empty) return; - - NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Cancel }); - } - - /// - /// Assigned in inspector to Ready button - /// - [ClientCallback] - public void RequestReadyChange() - { - if (localPlayerMatch == Guid.Empty && localJoinedMatch == Guid.Empty) return; - - Guid matchId = localPlayerMatch == Guid.Empty ? localJoinedMatch : localPlayerMatch; - - NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Ready, matchId = matchId }); - } - - /// - /// Assigned in inspector to Start button - /// - [ClientCallback] - public void RequestStartMatch() - { - if (localPlayerMatch == Guid.Empty) return; - - NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Start }); - } - - /// - /// Called from - /// - [ClientCallback] - public void OnMatchEnded() - { - localPlayerMatch = Guid.Empty; - localJoinedMatch = Guid.Empty; - ShowLobbyView(); - } - - #endregion - - #region Server & Client Callbacks - - // Methods in this section are called from MatchNetworkManager's corresponding methods - - [ServerCallback] - internal void OnStartServer() - { - InitializeData(); - NetworkServer.RegisterHandler(OnServerMatchMessage); - } - - [ServerCallback] - internal void OnServerReady(NetworkConnectionToClient conn) - { - waitingConnections.Add(conn); - playerInfos.Add(conn, new PlayerInfo { playerIndex = this.playerIndex, ready = false }); - playerIndex++; - - SendMatchList(); - } - - [ServerCallback] - internal IEnumerator OnServerDisconnect(NetworkConnectionToClient conn) - { - // 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 (NetworkConnectionToClient 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 (NetworkConnectionToClient playerConn in matchConnections[playerInfo.matchId]) - if (playerConn != conn) - playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); - } - } - - SendMatchList(); - - yield return null; - } - - [ServerCallback] - internal void OnStopServer() - { - ResetCanvas(); - } - - [ClientCallback] - internal void OnClientConnect() - { - playerInfos.Add(NetworkClient.connection, new PlayerInfo { playerIndex = this.playerIndex, ready = false }); - } - - [ClientCallback] - internal void OnStartClient() - { - InitializeData(); - ShowLobbyView(); - createButton.gameObject.SetActive(true); - joinButton.gameObject.SetActive(true); - NetworkClient.RegisterHandler(OnClientMatchMessage); - } - - [ClientCallback] - internal void OnClientDisconnect() - { - InitializeData(); - } - - [ClientCallback] - internal void OnStopClient() - { - ResetCanvas(); - } - - #endregion - - #region Server Match Message Handlers - - [ServerCallback] - void OnServerMatchMessage(NetworkConnectionToClient conn, ServerMatchMessage msg) - { - 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; - } - } - } - - [ServerCallback] - void OnServerPlayerReady(NetworkConnectionToClient conn, Guid matchId) - { - PlayerInfo playerInfo = playerInfos[conn]; - playerInfo.ready = !playerInfo.ready; - playerInfos[conn] = playerInfo; - - HashSet connections = matchConnections[matchId]; - PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); - - foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) - playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); - } - - [ServerCallback] - void OnServerLeaveMatch(NetworkConnectionToClient conn, Guid matchId) - { - 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 (NetworkConnectionToClient playerConn in matchConnections[matchId]) - playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); - - SendMatchList(); - - conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); - } - - [ServerCallback] - void OnServerCreateMatch(NetworkConnectionToClient conn) - { - if (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(); - } - - [ServerCallback] - void OnServerCancelMatch(NetworkConnectionToClient conn) - { - if (!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 (NetworkConnectionToClient 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(); - } - } - - [ServerCallback] - void OnServerStartMatch(NetworkConnectionToClient conn) - { - if (!playerMatches.ContainsKey(conn)) return; - - Guid matchId; - if (playerMatches.TryGetValue(conn, out matchId)) - { - GameObject matchControllerObject = Instantiate(matchControllerPrefab); - matchControllerObject.GetComponent().matchId = matchId; - NetworkServer.Spawn(matchControllerObject); - - MatchController matchController = matchControllerObject.GetComponent(); - - foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) - { - playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Started }); - - GameObject player = Instantiate(NetworkManager.singleton.playerPrefab); - player.GetComponent().matchId = matchId; - 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; - } - } - - [ServerCallback] - void OnServerJoinMatch(NetworkConnectionToClient conn, Guid matchId) - { - if (!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 (NetworkConnectionToClient playerConn in matchConnections[matchId]) - playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); - } - - /// - /// Sends updated match list to all waiting connections or just one if specified - /// - /// - [ServerCallback] - internal void SendMatchList(NetworkConnectionToClient conn = null) - { - if (conn != null) - conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); - else - foreach (NetworkConnectionToClient waiter in waitingConnections) - waiter.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); - } - - #endregion - - #region Client Match Message Handler - - [ClientCallback] - void OnClientMatchMessage(ClientMatchMessage msg) - { - 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; - } - } - } - - [ClientCallback] - 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; - } - } - - [ClientCallback] - void ShowRoomView() - { - lobbyView.SetActive(false); - roomView.SetActive(true); - } - - [ClientCallback] - 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); - - Toggle toggle = newMatch.GetComponent(); - toggle.group = toggleGroup; - if (matchInfo.matchId == selectedMatch) - toggle.isOn = true; - } - } - - #endregion - } -} diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta deleted file mode 100644 index 9379f5c..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index a6f24ec..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs +++ /dev/null @@ -1,47 +0,0 @@ -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); - } - - [ClientCallback] - public void MakePlay() - { - if (matchController.currentPlayer.isLocalPlayer) - matchController.CmdMakePlay(cellValue); - } - - [ClientCallback] - 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 deleted file mode 100644 index 2ab1003..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index f066e92..0000000 --- a/Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs +++ /dev/null @@ -1,310 +0,0 @@ -using System; -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); - } - - [ClientCallback] - 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; - } - } - - [ClientCallback] - 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; - } - - } - - [ServerCallback] - 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