...
@@ -0,0 +1,18 @@
|
||||
#if !FUSION_DEV
|
||||
|
||||
#region Assets/Photon/Fusion/Runtime/AssemblyAttributes/FusionAssemblyAttributes.Common.cs
|
||||
|
||||
// merged AssemblyAttributes
|
||||
|
||||
#region RegisterResourcesLoader.cs
|
||||
|
||||
// register a default loader; it will attempt to load the asset from their default paths if they happen to be Resources
|
||||
[assembly: Fusion.FusionGlobalScriptableObjectResource(typeof(Fusion.FusionGlobalScriptableObject), Order = 2000, AllowFallback = true)]
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87e3886742c1ae04096a83c7188f1d9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/Photon/Fusion/Runtime/Fusion.Unity.asmdef
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "Fusion.Unity",
|
||||
"rootNamespace": "Fusion",
|
||||
"references": [
|
||||
"GUID:9e24947de15b9834991c9d8411ea37cf",
|
||||
"GUID:84651a3751eca9349aac36a66bba901b",
|
||||
"GUID:2665a8d13d1b3f18800f46e256720795"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.burst",
|
||||
"expression": "",
|
||||
"define": "FUSION_BURST"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.addressables",
|
||||
"expression": "1.0",
|
||||
"define": "FUSION_ENABLE_ADDRESSABLES"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.addressables",
|
||||
"expression": "1.20",
|
||||
"define": "FUSION_ENABLE_ADDRESSABLES_LOCAL_PHYSICS"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.multiplayer.playmode",
|
||||
"expression": "0.6",
|
||||
"define": "FUSION_ENABLE_MPPM"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Assets/Photon/Fusion/Runtime/Fusion.Unity.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1baf1ffff1031e948b3b228ab3453251
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
4315
Assets/Photon/Fusion/Runtime/Fusion.Unity.cs
Normal file
11
Assets/Photon/Fusion/Runtime/Fusion.Unity.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a69219964762b240b6138a56c829f26
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace Fusion {
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
#endif
|
||||
|
||||
public class FusionAddressablePrefabsPreloader : MonoBehaviour {
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
private List<AsyncOperationHandle<GameObject>> _handles = new List<AsyncOperationHandle<GameObject>>();
|
||||
|
||||
private async void Start() {
|
||||
var config = NetworkProjectConfig.Global;
|
||||
|
||||
// there are a few ways to load an asset with Addressables (by label, by IResourceLocation, by address etc.)
|
||||
// but it seems that they're not fully interchangeable, i.e. loading by label will not make loading by address
|
||||
// be reported as done immediately; hence the only way to preload an asset for Quantum is to replicate
|
||||
// what it does internally, i.e. load with the very same parameters
|
||||
|
||||
foreach (var (id, source) in config.PrefabTable.GetEntries()) {
|
||||
if (source is NetworkPrefabSourceAddressable addressable) {
|
||||
// we can't just LoadAssetAsync() because source does it, too:
|
||||
// https://forum.unity.com/threads/1-15-1-assetreference-not-allow-loadassetasync-twice.959910/
|
||||
var key = addressable.RuntimeKey;
|
||||
var handle = Addressables.LoadAssetAsync<GameObject>(key);
|
||||
await handle.Task;
|
||||
_handles.Add(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy() {
|
||||
foreach (var handle in _handles) {
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccb29b1c478478c418765bc307a473ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
75
Assets/Photon/Fusion/Runtime/FusionBasicBillboard.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
namespace Fusion {
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Component which automatically faces this GameObject toward the supplied Camera. If Camera == null, will face towards Camera.main.
|
||||
/// </summary>
|
||||
[Fusion.ScriptHelp(BackColor = ScriptHeaderBackColor.Olive)]
|
||||
[ExecuteAlways]
|
||||
public class FusionBasicBillboard : Fusion.Behaviour {
|
||||
|
||||
/// <summary>
|
||||
/// Force a particular camera to billboard this object toward. Leave null to use Camera.main.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public Camera Camera;
|
||||
|
||||
// Camera find is expensive, so do it once per update for ALL implementations
|
||||
static float _lastCameraFindTime;
|
||||
static Camera _currentCam;
|
||||
|
||||
private void OnEnable() {
|
||||
UpdateLookAt();
|
||||
}
|
||||
|
||||
private void OnDisable() {
|
||||
transform.localRotation = default;
|
||||
}
|
||||
|
||||
Camera MainCamera {
|
||||
set {
|
||||
_currentCam = value;
|
||||
}
|
||||
get {
|
||||
|
||||
var time = Time.time;
|
||||
// Only look for the camera once per Update.
|
||||
if (time == _lastCameraFindTime)
|
||||
return _currentCam;
|
||||
|
||||
_lastCameraFindTime = time;
|
||||
var cam = Camera.main;
|
||||
_currentCam = cam;
|
||||
return cam;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmos() {
|
||||
LateUpdate();
|
||||
}
|
||||
#endif
|
||||
|
||||
private void LateUpdate() {
|
||||
UpdateLookAt();
|
||||
}
|
||||
|
||||
public void UpdateLookAt() {
|
||||
|
||||
var cam = Camera ? Camera : MainCamera;
|
||||
|
||||
if (cam) {
|
||||
if (enabled) {
|
||||
transform.rotation = cam.transform.rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
static void ResetStatics() {
|
||||
_currentCam = default;
|
||||
_lastCameraFindTime = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Photon/Fusion/Runtime/FusionBasicBillboard.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25acde9209338d24d83cc1c826297be4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
676
Assets/Photon/Fusion/Runtime/FusionBootstrap.cs
Normal file
@@ -0,0 +1,676 @@
|
||||
namespace Fusion {
|
||||
using System;
|
||||
using Fusion.Sockets;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Statistics;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// A Fusion prototyping class for starting up basic networking. Add this component to your startup scene, and supply a <see cref="RunnerPrefab"/>.
|
||||
/// Can be set to automatically startup the network, display an in-game menu, or allow simplified start calls like <see cref="StartHost()"/>.
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Fusion/Fusion Bootstrap")]
|
||||
[ScriptHelp(BackColor = ScriptHeaderBackColor.Steel)]
|
||||
public class FusionBootstrap : Fusion.Behaviour {
|
||||
|
||||
/// <summary>
|
||||
/// Selection for how <see cref="FusionBootstrap"/> will behave at startup.
|
||||
/// </summary>
|
||||
public enum StartModes {
|
||||
UserInterface,
|
||||
Automatic,
|
||||
Manual
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current stage of connection or shutdown.
|
||||
/// </summary>
|
||||
public enum Stage {
|
||||
Disconnected,
|
||||
StartingUp,
|
||||
UnloadOriginalScene,
|
||||
ConnectingServer,
|
||||
ConnectingClients,
|
||||
AllConnected,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class StartCommand : FusionMppmCommand {
|
||||
public string RoomName;
|
||||
public SceneRef InitialScene;
|
||||
public int ClientCount;
|
||||
public bool IsShared;
|
||||
|
||||
public override void Execute() {
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public static StartCommand Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supply a Prefab or a scene object which has the <see cref="NetworkRunner"/> component on it,
|
||||
/// as well as any runner dependent components which implement <see cref="INetworkRunnerCallbacks"/>,
|
||||
/// such as <see cref="NetworkEvents"/> or your own custom INetworkInput implementations.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[WarnIf(nameof(RunnerPrefab), false, "No " + nameof(RunnerPrefab) + " supplied. Will search for a " + nameof(NetworkRunner) + " in the scene at startup.")]
|
||||
public NetworkRunner RunnerPrefab;
|
||||
|
||||
/// <summary>
|
||||
/// Select how network startup will be triggered. Automatically, by in-game menu selection, or exclusively by script.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[WarnIf(nameof(StartMode), (long)StartModes.Manual, "Start network by calling the methods " + nameof(StartHost) + "(), " + nameof(StartServer) + "(), " + nameof(StartClient) + "(), " + nameof(StartHostPlusClients) + "(), or " + nameof(StartServerPlusClients) + "()")]
|
||||
public StartModes StartMode = StartModes.UserInterface;
|
||||
|
||||
/// <summary>
|
||||
/// When <see cref="StartMode"/> is set to <see cref="StartModes.Automatic"/>, this option selects if the <see cref="NetworkRunner"/>
|
||||
/// will be started as a dedicated server, or as a host (which is a server with a local player).
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[UnityEngine.Serialization.FormerlySerializedAs("Server")]
|
||||
[DrawIf(nameof(StartMode), (long)StartModes.Automatic, Hide = true)]
|
||||
public GameMode AutoStartAs = GameMode.Shared;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="FusionBootstrapDebugGUI"/> will not render GUI elements while <see cref="CurrentStage"/> == <see cref="Stage.AllConnected"/>.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[DrawIf(nameof(StartMode), (long)StartModes.UserInterface, Hide = true)]
|
||||
public bool AutoHideGUI = true;
|
||||
|
||||
/// <summary>
|
||||
/// The number of client <see cref="NetworkRunner"/> instances that will be created if running in Mulit-Peer Mode.
|
||||
/// When using the Select start mode, this number will be the default value for the additional clients option box.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[DrawIf(nameof(ShowAutoClients), Hide = true)]
|
||||
public int AutoClients = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How long to wait after starting a peer before starting the next one.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public float ClientStartDelay = 0.1f;
|
||||
|
||||
/// <summary>
|
||||
/// The port that server/host <see cref="NetworkRunner"/> will use.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public ushort ServerPort; // Any port
|
||||
|
||||
/// <summary>
|
||||
/// The default room name to use when connecting to photon cloud.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public string DefaultRoomName = string.Empty; // empty/null means Random Room Name
|
||||
|
||||
[NonSerialized]
|
||||
NetworkRunner _server;
|
||||
|
||||
/// <summary>
|
||||
/// The Scene that will be loaded after network shutdown completes (all peers have disconnected).
|
||||
/// If this field is null or invalid, will be set to the current scene when <see cref="FusionBootstrap"/> runs Awake().
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[ScenePath]
|
||||
public string InitialScenePath;
|
||||
|
||||
// TODO: this is debt
|
||||
static string _initialScenePath;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates which step of the startup process <see cref="FusionBootstrap"/> is currently in.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[SerializeField]
|
||||
[ReadOnly]
|
||||
protected Stage _currentStage;
|
||||
|
||||
/// <summary>
|
||||
/// Requires Multiplayer Play Mode (MPPM) to be installed. If enabled, <see cref="FusionBootstrap"/> will automatically join the virtual instance.
|
||||
/// </summary>
|
||||
[DrawIf(nameof(IsMPPMEnabled), true)]
|
||||
[Header("Multiplayer Play Mode")]
|
||||
public bool AutoConnectVirtualInstances = true;
|
||||
/// <summary>
|
||||
/// How much to wait before the main instance lets the virtual instances connect.
|
||||
/// </summary>
|
||||
[DrawIf(nameof(IsMPPMEnabled), true)]
|
||||
public float VirtualInstanceConnectDelay = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates which step of the startup process <see cref="FusionBootstrap"/> is currently in.
|
||||
/// </summary>
|
||||
public Stage CurrentStage {
|
||||
get => _currentStage;
|
||||
internal set {
|
||||
_currentStage = value;
|
||||
#if UNITY_EDITOR
|
||||
// Hack to force an inspector refresh when this value changes, as it affects which buttons are shown.
|
||||
EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The index number used for the last created peer.
|
||||
/// </summary>
|
||||
public int LastCreatedClientIndex { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The server mode that was used for initial startup. Used to inform UI which client modes should be available.
|
||||
/// </summary>
|
||||
public GameMode CurrentServerMode { get; internal set; }
|
||||
|
||||
protected bool CanAddClients => CurrentStage == Stage.AllConnected && CurrentServerMode > 0 && CurrentServerMode != GameMode.Shared && CurrentServerMode != GameMode.Single;
|
||||
protected bool CanAddSharedClients => CurrentStage == Stage.AllConnected && CurrentServerMode > 0 && CurrentServerMode == GameMode.Shared;
|
||||
protected bool IsShutdown => CurrentStage == Stage.Disconnected;
|
||||
protected bool IsShutdownAndMultiPeer => CurrentStage == Stage.Disconnected && UsingMultiPeerMode;
|
||||
|
||||
protected bool UsingMultiPeerMode => NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple;
|
||||
protected bool ShowAutoClients => UsingMultiPeerMode && (StartMode == StartModes.UserInterface || (StartMode == StartModes.Automatic && AutoStartAs != GameMode.Single));
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected virtual void Reset() {
|
||||
if (TryGetComponent<FusionBootstrapDebugGUI>(out var ndsg) == false) {
|
||||
ndsg = gameObject.AddComponent<FusionBootstrapDebugGUI>();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
protected virtual void Start() {
|
||||
|
||||
if (_initialScenePath == null) {
|
||||
if (string.IsNullOrEmpty(InitialScenePath)) {
|
||||
var currentScene = SceneManager.GetActiveScene();
|
||||
if (currentScene.IsValid()) {
|
||||
_initialScenePath = currentScene.path;
|
||||
} else {
|
||||
// Last fallback is the first entry in the build settings
|
||||
_initialScenePath = SceneManager.GetSceneByBuildIndex(0).path;
|
||||
}
|
||||
|
||||
InitialScenePath = _initialScenePath;
|
||||
} else {
|
||||
_initialScenePath = InitialScenePath;
|
||||
}
|
||||
}
|
||||
|
||||
var config = NetworkProjectConfig.Global;
|
||||
var isMultiPeer = config.PeerMode == NetworkProjectConfig.PeerModes.Multiple;
|
||||
|
||||
var existingRunner = FindFirstObjectByType<NetworkRunner>();
|
||||
|
||||
if (existingRunner && existingRunner != RunnerPrefab) {
|
||||
if (existingRunner.State != NetworkRunner.States.Shutdown) {
|
||||
// disable
|
||||
enabled = false;
|
||||
|
||||
// destroy this and GUI (if exists), and return
|
||||
var gui = GetComponent<FusionBootstrapDebugGUI>();
|
||||
if (gui) {
|
||||
Destroy(gui);
|
||||
}
|
||||
|
||||
Destroy(this);
|
||||
return;
|
||||
} else {
|
||||
// If no RunnerPrefab is supplied, use the scene runner.
|
||||
if (RunnerPrefab == null) {
|
||||
RunnerPrefab = existingRunner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FusionMppm.Status == FusionMppmStatus.VirtualInstance && AutoConnectVirtualInstances) {
|
||||
StartCoroutine(StartWithMppmVirtualInstance());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (StartMode) {
|
||||
case StartModes.Manual:
|
||||
// skip
|
||||
return;
|
||||
case StartModes.Automatic: {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
int clientCount;
|
||||
if (AutoStartAs == GameMode.Single) {
|
||||
clientCount = 0;
|
||||
} else if (isMultiPeer) {
|
||||
clientCount = AutoClients;
|
||||
} else if (AutoStartAs == GameMode.Client || AutoStartAs == GameMode.Shared || AutoStartAs == GameMode.AutoHostOrClient) {
|
||||
clientCount = 1;
|
||||
} else {
|
||||
clientCount = 0;
|
||||
}
|
||||
|
||||
StartCoroutine(StartWithClients(AutoStartAs, sceneRef, clientCount));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ShowUserInterface();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void ShowUserInterface() {
|
||||
if (TryGetComponent<FusionBootstrapDebugGUI>(out var gui) == false) {
|
||||
gui = gameObject.AddComponent<FusionBootstrapDebugGUI>();
|
||||
}
|
||||
gui.enabled = true;
|
||||
}
|
||||
|
||||
private bool TryGetSceneRef(out SceneRef sceneRef) {
|
||||
var activeScene = SceneManager.GetActiveScene();
|
||||
if (activeScene.buildIndex < 0 || activeScene.buildIndex >= SceneManager.sceneCountInBuildSettings) {
|
||||
sceneRef = default;
|
||||
return false;
|
||||
} else {
|
||||
sceneRef = SceneRef.FromIndex(activeScene.buildIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a single player instance.
|
||||
/// </summary>
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public virtual void StartSinglePlayer() {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Single, sceneRef, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a server instance.
|
||||
/// </summary>
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public virtual void StartServer() {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Server, sceneRef, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a host instance. This is a server instance, with a local player.
|
||||
/// </summary>
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public virtual void StartHost() {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Host, sceneRef, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a client instance.
|
||||
/// </summary>
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public virtual void StartClient() {
|
||||
StartCoroutine(StartWithClients(GameMode.Client, default, 1));
|
||||
}
|
||||
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public virtual void StartSharedClient() {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Shared, sceneRef, 1));
|
||||
}
|
||||
}
|
||||
|
||||
[EditorButton("Start Auto Host Or Client", EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public virtual void StartAutoClient() {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.AutoHostOrClient, sceneRef, 1));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a Fusion server instance, and the number of client instances indicated by <see cref="AutoClients"/>.
|
||||
/// InstanceMode must be set to Multi-Peer mode, as this requires multiple <see cref="NetworkRunner"/> instances.
|
||||
/// </summary>
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public virtual void StartServerPlusClients() {
|
||||
StartServerPlusClients(AutoClients);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a Fusion host instance, and the number of client instances indicated by <see cref="AutoClients"/>.
|
||||
/// InstanceMode must be set to Multi-Peer mode, as this requires multiple <see cref="NetworkRunner"/> instances.
|
||||
/// </summary>
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(IsShutdown), Hide = true)]
|
||||
public void StartHostPlusClients() {
|
||||
StartHostPlusClients(AutoClients);
|
||||
}
|
||||
|
||||
[EditorButton(EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(CurrentStage), Hide = true)]
|
||||
public void Shutdown() {
|
||||
ShutdownAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a Fusion server instance, and the indicated number of client instances.
|
||||
/// InstanceMode must be set to Multi-Peer mode, as this requires multiple <see cref="NetworkRunner"/> instances.
|
||||
/// </summary>
|
||||
public virtual void StartServerPlusClients(int clientCount) {
|
||||
if (NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple) {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Server, sceneRef, clientCount));
|
||||
}
|
||||
} else {
|
||||
Debug.LogWarning($"Unable to start multiple {nameof(NetworkRunner)}s in Unique Instance mode.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a Fusion host instance (server with local player), and the indicated number of additional client instances.
|
||||
/// InstanceMode must be set to Multi-Peer mode, as this requires multiple <see cref="NetworkRunner"/> instances.
|
||||
/// </summary>
|
||||
public void StartHostPlusClients(int clientCount) {
|
||||
if (NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple) {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Host, sceneRef, clientCount));
|
||||
}
|
||||
} else {
|
||||
Debug.LogWarning($"Unable to start multiple {nameof(NetworkRunner)}s in Unique Instance mode.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a Fusion host instance (server with local player), and the indicated number of additional client instances.
|
||||
/// InstanceMode must be set to Multi-Peer mode, as this requires multiple <see cref="NetworkRunner"/> instances.
|
||||
/// </summary>
|
||||
public void StartMultipleClients(int clientCount) {
|
||||
if (NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple) {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Client, sceneRef, clientCount));
|
||||
}
|
||||
} else {
|
||||
Debug.LogWarning($"Unable to start multiple {nameof(NetworkRunner)}s in Unique Instance mode.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start as Room on the Photon cloud, and connects as one or more clients.
|
||||
/// </summary>
|
||||
/// <param name="clientCount"></param>
|
||||
public void StartMultipleSharedClients(int clientCount) {
|
||||
if (NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple) {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.Shared, sceneRef, clientCount));
|
||||
}
|
||||
} else {
|
||||
Debug.LogWarning($"Unable to start multiple {nameof(NetworkRunner)}s in Unique Instance mode.");
|
||||
}
|
||||
}
|
||||
|
||||
public void StartMultipleAutoClients(int clientCount) {
|
||||
if (NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple) {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
StartCoroutine(StartWithClients(GameMode.AutoHostOrClient, sceneRef, clientCount));
|
||||
}
|
||||
} else {
|
||||
Debug.LogWarning($"Unable to start multiple {nameof(NetworkRunner)}s in Unique Instance mode.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ShutdownAll() {
|
||||
foreach (var runner in NetworkRunner.Instances.ToList()) {
|
||||
if (runner != null && runner.IsRunning) {
|
||||
runner.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
SceneManager.LoadSceneAsync(_initialScenePath);
|
||||
// Destroy our DontDestroyOnLoad objects to finish the reset
|
||||
Destroy(RunnerPrefab.gameObject);
|
||||
Destroy(gameObject);
|
||||
CurrentStage = Stage.Disconnected;
|
||||
CurrentServerMode = 0;
|
||||
}
|
||||
|
||||
|
||||
protected IEnumerator StartWithClients(GameMode serverMode, SceneRef sceneRef, int clientCount) {
|
||||
// Avoid double clicks or disallow multiple startup calls.
|
||||
if (CurrentStage != Stage.Disconnected) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
bool includesServerStart = serverMode != GameMode.Shared && serverMode != GameMode.Client && serverMode != GameMode.AutoHostOrClient;
|
||||
|
||||
if (!includesServerStart && clientCount == 0) {
|
||||
Debug.LogError($"{nameof(GameMode)} is set to {serverMode}, and {nameof(clientCount)} is set to zero. Starting no network runners.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
CurrentStage = Stage.StartingUp;
|
||||
|
||||
var currentScene = SceneManager.GetActiveScene();
|
||||
|
||||
// must have a runner
|
||||
if (!RunnerPrefab) {
|
||||
Debug.LogError($"{nameof(RunnerPrefab)} not set, can't perform debug start.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
// Clone the RunnerPrefab so we can safely delete the startup scene (the prefab might be part of it, rather than an asset).
|
||||
RunnerPrefab = Instantiate(RunnerPrefab);
|
||||
DontDestroyOnLoad(RunnerPrefab);
|
||||
RunnerPrefab.name = "Temporary Runner Prefab";
|
||||
|
||||
// Single-peer can't start more than one peer. Validate clientCount to make sure it complies with current PeerMode.
|
||||
var config = NetworkProjectConfig.Global;
|
||||
if (config.PeerMode != NetworkProjectConfig.PeerModes.Multiple) {
|
||||
int maxClientsAllowed = includesServerStart ? 0 : 1;
|
||||
if (clientCount > maxClientsAllowed) {
|
||||
Debug.LogWarning($"Instance mode must be set to {nameof(NetworkProjectConfig.PeerModes.Multiple)} to perform a debug start multiple peers. Restricting client count to {maxClientsAllowed}.");
|
||||
clientCount = maxClientsAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
// If NDS is starting more than 1 shared or auto client, they need to use the same Session Name, otherwise, they will end up on different Rooms
|
||||
// as Fusion creates a Random Session Name when no name is passed on the args
|
||||
var localMultipeerCheck = (serverMode == GameMode.Shared || serverMode == GameMode.AutoHostOrClient || serverMode == GameMode.Server || serverMode == GameMode.Host) &&
|
||||
clientCount > 1 &&
|
||||
config.PeerMode == NetworkProjectConfig.PeerModes.Multiple;
|
||||
var isMppmMainInstance = FusionMppm.Status == FusionMppmStatus.MainInstance;
|
||||
|
||||
if ((localMultipeerCheck || isMppmMainInstance) && string.IsNullOrEmpty(DefaultRoomName)) {
|
||||
DefaultRoomName = Guid.NewGuid().ToString();
|
||||
Debug.Log($"Generated Session Name: {DefaultRoomName}");
|
||||
}
|
||||
|
||||
if (gameObject.transform.parent) {
|
||||
Debug.LogWarning($"{nameof(FusionBootstrap)} can't be a child game object, un-parenting.");
|
||||
gameObject.transform.parent = null;
|
||||
}
|
||||
|
||||
DontDestroyOnLoad(gameObject);
|
||||
CurrentServerMode = serverMode;
|
||||
|
||||
// start server, just take address from it
|
||||
if (includesServerStart) {
|
||||
_server = Instantiate(RunnerPrefab);
|
||||
_server.name = serverMode.ToString();
|
||||
|
||||
var serverTask = InitializeNetworkRunner(_server, serverMode, NetAddress.Any(ServerPort), sceneRef, (runner) => {
|
||||
#if FUSION_DEV
|
||||
var name = _server.name; // closures do not capture values, need a local var to save it
|
||||
Debug.Log($"Server NetworkRunner '{name}' started.");
|
||||
#endif
|
||||
});
|
||||
|
||||
while (serverTask.IsCompleted == false) {
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
|
||||
if (serverTask.IsFaulted) {
|
||||
Log.Debug($"Unable to start server: {serverTask.Exception}");
|
||||
|
||||
ShutdownAll();
|
||||
yield break;
|
||||
}
|
||||
|
||||
// this action is called after InitializeNetworkRunner for the server has completed startup
|
||||
yield return StartClients(clientCount, serverMode, sceneRef);
|
||||
} else {
|
||||
yield return StartClients(clientCount, serverMode, sceneRef);
|
||||
}
|
||||
|
||||
if (FusionMppm.Status == FusionMppmStatus.MainInstance && serverMode != GameMode.Single) {
|
||||
if (VirtualInstanceConnectDelay > 0) {
|
||||
yield return new WaitForSecondsRealtime(VirtualInstanceConnectDelay);
|
||||
}
|
||||
FusionMppm.MainEditor?.Send(new StartCommand {
|
||||
RoomName = DefaultRoomName,
|
||||
InitialScene = sceneRef,
|
||||
ClientCount = 1,
|
||||
IsShared = serverMode == GameMode.Shared
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerator StartWithMppmVirtualInstance() {
|
||||
while (StartCommand.Instance == null) {
|
||||
yield return null;
|
||||
}
|
||||
|
||||
var command = StartCommand.Instance;
|
||||
StartCommand.Instance = null;
|
||||
|
||||
DefaultRoomName = command.RoomName;
|
||||
yield return StartClients(command.ClientCount, command.IsShared ? GameMode.Shared : GameMode.Client, command.InitialScene);
|
||||
}
|
||||
|
||||
[EditorButton("Add Additional Client", EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(CanAddClients), Hide = true)]
|
||||
public void AddClient() {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
AddClient(GameMode.Client, sceneRef);
|
||||
}
|
||||
}
|
||||
|
||||
[EditorButton("Add Additional Shared Client", EditorButtonVisibility.PlayMode)]
|
||||
[DrawIf(nameof(CanAddSharedClients), Hide = true)]
|
||||
public void AddSharedClient() {
|
||||
if (TryGetSceneRef(out var sceneRef)) {
|
||||
AddClient(GameMode.Shared, sceneRef);
|
||||
}
|
||||
}
|
||||
|
||||
public Task AddClient(GameMode serverMode, SceneRef sceneRef) {
|
||||
var client = Instantiate(RunnerPrefab);
|
||||
DontDestroyOnLoad(client);
|
||||
|
||||
client.name = $"Client {(Char)(65 + LastCreatedClientIndex++)}";
|
||||
|
||||
// if server mode is Shared or AutoHostOrClient, then game client mode is the same as the server, otherwise it is client
|
||||
var mode = GameMode.Client;
|
||||
switch (serverMode) {
|
||||
case GameMode.Shared:
|
||||
case GameMode.AutoHostOrClient:
|
||||
mode = serverMode;
|
||||
break;
|
||||
}
|
||||
|
||||
#if FUSION_DEV
|
||||
var clientTask = InitializeNetworkRunner(client, mode, NetAddress.Any(), sceneRef, (runner) => {
|
||||
var name = client.name; // closures do not capture values, need a local var to save it
|
||||
Debug.Log($"Client NetworkRunner '{name}' started.");
|
||||
});
|
||||
#else
|
||||
var clientTask = InitializeNetworkRunner(client, mode, NetAddress.Any(), sceneRef, null);
|
||||
#endif
|
||||
|
||||
return clientTask;
|
||||
}
|
||||
|
||||
protected IEnumerator StartClients(int clientCount, GameMode serverMode, SceneRef sceneRef = default) {
|
||||
|
||||
CurrentStage = Stage.ConnectingClients;
|
||||
|
||||
var clientTasks = new List<Task>();
|
||||
for (int i = 0; i < clientCount; ++i) {
|
||||
clientTasks.Add(AddClient(serverMode, sceneRef));
|
||||
yield return new WaitForSeconds(ClientStartDelay);
|
||||
}
|
||||
|
||||
var clientsStartTask = Task.WhenAll(clientTasks);
|
||||
|
||||
while (clientsStartTask.IsCompleted == false) {
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
|
||||
if (clientsStartTask.IsFaulted) {
|
||||
Debug.LogWarning(clientsStartTask.Exception);
|
||||
}
|
||||
|
||||
CurrentStage = Stage.AllConnected;
|
||||
}
|
||||
|
||||
protected virtual Task InitializeNetworkRunner(NetworkRunner runner, GameMode gameMode, NetAddress address, SceneRef scene, Action<NetworkRunner> onGameStarted,
|
||||
INetworkRunnerUpdater updater = null) {
|
||||
|
||||
var sceneManager = runner.GetComponent<INetworkSceneManager>();
|
||||
if (sceneManager == null) {
|
||||
Debug.Log($"NetworkRunner does not have any component implementing {nameof(INetworkSceneManager)} interface, adding {nameof(NetworkSceneManagerDefault)}.", runner);
|
||||
sceneManager = runner.gameObject.AddComponent<NetworkSceneManagerDefault>();
|
||||
}
|
||||
|
||||
var objectProvider = runner.GetComponent<INetworkObjectProvider>();
|
||||
if (objectProvider == null) {
|
||||
Debug.Log($"NetworkRunner does not have any component implementing {nameof(INetworkObjectProvider)} interface, adding {nameof(NetworkObjectProviderDefault)}.", runner);
|
||||
objectProvider = runner.gameObject.AddComponent<NetworkObjectProviderDefault>();
|
||||
}
|
||||
|
||||
var sceneInfo = new NetworkSceneInfo();
|
||||
if (scene.IsValid) {
|
||||
sceneInfo.AddSceneRef(scene, LoadSceneMode.Additive);
|
||||
}
|
||||
|
||||
return runner.StartGame(new StartGameArgs {
|
||||
GameMode = gameMode,
|
||||
Address = address,
|
||||
Scene = sceneInfo,
|
||||
SessionName = DefaultRoomName,
|
||||
OnGameStarted = onGameStarted,
|
||||
SceneManager = sceneManager,
|
||||
Updater = updater,
|
||||
ObjectProvider = objectProvider,
|
||||
});
|
||||
}
|
||||
|
||||
private static bool IsMPPMEnabled => FusionMppm.Status != FusionMppmStatus.Disabled;
|
||||
|
||||
/// <summary>
|
||||
/// Only show the GUI if the StartMode is set to UserInterface and not being run in a Virtual Instance (MPPM).
|
||||
/// </summary>
|
||||
public bool ShouldShowGUI => StartMode == StartModes.UserInterface &&
|
||||
!(AutoConnectVirtualInstances && FusionMppm.Status == FusionMppmStatus.VirtualInstance);
|
||||
}
|
||||
}
|
||||
11
Assets/Photon/Fusion/Runtime/FusionBootstrap.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88230848386761045af440d808ee3efa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
359
Assets/Photon/Fusion/Runtime/FusionBootstrapDebugGUI.cs
Normal file
@@ -0,0 +1,359 @@
|
||||
namespace Fusion {
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Companion component for <see cref="FusionBootstrap"/>. Automatically added as needed for rendering in-game networking IMGUI.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(FusionBootstrap))]
|
||||
[AddComponentMenu("Fusion/Fusion Boostrap Debug GUI")]
|
||||
[ScriptHelp(BackColor = ScriptHeaderBackColor.Steel)]
|
||||
public class FusionBootstrapDebugGUI : Fusion.Behaviour {
|
||||
|
||||
/// <summary>
|
||||
/// When enabled, the in-game user interface buttons can be activated with the keys H (Host), S (Server) and C (Client).
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public bool EnableHotkeys;
|
||||
|
||||
/// <summary>
|
||||
/// The GUISkin to use as the base for the scalable in-game UI.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public GUISkin BaseSkin;
|
||||
|
||||
FusionBootstrap _networkDebugStart;
|
||||
string _clientCount;
|
||||
bool _isMultiplePeerMode;
|
||||
|
||||
Dictionary<FusionBootstrap.Stage, string> _nicifiedStageNames;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
protected virtual void Reset() {
|
||||
_networkDebugStart = EnsureNetworkDebugStartExists();
|
||||
_clientCount = _networkDebugStart.AutoClients.ToString();
|
||||
BaseSkin = GetAsset<GUISkin>("e59b35dfeb4b6f54e9b2791b2a40a510");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
protected virtual void OnValidate() {
|
||||
ValidateClientCount();
|
||||
}
|
||||
|
||||
protected void ValidateClientCount() {
|
||||
if (_clientCount == null) {
|
||||
_clientCount = "1";
|
||||
} else {
|
||||
_clientCount = System.Text.RegularExpressions.Regex.Replace(_clientCount, "[^0-9]", "");
|
||||
}
|
||||
}
|
||||
protected int GetClientCount() {
|
||||
try {
|
||||
return Convert.ToInt32(_clientCount);
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Awake() {
|
||||
|
||||
_nicifiedStageNames = ConvertEnumToNicifiedNameLookup<FusionBootstrap.Stage>("Fusion Status: ");
|
||||
_networkDebugStart = EnsureNetworkDebugStartExists();
|
||||
_clientCount = _networkDebugStart.AutoClients.ToString();
|
||||
ValidateClientCount();
|
||||
}
|
||||
protected virtual void Start() {
|
||||
_isMultiplePeerMode = NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple;
|
||||
}
|
||||
|
||||
protected FusionBootstrap EnsureNetworkDebugStartExists() {
|
||||
if (_networkDebugStart) {
|
||||
if (_networkDebugStart.gameObject == gameObject)
|
||||
return _networkDebugStart;
|
||||
}
|
||||
|
||||
if (TryGetBehaviour<FusionBootstrap>(out var found)) {
|
||||
_networkDebugStart = found;
|
||||
return found;
|
||||
}
|
||||
|
||||
_networkDebugStart = AddBehaviour<FusionBootstrap>();
|
||||
return _networkDebugStart;
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
|
||||
var nds = EnsureNetworkDebugStartExists();
|
||||
if (!nds.ShouldShowGUI) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentstage = nds.CurrentStage;
|
||||
if (currentstage != FusionBootstrap.Stage.Disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EnableHotkeys) {
|
||||
if (Input.GetKeyDown(KeyCode.I)) {
|
||||
_networkDebugStart.StartSinglePlayer();
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.H)) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartHostWithClients(_networkDebugStart);
|
||||
} else {
|
||||
_networkDebugStart.StartHost();
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.S)) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartServerWithClients(_networkDebugStart);
|
||||
} else {
|
||||
_networkDebugStart.StartServer();
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.C)) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartMultipleClients(nds);
|
||||
} else {
|
||||
nds.StartClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.A)) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartMultipleAutoClients(nds);
|
||||
} else {
|
||||
nds.StartAutoClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.P)) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartMultipleSharedClients(nds);
|
||||
} else {
|
||||
nds.StartSharedClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGUI() {
|
||||
|
||||
var nds = EnsureNetworkDebugStartExists();
|
||||
if (!nds.ShouldShowGUI) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentstage = nds.CurrentStage;
|
||||
if (nds.AutoHideGUI && currentstage == FusionBootstrap.Stage.AllConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
var holdskin = GUI.skin;
|
||||
|
||||
GUI.skin = FusionScalableIMGUI.GetScaledSkin(BaseSkin, out var height, out var width, out var padding, out var margin, out var leftBoxMargin);
|
||||
|
||||
GUILayout.BeginArea(new Rect(leftBoxMargin, margin, width, Screen.height));
|
||||
{
|
||||
GUILayout.BeginVertical(GUI.skin.window);
|
||||
{
|
||||
GUILayout.BeginHorizontal(GUILayout.Height(height));
|
||||
{
|
||||
var stagename = _nicifiedStageNames.TryGetValue(nds.CurrentStage, out var stage) ? stage : "Unrecognized Stage";
|
||||
GUILayout.Label(stagename, new GUIStyle(GUI.skin.label) { fontSize = (int)(GUI.skin.label.fontSize * .8f), alignment = TextAnchor.UpperLeft });
|
||||
|
||||
// Add button to hide Shutdown option after all connect, which just enables AutoHide - so that interface will reappear after a disconnect.
|
||||
if (nds.AutoHideGUI == false && nds.CurrentStage == FusionBootstrap.Stage.AllConnected) {
|
||||
if (GUILayout.Button("X", GUILayout.ExpandHeight(true), GUILayout.Width(height))) {
|
||||
nds.AutoHideGUI = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.BeginVertical(GUI.skin.window);
|
||||
{
|
||||
|
||||
if (currentstage == FusionBootstrap.Stage.Disconnected) {
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Label("Room:", GUILayout.Height(height), GUILayout.Width(width * .33f));
|
||||
nds.DefaultRoomName = GUILayout.TextField(nds.DefaultRoomName, 25, GUILayout.Height(height));
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button(EnableHotkeys ? "Start Single Player (I)" : "Start Single Player", GUILayout.Height(height))) {
|
||||
nds.StartSinglePlayer();
|
||||
}
|
||||
|
||||
if (GUILayout.Button(EnableHotkeys ? "Start Shared Client (P)" : "Start Shared Client", GUILayout.Height(height))) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartMultipleSharedClients(nds);
|
||||
} else {
|
||||
nds.StartSharedClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button(EnableHotkeys ? "Start Server (S)" : "Start Server", GUILayout.Height(height))) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartServerWithClients(nds);
|
||||
|
||||
} else {
|
||||
nds.StartServer();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button(EnableHotkeys ? "Start Host (H)" : "Start Host", GUILayout.Height(height))) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartHostWithClients(nds);
|
||||
} else {
|
||||
nds.StartHost();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button(EnableHotkeys ? "Start Client (C)" : "Start Client", GUILayout.Height(height))) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartMultipleClients(nds);
|
||||
} else {
|
||||
nds.StartClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button(EnableHotkeys ? "Start Auto Host Or Client (A)" : "Start Auto Host Or Client", GUILayout.Height(height))) {
|
||||
if (_isMultiplePeerMode) {
|
||||
StartMultipleAutoClients(nds);
|
||||
} else {
|
||||
nds.StartAutoClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (_isMultiplePeerMode) {
|
||||
|
||||
GUILayout.BeginHorizontal(/*GUI.skin.button*/);
|
||||
{
|
||||
GUILayout.Label("Client Count:", GUILayout.Height(height));
|
||||
GUILayout.Label("", GUILayout.Width(4));
|
||||
string newcount = GUILayout.TextField(_clientCount, 10, GUILayout.Width(width * .25f), GUILayout.Height(height));
|
||||
if (_clientCount != newcount) {
|
||||
// Remove everything but numbers from our client count string.
|
||||
_clientCount = newcount;
|
||||
ValidateClientCount();
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (GUILayout.Button("Shutdown", GUILayout.Height(height))) {
|
||||
_networkDebugStart.ShutdownAll();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
GUILayout.EndArea();
|
||||
|
||||
GUI.skin = holdskin;
|
||||
}
|
||||
|
||||
private void StartHostWithClients(FusionBootstrap nds) {
|
||||
int count;
|
||||
try {
|
||||
count = Convert.ToInt32(_clientCount);
|
||||
} catch {
|
||||
count = 0;
|
||||
}
|
||||
nds.StartHostPlusClients(count);
|
||||
}
|
||||
|
||||
private void StartServerWithClients(FusionBootstrap nds) {
|
||||
int count;
|
||||
try {
|
||||
count = Convert.ToInt32(_clientCount);
|
||||
} catch {
|
||||
count = 0;
|
||||
}
|
||||
nds.StartServerPlusClients(count);
|
||||
}
|
||||
|
||||
private void StartMultipleClients(FusionBootstrap nds) {
|
||||
int count;
|
||||
try {
|
||||
count = Convert.ToInt32(_clientCount);
|
||||
} catch {
|
||||
count = 0;
|
||||
}
|
||||
nds.StartMultipleClients(count);
|
||||
}
|
||||
|
||||
private void StartMultipleAutoClients(FusionBootstrap nds) {
|
||||
int.TryParse(_clientCount, out int count);
|
||||
nds.StartMultipleAutoClients(count);
|
||||
}
|
||||
|
||||
private void StartMultipleSharedClients(FusionBootstrap nds) {
|
||||
int count;
|
||||
try {
|
||||
count = Convert.ToInt32(_clientCount);
|
||||
} catch {
|
||||
count = 0;
|
||||
}
|
||||
nds.StartMultipleSharedClients(count);
|
||||
}
|
||||
|
||||
// TODO Move to a utility
|
||||
public static Dictionary<T, string> ConvertEnumToNicifiedNameLookup<T>(string prefix = null, Dictionary<T, string> nonalloc = null) where T : System.Enum {
|
||||
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
|
||||
if (nonalloc == null) {
|
||||
nonalloc = new Dictionary<T, string>();
|
||||
} else {
|
||||
nonalloc.Clear();
|
||||
}
|
||||
|
||||
var names = Enum.GetNames(typeof(T));
|
||||
var values = Enum.GetValues(typeof(T));
|
||||
for (int i = 0, cnt = names.Length; i < cnt; ++i) {
|
||||
sb.Clear();
|
||||
if (prefix != null) {
|
||||
sb.Append(prefix);
|
||||
}
|
||||
var name = names[i];
|
||||
for (int n = 0; n < name.Length; n++) {
|
||||
// If this character is a capital and it is not the first character add a space.
|
||||
// This is because we don't want a space before the word has even begun.
|
||||
if (char.IsUpper(name[n]) == true && n != 0) {
|
||||
sb.Append(" ");
|
||||
}
|
||||
|
||||
// Add the character to our new string
|
||||
sb.Append(name[n]);
|
||||
}
|
||||
nonalloc.Add((T)values.GetValue(i), sb.ToString());
|
||||
}
|
||||
return nonalloc;
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
|
||||
public static T GetAsset<T>(string Guid) where T : UnityEngine.Object {
|
||||
var path = UnityEditor.AssetDatabase.GUIDToAssetPath(Guid);
|
||||
if (string.IsNullOrEmpty(path)) {
|
||||
return null;
|
||||
} else {
|
||||
return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
12
Assets/Photon/Fusion/Runtime/FusionBootstrapDebugGUI.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ba5764f4714bd64ab9efab127938e77
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- BaseSkin: {fileID: 11400000, guid: e59b35dfeb4b6f54e9b2791b2a40a510, type: 2}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1560
Assets/Photon/Fusion/Runtime/FusionBootstrapDebugGUISkin.guiskin
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e59b35dfeb4b6f54e9b2791b2a40a510
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 732 B |
@@ -0,0 +1,122 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7d0c96f4d96542cd9a593afbcf2c535
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
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
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
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: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 764 B |
@@ -0,0 +1,122 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c90b937da87ec4183bab56bc75798697
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
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
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 746 B |
@@ -0,0 +1,122 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0bf88ab770bd548f2a1c9eecd1c8be06
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
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
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 731 B |
@@ -0,0 +1,122 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7a6709449d68482c8c03bb546ddcaec
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
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
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
156
Assets/Photon/Fusion/Runtime/NetworkCharacterController.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
namespace Fusion {
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
[NetworkStructWeaved(WORDS + 4)]
|
||||
public unsafe struct NetworkCCData : INetworkStruct {
|
||||
public const int WORDS = NetworkTRSPData.WORDS + 4;
|
||||
public const int SIZE = WORDS * 4;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public NetworkTRSPData TRSPData;
|
||||
|
||||
[FieldOffset((NetworkTRSPData.WORDS + 0) * Allocator.REPLICATE_WORD_SIZE)]
|
||||
int _grounded;
|
||||
|
||||
[FieldOffset((NetworkTRSPData.WORDS + 1) * Allocator.REPLICATE_WORD_SIZE)]
|
||||
Vector3Compressed _velocityData;
|
||||
|
||||
public bool Grounded {
|
||||
get => _grounded == 1;
|
||||
set => _grounded = (value ? 1 : 0);
|
||||
}
|
||||
|
||||
public Vector3 Velocity {
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _velocityData;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => _velocityData = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(CharacterController))]
|
||||
[NetworkBehaviourWeaved(NetworkCCData.WORDS)]
|
||||
// ReSharper disable once CheckNamespace
|
||||
public sealed unsafe class NetworkCharacterController : NetworkTRSP, INetworkTRSPTeleport, IBeforeAllTicks, IAfterAllTicks, IBeforeCopyPreviousState {
|
||||
new ref NetworkCCData Data => ref ReinterpretState<NetworkCCData>();
|
||||
|
||||
[Header("Character Controller Settings")]
|
||||
public float gravity = -20.0f;
|
||||
public float jumpImpulse = 8.0f;
|
||||
public float acceleration = 10.0f;
|
||||
public float braking = 10.0f;
|
||||
public float maxSpeed = 2.0f;
|
||||
public float rotationSpeed = 15.0f;
|
||||
|
||||
Tick _initial;
|
||||
CharacterController _controller;
|
||||
|
||||
public Vector3 Velocity {
|
||||
get => Data.Velocity;
|
||||
set => Data.Velocity = value;
|
||||
}
|
||||
|
||||
public bool Grounded {
|
||||
get => Data.Grounded;
|
||||
set => Data.Grounded = value;
|
||||
}
|
||||
|
||||
public void Teleport(Vector3? position = null, Quaternion? rotation = null) {
|
||||
_controller.enabled = false;
|
||||
NetworkTRSP.Teleport(this, transform, position, rotation);
|
||||
_controller.enabled = true;
|
||||
}
|
||||
|
||||
|
||||
public void Jump(bool ignoreGrounded = false, float? overrideImpulse = null) {
|
||||
if (Data.Grounded || ignoreGrounded) {
|
||||
var newVel = Data.Velocity;
|
||||
newVel.y += overrideImpulse ?? jumpImpulse;
|
||||
Data.Velocity = newVel;
|
||||
}
|
||||
}
|
||||
|
||||
public void Move(Vector3 direction) {
|
||||
var deltaTime = Runner.DeltaTime;
|
||||
var previousPos = transform.position;
|
||||
var moveVelocity = Data.Velocity;
|
||||
|
||||
direction = direction.normalized;
|
||||
|
||||
if (Data.Grounded && moveVelocity.y < 0) {
|
||||
moveVelocity.y = 0f;
|
||||
}
|
||||
|
||||
moveVelocity.y += gravity * Runner.DeltaTime;
|
||||
|
||||
var horizontalVel = default(Vector3);
|
||||
horizontalVel.x = moveVelocity.x;
|
||||
horizontalVel.z = moveVelocity.z;
|
||||
|
||||
if (direction == default) {
|
||||
horizontalVel = Vector3.Lerp(horizontalVel, default, braking * deltaTime);
|
||||
} else {
|
||||
horizontalVel = Vector3.ClampMagnitude(horizontalVel + direction * acceleration * deltaTime, maxSpeed);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Runner.DeltaTime);
|
||||
}
|
||||
|
||||
moveVelocity.x = horizontalVel.x;
|
||||
moveVelocity.z = horizontalVel.z;
|
||||
|
||||
_controller.Move(moveVelocity * deltaTime);
|
||||
|
||||
Data.Velocity = (transform.position - previousPos) * Runner.TickRate;
|
||||
Data.Grounded = _controller.isGrounded;
|
||||
}
|
||||
|
||||
public override void Spawned() {
|
||||
_initial = default;
|
||||
TryGetComponent(out _controller);
|
||||
// Without disabling and re-enabling the CharacterController here, the first Move call will reset the position to 0,0,0 instead of
|
||||
// keeping the position it was spawned at. Presumably disabling it clears some kind of internally cached "previous position" value
|
||||
_controller.enabled = false;
|
||||
_controller.enabled = true;
|
||||
CopyToBuffer();
|
||||
}
|
||||
|
||||
public override void Render() {
|
||||
NetworkTRSP.Render(this, transform, false, false, false, ref _initial);
|
||||
}
|
||||
|
||||
void IBeforeAllTicks.BeforeAllTicks(bool resimulation, int tickCount) {
|
||||
CopyToEngine();
|
||||
}
|
||||
|
||||
void IAfterAllTicks.AfterAllTicks(bool resimulation, int tickCount) {
|
||||
CopyToBuffer();
|
||||
}
|
||||
|
||||
void IBeforeCopyPreviousState.BeforeCopyPreviousState() {
|
||||
CopyToBuffer();
|
||||
}
|
||||
|
||||
void Awake() {
|
||||
TryGetComponent(out _controller);
|
||||
}
|
||||
|
||||
void CopyToBuffer() {
|
||||
Data.TRSPData.Position = transform.position;
|
||||
Data.TRSPData.Rotation = transform.rotation;
|
||||
}
|
||||
|
||||
void CopyToEngine() {
|
||||
// CC must be disabled before resetting the transform state
|
||||
_controller.enabled = false;
|
||||
|
||||
// set position and rotation
|
||||
transform.SetPositionAndRotation(Data.TRSPData.Position, Data.TRSPData.Rotation);
|
||||
|
||||
// Re-enable CC
|
||||
_controller.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 378411a89480da345945c2f888327a2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
97
Assets/Photon/Fusion/Runtime/NetworkObjectProviderDefault.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
namespace Fusion {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
public class NetworkObjectProviderDefault : Fusion.Behaviour, INetworkObjectProvider {
|
||||
/// <summary>
|
||||
/// If enabled, the provider will delay acquiring a prefab instance if the scene manager is busy.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public bool DelayIfSceneManagerIsBusy = true;
|
||||
|
||||
public virtual NetworkObjectAcquireResult AcquirePrefabInstance(NetworkRunner runner, in NetworkPrefabAcquireContext context, out NetworkObject instance) {
|
||||
|
||||
instance = null;
|
||||
|
||||
if (DelayIfSceneManagerIsBusy && runner.SceneManager.IsBusy) {
|
||||
return NetworkObjectAcquireResult.Retry;
|
||||
}
|
||||
|
||||
NetworkObject prefab;
|
||||
try {
|
||||
prefab = runner.Prefabs.Load(context.PrefabId, isSynchronous: context.IsSynchronous);
|
||||
} catch (Exception ex) {
|
||||
Log.Error($"Failed to load prefab: {ex}");
|
||||
return NetworkObjectAcquireResult.Failed;
|
||||
}
|
||||
|
||||
if (!prefab) {
|
||||
// this is ok, as long as Fusion does not require the prefab to be loaded immediately;
|
||||
// if an instance for this prefab is still needed, this method will be called again next update
|
||||
return NetworkObjectAcquireResult.Retry;
|
||||
}
|
||||
|
||||
instance = InstantiatePrefab(runner, prefab);
|
||||
Assert.Check(instance);
|
||||
|
||||
if (context.DontDestroyOnLoad) {
|
||||
runner.MakeDontDestroyOnLoad(instance.gameObject);
|
||||
} else {
|
||||
runner.MoveToRunnerScene(instance.gameObject);
|
||||
}
|
||||
|
||||
runner.Prefabs.AddInstance(context.PrefabId);
|
||||
return NetworkObjectAcquireResult.Success;
|
||||
}
|
||||
|
||||
public virtual void ReleaseInstance(NetworkRunner runner, in NetworkObjectReleaseContext context) {
|
||||
var instance = context.Object;
|
||||
|
||||
if (!context.IsBeingDestroyed) {
|
||||
if (context.TypeId.IsPrefab) {
|
||||
DestroyPrefabInstance(runner, context.TypeId.AsPrefabId, instance);
|
||||
} else if (context.TypeId.IsSceneObject) {
|
||||
DestroySceneObject(runner, context.TypeId.AsSceneObjectId, instance);
|
||||
} else if (context.IsNestedObject) {
|
||||
DestroyPrefabNestedObject(runner, instance);
|
||||
} else {
|
||||
throw new NotImplementedException($"Unknown type id {context.TypeId}");
|
||||
}
|
||||
}
|
||||
|
||||
if (context.TypeId.IsPrefab) {
|
||||
runner.Prefabs.RemoveInstance(context.TypeId.AsPrefabId);
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkPrefabId GetPrefabId(NetworkRunner runner, NetworkObjectGuid prefabGuid) {
|
||||
return runner.Prefabs.GetId(prefabGuid);
|
||||
}
|
||||
|
||||
protected virtual NetworkObject InstantiatePrefab(NetworkRunner runner, NetworkObject prefab) {
|
||||
return Instantiate(prefab);
|
||||
}
|
||||
|
||||
protected virtual void DestroyPrefabInstance(NetworkRunner runner, NetworkPrefabId prefabId, NetworkObject instance) {
|
||||
Destroy(instance.gameObject);
|
||||
}
|
||||
|
||||
protected virtual void DestroyPrefabNestedObject(NetworkRunner runner, NetworkObject instance) {
|
||||
Destroy(instance.gameObject);
|
||||
}
|
||||
|
||||
protected virtual void DestroySceneObject(NetworkRunner runner, NetworkSceneObjectId sceneObjectId, NetworkObject instance) {
|
||||
Destroy(instance.gameObject);
|
||||
}
|
||||
|
||||
void INetworkObjectProvider.Shutdown(NetworkRunner runner) {
|
||||
var prefabs = runner.Prefabs;
|
||||
if (prefabs?.Options.UnloadUnusedPrefabsOnShutdown == true) {
|
||||
prefabs.UnloadUnreferenced(includeIncompleteLoads: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10533623ed629624c8acc6869f609bf2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
846
Assets/Photon/Fusion/Runtime/NetworkSceneManagerDefault.cs
Normal file
@@ -0,0 +1,846 @@
|
||||
namespace Fusion {
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
#endif
|
||||
|
||||
public class NetworkSceneManagerDefault : Fusion.Behaviour, INetworkSceneManager {
|
||||
/// <summary>
|
||||
/// If enabled and there is an already loaded scene that matches what the scene manager has intended to load,
|
||||
/// that scene will be used instead and load will be avoided.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[ToggleLeft]
|
||||
public bool IsSceneTakeOverEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// Should all scene load errors be logged into the console? If disabled, errors can still be retrieved via the
|
||||
/// <see cref="NetworkSceneAsyncOp.Error"/> or <see cref="NetworkSceneAsyncOp.AddOnCompleted"/>.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[ToggleLeft]
|
||||
public bool LogSceneLoadErrors = true;
|
||||
|
||||
/// <summary>
|
||||
/// If enabled the scenemanager despawns all runtime spawned prefab instances (not scene objects) before unloading a scene.
|
||||
/// If the peer does not have StateAuthority over the object it is destroyed instead of despawned.
|
||||
/// If disabled the destroy will be indirectly done via the scene unload from Unity however it will be async and might be delayed,
|
||||
/// this can lead to the scene change being synchronized in an earlier tick than the destroys.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[ToggleLeft]
|
||||
public bool DestroySpawnedPrefabsOnSceneUnload = true;
|
||||
|
||||
/// <summary>
|
||||
/// All the scenes loaded by all the managers. Used when <see cref="IsSceneTakeOverEnabled"/> is enabled.
|
||||
/// </summary>
|
||||
private static Dictionary<Scene, NetworkSceneManagerDefault> _allOwnedScenes = new Dictionary<Scene, NetworkSceneManagerDefault>(new FusionUnitySceneManagerUtils.SceneEqualityComparer());
|
||||
|
||||
/// <summary>
|
||||
/// In multiple peer mode, each runner maintains its own scene where all the newly loaded scenes
|
||||
/// are moved to. This is to make sure physics are properly sandboxed.
|
||||
/// </summary>
|
||||
private List<MultiPeerSceneRoot> _multiPeerSceneRoots = new List<MultiPeerSceneRoot>();
|
||||
private MultiPeerSceneRoot _multiPeerActiveRoot;
|
||||
|
||||
/// <summary>
|
||||
/// List of running coroutines. Only one is actually executed at a time.
|
||||
/// </summary>
|
||||
private List<ICoroutine> _runningCoroutines = new List<ICoroutine>();
|
||||
|
||||
/// <summary>
|
||||
/// For remote clients, this manager first unloads old scenes then loads the new ones. It might happen that all
|
||||
/// the current scenes need to be unloaded and in such case a temp scene needs to be created to ensure at least one
|
||||
/// scene loaded at all times.
|
||||
/// </summary>
|
||||
private Scene _tempUnloadScene;
|
||||
|
||||
/// <summary>
|
||||
/// Scene used when Multiple Peer mode is used. Each loaded scene is merged into this one, allowing
|
||||
/// for multiple runners to have separate cross-scene physics.
|
||||
/// </summary>
|
||||
public Scene MultiPeerScene { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Root for DontDestroyOnLoad objects. Instantiated on <see cref="MultiPeerScene"/>.
|
||||
/// </summary>
|
||||
public Transform MultiPeerDontDestroyOnLoadRoot { get; private set; }
|
||||
|
||||
public NetworkRunner Runner { get; private set; }
|
||||
|
||||
private bool IsMultiplePeer => Runner.Config.PeerMode == NetworkProjectConfig.PeerModes.Multiple;
|
||||
private bool _isLoading;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
static void ClearStatics() {
|
||||
_allOwnedScenes.Clear();
|
||||
}
|
||||
|
||||
static NetworkSceneManagerDefault() {
|
||||
SceneManager.sceneUnloaded += (s) => _allOwnedScenes.Remove(s);
|
||||
}
|
||||
|
||||
#region INetworkSceneManager
|
||||
|
||||
public virtual void Initialize(NetworkRunner runner) {
|
||||
Log.TraceSceneManager(runner, $"Initialize with {runner}");
|
||||
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
LoadAddressableScenePathsAsync();
|
||||
#endif
|
||||
|
||||
Debug.Assert(Runner == null);
|
||||
Runner = runner;
|
||||
|
||||
// assign an empty scene with a separate physics stage immediately, so that they won't spawn anything on the currently active scene
|
||||
// an lose track of it
|
||||
if (IsMultiplePeer) {
|
||||
var scene = SceneManager.CreateScene($"{runner.name}_{runner.LocalPlayer}",
|
||||
new CreateSceneParameters(LocalPhysicsMode.Physics2D | LocalPhysicsMode.Physics3D));
|
||||
Log.TraceSceneManager(Runner, $"Assigned an initial scene: {scene.Dump()}");
|
||||
|
||||
MultiPeerScene = scene;
|
||||
MultiPeerDontDestroyOnLoadRoot = new GameObject("[DontDestroyOnLoad]").transform;
|
||||
SceneManager.MoveGameObjectToScene(MultiPeerDontDestroyOnLoadRoot.gameObject, MultiPeerScene);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Shutdown() {
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Shutdown with {Runner}");
|
||||
|
||||
Runner = null;
|
||||
|
||||
// clear owned scenes in case this manager is reused
|
||||
var ownedScenes = _allOwnedScenes
|
||||
.Where(x => x.Value == this)
|
||||
.Select(x => x.Key)
|
||||
.ToList();
|
||||
|
||||
foreach (var ownedScene in ownedScenes) {
|
||||
_allOwnedScenes.Remove(ownedScene);
|
||||
}
|
||||
|
||||
_multiPeerSceneRoots.Clear();
|
||||
_multiPeerActiveRoot = null;
|
||||
|
||||
MultiPeerDontDestroyOnLoadRoot = null;
|
||||
|
||||
var sceneToUnload = MultiPeerScene;
|
||||
MultiPeerScene = default;
|
||||
|
||||
if (sceneToUnload.isLoaded) {
|
||||
if (!sceneToUnload.CanBeUnloaded()) {
|
||||
SceneManager.CreateScene($"FusionSceneManager_TempEmptyScene");
|
||||
}
|
||||
SceneManager.UnloadSceneAsync(sceneToUnload);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsBusy {
|
||||
get {
|
||||
if (_isLoading) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsMultiplePeer && _multiPeerSceneRoots.Count == 0) {
|
||||
// nothing to spawn on
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Scene MainRunnerScene {
|
||||
get {
|
||||
if (IsMultiplePeer) {
|
||||
return MultiPeerScene;
|
||||
} else {
|
||||
return SceneManager.GetActiveScene();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsRunnerScene(Scene scene) {
|
||||
if (IsMultiplePeer) {
|
||||
return scene == MultiPeerScene;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool TryGetPhysicsScene2D(out PhysicsScene2D scene2D) {
|
||||
var mainScene = MainRunnerScene;
|
||||
if (mainScene.IsValid()) {
|
||||
scene2D = mainScene.GetPhysicsScene2D();
|
||||
return true;
|
||||
} else {
|
||||
scene2D = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool TryGetPhysicsScene3D(out PhysicsScene scene3D) {
|
||||
var mainScene = MainRunnerScene;
|
||||
if (mainScene.IsValid()) {
|
||||
scene3D = mainScene.GetPhysicsScene();
|
||||
return true;
|
||||
} else {
|
||||
scene3D = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void MakeDontDestroyOnLoad(GameObject obj) {
|
||||
if (IsMultiplePeer) {
|
||||
Debug.Assert(obj.transform.parent == null || obj.transform.parent == MultiPeerDontDestroyOnLoadRoot);
|
||||
obj.transform.SetParent(MultiPeerDontDestroyOnLoadRoot, true);
|
||||
} else {
|
||||
DontDestroyOnLoad(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveGameObjectToScene(GameObject gameObject, SceneRef sceneRef) {
|
||||
if (IsMultiplePeer) {
|
||||
// find the first matching scene ref
|
||||
foreach (var root in _multiPeerSceneRoots) {
|
||||
if (sceneRef != default && root.SceneRef != sceneRef) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sceneRef == default) {
|
||||
// if scene ref is not specified, use the active root, if it exists
|
||||
if (_multiPeerActiveRoot && root != _multiPeerActiveRoot) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameObject.scene != MultiPeerScene) {
|
||||
gameObject.transform.SetParent(null, true);
|
||||
SceneManager.MoveGameObjectToScene(gameObject, MultiPeerScene);
|
||||
|
||||
if (Application.isBatchMode == false)
|
||||
Runner.AddVisibilityNodes(gameObject);
|
||||
}
|
||||
|
||||
gameObject.transform.SetParent(root.transform, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
if (sceneRef == default) {
|
||||
// do nothing, all scenes belong to the runner
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SceneManager.sceneCount; ++i) {
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
if (scene.isLoaded && GetSceneRef(scene.path) == sceneRef) {
|
||||
SceneManager.MoveGameObjectToScene(gameObject, scene);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual NetworkSceneAsyncOp LoadScene(SceneRef sceneRef, NetworkLoadSceneParameters parameters) {
|
||||
Log.TraceSceneManager(Runner, $"Load scene {sceneRef} called with parameters: {parameters}");
|
||||
return NetworkSceneAsyncOp.FromCoroutine(sceneRef, StartTracedCoroutine(LoadSceneCoroutine(sceneRef, parameters)));
|
||||
}
|
||||
|
||||
public virtual NetworkSceneAsyncOp UnloadScene(SceneRef sceneRef) {
|
||||
Log.TraceSceneManager(Runner, $"Unload scene {sceneRef} called");
|
||||
return NetworkSceneAsyncOp.FromCoroutine(sceneRef, StartTracedCoroutine(UnloadSceneCoroutine(sceneRef)));
|
||||
}
|
||||
|
||||
public virtual SceneRef GetSceneRef(string sceneNameOrPath) {
|
||||
int buildIndex = FusionUnitySceneManagerUtils.GetSceneBuildIndex(sceneNameOrPath);
|
||||
if (buildIndex >= 0) {
|
||||
return SceneRef.FromIndex(buildIndex);
|
||||
}
|
||||
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
// this may be a blocking call due to WaitForCompletion being used internally
|
||||
if (!TryGetAddressableScenes(out var addressableScenes)) {
|
||||
Log.Error(this, $"Failed to resolve addressable scene paths, won't be able to resolve {sceneNameOrPath} or any other addressable scene.");
|
||||
addressableScenes = Array.Empty<string>();
|
||||
}
|
||||
|
||||
var index = FusionUnitySceneManagerUtils.GetSceneIndex(addressableScenes, sceneNameOrPath);
|
||||
if (index >= 0) {
|
||||
return SceneRef.FromPath(addressableScenes[index]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SceneRef.None;
|
||||
}
|
||||
|
||||
public SceneRef GetSceneRef(GameObject gameObject) {
|
||||
if (IsMultiplePeer) {
|
||||
if (gameObject.scene != MultiPeerScene) {
|
||||
// not a part of this scene
|
||||
return default;
|
||||
}
|
||||
|
||||
// find among scene roots
|
||||
var sceneRoot = gameObject.transform.root;
|
||||
foreach (var root in _multiPeerSceneRoots) {
|
||||
if (root.transform == sceneRoot) {
|
||||
return root.SceneRef;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
} else {
|
||||
var scene = gameObject.scene;
|
||||
return GetSceneRef(scene.path);
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnSceneInfoChanged(NetworkSceneInfo sceneInfo, NetworkSceneInfoChangeSource changeSource) {
|
||||
// implement this method and return true if you want to handle scene info changes manually
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected virtual IEnumerator LoadSceneCoroutine(SceneRef sceneRef, NetworkLoadSceneParameters sceneParams) {
|
||||
Runner.InvokeSceneLoadStart(sceneRef);
|
||||
|
||||
Scene scene = default;
|
||||
|
||||
using (MakeLoadingScope()) {
|
||||
Log.TraceSceneManager(Runner, $"LoadSceneCoroutine called with {sceneRef}, {sceneParams}");
|
||||
var localPhysicsMode = sceneParams.LocalPhysicsMode;
|
||||
var loadSceneMode = sceneParams.LoadSceneMode;
|
||||
|
||||
if (IsMultiplePeer) {
|
||||
if (localPhysicsMode != LocalPhysicsMode.None) {
|
||||
throw new ArgumentException($"Local physics mode is not supported in multiple peer mode",
|
||||
nameof(sceneParams));
|
||||
}
|
||||
|
||||
if (loadSceneMode == LoadSceneMode.Single) {
|
||||
// all the current scenes need to be "unloaded", except possibly for the one
|
||||
// that matches the sceneRef, if scene take over is enabled
|
||||
loadSceneMode = LoadSceneMode.Additive;
|
||||
|
||||
try {
|
||||
foreach (var root in _multiPeerSceneRoots) {
|
||||
Log.TraceSceneManager(Runner, $"Destroying scene {sceneRef} root {root.name} due to single-mode load");
|
||||
Destroy(root.gameObject);
|
||||
}
|
||||
|
||||
// wait for each root to be destroyed
|
||||
foreach (var root in _multiPeerSceneRoots) {
|
||||
while (root != null) {
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_multiPeerSceneRoots.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DestroySpawnedPrefabsOnSceneUnload && loadSceneMode == LoadSceneMode.Single)
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++) {
|
||||
// find the scene to unload
|
||||
var sceneToBeUnloaded = SceneManager.GetSceneAt(i); // will be unloaded by Unity on scene load
|
||||
var sceneRefToBeUnloaded = GetSceneRef(sceneToBeUnloaded.path);
|
||||
|
||||
if (sceneRefToBeUnloaded != SceneRef.None) {
|
||||
DestroyAllRuntimeSpawnedObjectsInScene(sceneToBeUnloaded, sceneRefToBeUnloaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSceneTakeOverEnabled) {
|
||||
// check if a loaded scene can be taken over
|
||||
Scene candidate = FindSceneToTakeOver(sceneRef);
|
||||
if (candidate.IsValid()) {
|
||||
Log.TraceSceneManager(Runner, $"Taking over {sceneRef}: {candidate.Dump()}");
|
||||
|
||||
if (candidate.GetLocalPhysicsMode() != localPhysicsMode) {
|
||||
throw new InvalidOperationException($"Tried to take over {candidate.Dump()} for {sceneRef}, but physics mode were different: {candidate.GetLocalPhysicsMode()} != {localPhysicsMode}");
|
||||
}
|
||||
|
||||
scene = candidate;
|
||||
MarkSceneAsOwned(sceneRef, candidate);
|
||||
|
||||
if (loadSceneMode == LoadSceneMode.Single && !IsMultiplePeer) {
|
||||
// need to unload scenes manually, multiple peer mode is handled at the beginning of this method, because
|
||||
// it always needs to the manual cleanup for single mode
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++) {
|
||||
var toUnload = SceneManager.GetSceneAt(i);
|
||||
if (toUnload != candidate) {
|
||||
Log.TraceSceneManager(Runner, $"Unloading {sceneRef} ({toUnload.Dump()}) due to single-mode take over of {candidate.Dump()}");
|
||||
yield return SceneManager.UnloadSceneAsync(toUnload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!scene.IsValid()) {
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
if (loadSceneMode == LoadSceneMode.Single) {
|
||||
// single mode unloads all the scenes anyway
|
||||
_addressableOperations.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sceneRef.IsIndex) {
|
||||
Log.TraceSceneManager(Runner, $"Loading scene {sceneRef} with build index {sceneRef.AsIndex} with mode {loadSceneMode}");
|
||||
var op = SceneManager.LoadSceneAsync(sceneRef.AsIndex,
|
||||
new LoadSceneParameters(loadSceneMode, localPhysicsMode));
|
||||
if (op == null) {
|
||||
throw new InvalidOperationException($"Scene not found: {sceneRef.AsIndex}");
|
||||
}
|
||||
|
||||
Debug.Assert(SceneManager.sceneCount > 0);
|
||||
scene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
|
||||
MarkSceneAsOwned(sceneRef, scene);
|
||||
|
||||
Debug.Assert(scene.buildIndex == sceneRef.AsIndex);
|
||||
|
||||
while (!op.isDone) {
|
||||
OnLoadSceneProgress(sceneRef, op.progress);
|
||||
yield return null;
|
||||
}
|
||||
} else {
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
if (!TryGetAddressableScenes(out var addressableScenes)) {
|
||||
Log.Error(this, $"Failed to resolve addressable scene paths, won't be able to resolve {sceneRef}");
|
||||
addressableScenes = Array.Empty<string>();
|
||||
}
|
||||
|
||||
string sceneAddress = null;
|
||||
foreach (var path in addressableScenes) {
|
||||
if (sceneRef.IsPath(path)) {
|
||||
sceneAddress = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sceneAddress == null) {
|
||||
throw new InvalidOperationException($"Unable to find addressable scene path for {sceneRef}");
|
||||
}
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Loading scene {sceneRef} from addressable: {sceneAddress}");
|
||||
|
||||
#if FUSION_ENABLE_ADDRESSABLES_LOCAL_PHYSICS
|
||||
var loadSceneParameters = new LoadSceneParameters(loadSceneMode, localPhysicsMode);
|
||||
#else
|
||||
if (localPhysicsMode != LocalPhysicsMode.None) {
|
||||
throw new InvalidOperationException($"{nameof(LocalPhysicsMode)} is not supported in this version of Addressables");
|
||||
}
|
||||
var loadSceneParameters = loadSceneMode;
|
||||
#endif
|
||||
var op = Addressables.LoadSceneAsync(sceneAddress, loadSceneParameters);
|
||||
|
||||
// to get the scene a callback is used, as it fires immediately when loading finished,
|
||||
// compared to waiting for the coroutine to resume
|
||||
scene = default;
|
||||
op.Completed += op => {
|
||||
if (op.Status == AsyncOperationStatus.Succeeded) {
|
||||
scene = op.Result.Scene;
|
||||
MarkSceneAsOwned(sceneRef, scene);
|
||||
}
|
||||
};
|
||||
|
||||
op.Destroyed += _ => {
|
||||
// this will happen in MP mode when scenes are merged or when a scene is loaded in a single mode
|
||||
if (_addressableOperations.Remove(sceneRef)) {
|
||||
Log.TraceSceneManager(Runner, $"Destroyed Addressables op for {sceneRef}");
|
||||
}
|
||||
};
|
||||
|
||||
_addressableOperations.Add(sceneRef, op);
|
||||
|
||||
while (!op.IsDone) {
|
||||
OnLoadSceneProgress(sceneRef, op.PercentComplete);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (!op.IsValid()) {
|
||||
throw new InvalidOperationException($"Loading operation for {sceneRef} has been destroyed");
|
||||
}
|
||||
|
||||
if (op.Status == AsyncOperationStatus.Failed) {
|
||||
Addressables.Release(op);
|
||||
throw new InvalidOperationException($"Failed to load scene from addressable: {sceneAddress}");
|
||||
}
|
||||
#else
|
||||
throw new InvalidOperationException($"SceneRef {sceneRef} points to an addressable scene, but FUSION_ENABLE_ADDRESSABLES is not defined");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield return StartCoroutine(OnSceneLoaded(sceneRef, scene, sceneParams));
|
||||
}
|
||||
|
||||
protected virtual IEnumerator UnloadSceneCoroutine(SceneRef sceneRef) {
|
||||
Log.TraceSceneManager(Runner, $"UnloadSceneCoroutine called for {sceneRef}");
|
||||
|
||||
using (MakeLoadingScope()) {
|
||||
if (IsMultiplePeer) {
|
||||
// in multiple peer, the unload simply destroys the scene root
|
||||
for (int i = 0; i < _multiPeerSceneRoots.Count; ++i) {
|
||||
var root = _multiPeerSceneRoots[i];
|
||||
if (root.SceneRef == sceneRef) {
|
||||
|
||||
if (root == _multiPeerActiveRoot) {
|
||||
_multiPeerActiveRoot = null;
|
||||
}
|
||||
|
||||
_multiPeerSceneRoots.RemoveAt(i);
|
||||
Log.TraceSceneManager(Runner, $"Destroying scene root {root.name} for {sceneRef}");
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Started unloading {root.Scene.ToString()} for {sceneRef}");
|
||||
Destroy(root.gameObject);
|
||||
while (root != null) {
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Finished unloading {root.Scene.ToString()} for {sceneRef}");
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException($"Did not find a scene to unload: {sceneRef}", nameof(sceneRef));
|
||||
} else {
|
||||
Scene sceneToUnload = default;
|
||||
|
||||
// find the scene to unload
|
||||
for (int i = 0; i < SceneManager.sceneCount; ++i) {
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
if (GetSceneRef(scene.path) == sceneRef) {
|
||||
sceneToUnload = scene;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sceneToUnload.IsValid()) {
|
||||
throw new ArgumentOutOfRangeException($"Did not find a scene to unload: {sceneRef}", nameof(sceneRef));
|
||||
}
|
||||
|
||||
if (DestroySpawnedPrefabsOnSceneUnload) {
|
||||
DestroyAllRuntimeSpawnedObjectsInScene(sceneToUnload, sceneRef);
|
||||
}
|
||||
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Started unloading {sceneToUnload.Dump()} for {sceneRef}");
|
||||
|
||||
if (!sceneToUnload.CanBeUnloaded()) {
|
||||
Log.Warn(Runner, $"Scene {sceneToUnload.Dump()} can't be unloaded for {sceneRef}, creating a temporary scene to unload it");
|
||||
Debug.Assert(!_tempUnloadScene.IsValid());
|
||||
_tempUnloadScene = SceneManager.CreateScene($"FusionSceneManager_TempEmptyScene");
|
||||
}
|
||||
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
if (_addressableOperations.TryGetValue(sceneRef, out var asyncOp)) {
|
||||
Log.TraceSceneManager(Runner, $"Unloading addressable scene {sceneToUnload.Dump()} for {sceneRef}");
|
||||
yield return Addressables.UnloadSceneAsync(asyncOp);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
Log.TraceSceneManager(Runner, $"Unloading {sceneToUnload.Dump()} for {sceneRef}");
|
||||
var op = SceneManager.UnloadSceneAsync(sceneToUnload);
|
||||
if (op == null) {
|
||||
throw new InvalidOperationException($"Failed to unload {sceneToUnload.Dump()}");
|
||||
}
|
||||
|
||||
yield return op;
|
||||
}
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Finished unloading {sceneToUnload.Dump()} for {sceneRef}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IEnumerator OnSceneLoaded(SceneRef sceneRef, Scene scene, NetworkLoadSceneParameters sceneParams) {
|
||||
Log.TraceSceneManager(Runner, $"Finished loading, starting processing {scene.Dump()} for {sceneRef}");
|
||||
|
||||
var sceneObjects = scene.GetComponents<NetworkObject>(includeInactive: true, out var rootObjects);
|
||||
|
||||
// since it is impossible to get objects in deterministic order (sibling index is 0 for all root objects in builds),
|
||||
// scene objects need to be sorted by something that will guarantee the order
|
||||
Array.Sort(sceneObjects, NetworkObjectSortKeyComparer.Instance);
|
||||
|
||||
if (IsMultiplePeer) {
|
||||
// create a root GO for all the gameObjects in the newly loaded scene
|
||||
var newSceneRoot = new GameObject($"[{scene.name}]").AddComponent<MultiPeerSceneRoot>();
|
||||
newSceneRoot.SceneRef = sceneRef;
|
||||
newSceneRoot.SceneHandle = scene.handle;
|
||||
newSceneRoot.Scene = scene;
|
||||
newSceneRoot.ScenePath = scene.path;
|
||||
|
||||
SceneManager.MoveGameObjectToScene(newSceneRoot.gameObject, scene);
|
||||
|
||||
foreach (var rootGameObject in rootObjects) {
|
||||
rootGameObject.transform.SetParent(newSceneRoot.transform, true);
|
||||
}
|
||||
|
||||
// store the info
|
||||
_multiPeerSceneRoots.Add(newSceneRoot);
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Merging {scene.Dump()} to {MultiPeerScene.Dump()} for {sceneRef}");
|
||||
SceneManager.MergeScenes(scene, MultiPeerScene);
|
||||
|
||||
if (sceneParams.IsActiveOnLoad) {
|
||||
_multiPeerActiveRoot = newSceneRoot;
|
||||
}
|
||||
} else {
|
||||
if (sceneParams.IsActiveOnLoad) {
|
||||
SceneManager.SetActiveScene(scene);
|
||||
}
|
||||
}
|
||||
|
||||
// register scene objects; this will deactivate GameObjects for clients
|
||||
// the additional loadId parameter is passed to ensure each scene load
|
||||
// yields unique type ids for scene objects
|
||||
Runner.RegisterSceneObjects(sceneRef, sceneObjects, loadId: sceneParams.LoadId);
|
||||
|
||||
Log.TraceSceneManager(Runner, $"Finished loading & processing {scene.Dump()} for {sceneRef}");
|
||||
Runner.InvokeSceneLoadDone(new SceneLoadDoneArgs(sceneRef, sceneObjects, scene, rootObjects));
|
||||
yield break;
|
||||
}
|
||||
|
||||
protected virtual void OnLoadSceneProgress(SceneRef sceneRef, float progress) {
|
||||
Log.TraceSceneManager(Runner, $"Loading scene progress {sceneRef} ({progress:P2})");
|
||||
}
|
||||
|
||||
private void DestroyAllRuntimeSpawnedObjectsInScene(Scene scene, SceneRef sceneRef) {
|
||||
Log.TraceSceneManager(Runner, $"destroying runtime spawned NetworkObjects in scene {scene.Dump()} for {sceneRef}");
|
||||
foreach (var networkObject in Runner.GetAllNetworkObjects()) {
|
||||
// This exists to ensure all object meta is destroyed when unloading the scene to prevent objects from getting despawned and spawned again repeadetly on scene unload.
|
||||
// Scene objects are ignored as they can't be spawned again when the scene is unloaded.
|
||||
if (networkObject.gameObject.scene == scene && networkObject.NetworkTypeId.IsSceneObject == false) {
|
||||
if (networkObject.HasStateAuthority) {
|
||||
// despawn to ensure the object is immediately added to destroy queue. (Unity destroy callback is delayed until end of Update()
|
||||
Runner.Despawn(networkObject);
|
||||
} else {
|
||||
Destroy(networkObject.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Scene FindSceneToTakeOver(SceneRef sceneRef) {
|
||||
for (int i = 0; i < SceneManager.sceneCount; ++i) {
|
||||
var candidate = SceneManager.GetSceneAt(i);
|
||||
if (!candidate.isLoaded) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GetSceneRef(candidate.path) != sceneRef) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_allOwnedScenes.ContainsKey(candidate)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private ICoroutine StartTracedCoroutine(IEnumerator inner) {
|
||||
var coro = new FusionCoroutine(inner);
|
||||
|
||||
_runningCoroutines.Add(coro);
|
||||
|
||||
coro.Completed += x => {
|
||||
|
||||
if (LogSceneLoadErrors && x.Error != null) {
|
||||
Log.Error(Runner, $"Failed async op: {x.Error.SourceException}");
|
||||
}
|
||||
|
||||
// remove this one from the list
|
||||
var index = _runningCoroutines.IndexOf((ICoroutine)x);
|
||||
Debug.Assert(index == 0, "Expected the completed coroutine to be the first in the list");
|
||||
_runningCoroutines.RemoveAt(index);
|
||||
|
||||
// start the next one
|
||||
if (index < _runningCoroutines.Count) {
|
||||
Log.TraceSceneManager(Runner, $"Starting enqueued coroutine {index} of {_runningCoroutines.Count}");
|
||||
StartCoroutine(_runningCoroutines[index]);
|
||||
}
|
||||
};
|
||||
|
||||
if (_runningCoroutines.Count == 1) {
|
||||
// start immediately
|
||||
StartCoroutine(coro);
|
||||
} else {
|
||||
Log.TraceSceneManager(Runner, $"Enqueued coroutine, there are already {_runningCoroutines.Count - 1} running");
|
||||
}
|
||||
|
||||
return coro;
|
||||
}
|
||||
|
||||
protected LoadingScope MakeLoadingScope() {
|
||||
return new LoadingScope(this);
|
||||
}
|
||||
|
||||
protected void MarkSceneAsOwned(SceneRef sceneRef, Scene scene) {
|
||||
if (_allOwnedScenes.TryGetValue(scene, out var manager)) {
|
||||
Log.Warn(Runner, $"Scene {scene.Dump()} (for {sceneRef}) already owned by {manager}");
|
||||
} else {
|
||||
_allOwnedScenes.Add(scene, this);
|
||||
}
|
||||
}
|
||||
|
||||
private NetworkSceneAsyncOp FailOp(SceneRef sceneRef, Exception exception) {
|
||||
if (LogSceneLoadErrors) {
|
||||
Log.Error(Runner, $"Failed with: {exception}");
|
||||
}
|
||||
|
||||
return NetworkSceneAsyncOp.FromError(sceneRef, exception);
|
||||
}
|
||||
|
||||
#if FUSION_ENABLE_ADDRESSABLES && !FUSION_DISABLE_ADDRESSABLES
|
||||
/// <summary>
|
||||
/// A label by which addressable scenes can be discovered.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public string AddressableScenesLabel = "FusionScenes";
|
||||
|
||||
public NetworkSceneManagerDefault() {
|
||||
_addressableScenesTask = new(() => GetAddressableScenes());
|
||||
}
|
||||
|
||||
public Task LoadAddressableScenePathsAsync() {
|
||||
return _addressableScenesTask.Value.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a task that resolves addressable scene paths. By default, this method locates all the addressable scenes with
|
||||
/// <see cref="AddressableScenesLabel"/> label. Override this method to provide a custom implementation. For example, user
|
||||
/// might want to have a pre-defined set of addressable scenes to avoid the wait:
|
||||
/// <example><code>
|
||||
/// protected override GetAddressableScenesResult GetAddressableScenes() {
|
||||
/// return Task.FromResult(new string[] {
|
||||
/// "Assets/Scenes/AddressableScene1.unity",
|
||||
/// "Assets/Scenes/AddressableScene2.unity",
|
||||
/// });
|
||||
/// }
|
||||
/// </code></example>
|
||||
/// </summary>
|
||||
/// <returns>A task representing resolve operation and optionally a delegate to be invoked before the task is going to be
|
||||
/// awaited synchronously</returns>
|
||||
protected virtual GetAddressableScenesResult GetAddressableScenes() {
|
||||
Log.TraceSceneManager(Runner, $"Locating addressable scenes with label: {AddressableScenesLabel}");
|
||||
|
||||
var tcs = new TaskCompletionSource<string[]>();
|
||||
var result = Addressables.LoadResourceLocationsAsync(AddressableScenesLabel, typeof(SceneInstance));
|
||||
|
||||
result.Completed += op => {
|
||||
try {
|
||||
if (op.Status == AsyncOperationStatus.Failed) {
|
||||
tcs.SetException(op.OperationException);
|
||||
} else {
|
||||
var paths = op.Result.Select(x => x.PrimaryKey).ToArray();
|
||||
Log.TraceSceneManager(Runner, $"Found {paths.Length} addressable scenes: {string.Join(", ", paths)}");
|
||||
tcs.SetResult(paths);
|
||||
}
|
||||
} finally {
|
||||
Addressables.Release(op);
|
||||
}
|
||||
};
|
||||
|
||||
return new GetAddressableScenesResult {
|
||||
Task = tcs.Task,
|
||||
|
||||
// awaiting tasks synchronously does not play well with addressables; simply waiting will block the main thread and that's it.
|
||||
// addressables *need* to have WaitForCompletion called
|
||||
BeforeWaitForCompletion = () => {
|
||||
if (result.IsValid()) {
|
||||
result.WaitForCompletion();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the timeout for addressable scene paths to be resolved. By default, this method returns 10 seconds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual TimeSpan GetAddressableScenePathsTimeout() {
|
||||
return TimeSpan.FromSeconds(10);
|
||||
}
|
||||
|
||||
private bool TryGetAddressableScenes(out string[] addressableScenes) {
|
||||
if (!_addressableScenesTask.IsValueCreated) {
|
||||
Log.Warn(Runner, $"Going to block the thread in wait for addressable scene paths being resolved, call and await {nameof(LoadAddressableScenePathsAsync)} to avoid this.");
|
||||
}
|
||||
|
||||
var t = _addressableScenesTask.Value;
|
||||
if (!t.Task.IsCompleted) {
|
||||
t.BeforeWaitForCompletion?.Invoke();
|
||||
|
||||
if (!t.Task.Wait(GetAddressableScenePathsTimeout())) {
|
||||
addressableScenes = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
addressableScenes = t.Task.Result;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected struct GetAddressableScenesResult {
|
||||
public Task<string[]> Task;
|
||||
public Action BeforeWaitForCompletion;
|
||||
public static implicit operator GetAddressableScenesResult(Task<string[]> task) {
|
||||
return new GetAddressableScenesResult {
|
||||
Task = task,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private Lazy<GetAddressableScenesResult> _addressableScenesTask;
|
||||
private Dictionary<SceneRef, AsyncOperationHandle<SceneInstance>> _addressableOperations = new();
|
||||
#endif
|
||||
|
||||
protected sealed class MultiPeerSceneRoot : MonoBehaviour {
|
||||
public SceneRef SceneRef;
|
||||
public string ScenePath;
|
||||
public int SceneHandle;
|
||||
public Scene Scene;
|
||||
}
|
||||
|
||||
protected struct LoadingScope : IDisposable {
|
||||
private readonly NetworkSceneManagerDefault _manager;
|
||||
|
||||
public LoadingScope(NetworkSceneManagerDefault manager) {
|
||||
_manager = manager;
|
||||
_manager._isLoading = true;
|
||||
Log.TraceSceneManager(manager.Runner, "Loading scope started");
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
_manager._isLoading = false;
|
||||
Log.TraceSceneManager(_manager.Runner, "Loading scope ended");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90a93abf1a391964a94e5c139605105b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Photon/Fusion/Runtime/RuntimeAssets.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b39ad3f7538fa4d489eab1f1431116ce
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01cd9d77222d74c74a540c1ec3a85c7a
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4ed52b30ac954791b7f3c691f1a348e
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences:
|
||||
- {fileID: 12800000, guid: 3c311f7773b444db7b0972edd68fd30a, type: 3}
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Photon/Fusion/Runtime/RuntimeAssets/Roboto-Regular.ttf
Normal file
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b587a998c6994e4a9a7e724729f140e
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- Roboto
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Photon/Fusion/Runtime/Statistics.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b11e317a3f6457f469fc57774081f48c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Fusion.Statistics {
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(NetworkObject)), DisallowMultipleComponent]
|
||||
[AddComponentMenu("Fusion/Statistics/Network Object Statistics")]
|
||||
public class FusionNetworkObjectStatistics : MonoBehaviour {
|
||||
[HideInInspector]
|
||||
public NetworkObject NetworkObject;
|
||||
|
||||
private void ToggleMonitoring(bool value) {
|
||||
NetworkObject = GetComponent<NetworkObject>();
|
||||
if (NetworkObject.Runner && NetworkObject.Runner.IsRunning) {
|
||||
if (NetworkObject.Runner.TryGetComponent<FusionStatistics>(out var statistics)) {
|
||||
if (statistics.MonitorNetworkObject(NetworkObject, this, value))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If not running or don't have the statistics manager or NO is already added on the graph, destroy for now.
|
||||
Destroy(this);
|
||||
}
|
||||
|
||||
private void OnEnable() {
|
||||
ToggleMonitoring(true);
|
||||
}
|
||||
|
||||
private void OnDisable() {
|
||||
ToggleMonitoring(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 526b142195d343c39a9184405f9ed5e0
|
||||
timeCreated: 1711133243
|
||||
@@ -0,0 +1,92 @@
|
||||
namespace Fusion.Statistics {
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
[Flags]
|
||||
internal enum NetworkObjectStat{
|
||||
InBandwidth = 1 << 0,
|
||||
OutBandwidth = 1 << 1,
|
||||
InPackets = 1 << 2,
|
||||
OutPackets = 1 << 3,
|
||||
AverageInPacketSize = 1 << 4,
|
||||
AverageOutPacketSize = 1 << 5
|
||||
}
|
||||
|
||||
public class FusionNetworkObjectStatsGraph : FusionStatsGraphBase {
|
||||
[SerializeField] private Text _description;
|
||||
private NetworkId _id;
|
||||
private NetworkObjectStat _stat;
|
||||
private FusionNetworkObjectStatsGraphCombine _combineParentGraph;
|
||||
|
||||
public override void UpdateGraph(NetworkRunner runner, FusionStatisticsManager statisticsManager, ref DateTime now) {
|
||||
AddValueToBuffer(GetNetworkObjectStatValue(statisticsManager), ref now);
|
||||
}
|
||||
|
||||
private float GetNetworkObjectStatValue(FusionStatisticsManager statisticsManager) {
|
||||
if (statisticsManager.ObjectStatisticsManager.GetNetworkObjectStatistics(_id, out var snapshot)) {
|
||||
switch (_stat) {
|
||||
case NetworkObjectStat.InBandwidth:
|
||||
return snapshot.InBandwidth;
|
||||
case NetworkObjectStat.OutBandwidth:
|
||||
return snapshot.OutBandwidth;
|
||||
case NetworkObjectStat.InPackets:
|
||||
return snapshot.InPackets;
|
||||
case NetworkObjectStat.OutPackets:
|
||||
return snapshot.OutPackets;
|
||||
case NetworkObjectStat.AverageInPacketSize:
|
||||
return snapshot.InBandwidth / Mathf.Max(1, snapshot.InPackets);
|
||||
case NetworkObjectStat.AverageOutPacketSize:
|
||||
return snapshot.OutBandwidth / Mathf.Max(1, snapshot.OutPackets);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal void SetupNetworkObjectStat(NetworkId id, NetworkObjectStat stat) {
|
||||
_id = id;
|
||||
_stat = stat;
|
||||
_description.text = _stat.ToString();
|
||||
|
||||
string valueTextFormat;
|
||||
float threshold1 = 0, threshold2 = 0, threshold3 = 0;
|
||||
float valueTextMultiplier = 1;
|
||||
bool ignoreZeroOnAverage = false, ignoreZeroOnBuffer = false;
|
||||
int accumulateTimeMs = 0;
|
||||
|
||||
switch (stat) {
|
||||
|
||||
case NetworkObjectStat.InBandwidth:
|
||||
case NetworkObjectStat.OutBandwidth:
|
||||
valueTextFormat = "{0:0} B";
|
||||
accumulateTimeMs = 1000;
|
||||
_description.text += " (Per second)";
|
||||
break;
|
||||
case NetworkObjectStat.AverageInPacketSize:
|
||||
case NetworkObjectStat.AverageOutPacketSize:
|
||||
valueTextFormat = "{0:0} B";
|
||||
ignoreZeroOnAverage = true;
|
||||
ignoreZeroOnBuffer = true;
|
||||
break;
|
||||
|
||||
case NetworkObjectStat.InPackets:
|
||||
case NetworkObjectStat.OutPackets:
|
||||
valueTextFormat = "{0:0}";
|
||||
accumulateTimeMs = 1000;
|
||||
_description.text += " (Per second)";
|
||||
break;
|
||||
|
||||
default:
|
||||
valueTextFormat = "{0:0}";
|
||||
break;
|
||||
}
|
||||
|
||||
SetValueTextFormat(valueTextFormat);
|
||||
SetValueTextMultiplier(valueTextMultiplier);
|
||||
SetThresholds(threshold1, threshold2, threshold3);
|
||||
SetIgnoreZeroValues(ignoreZeroOnAverage, ignoreZeroOnBuffer);
|
||||
Initialize(accumulateTimeMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c65e6f8cc0e421195e5884e060e7ead
|
||||
timeCreated: 1711029971
|
||||
@@ -0,0 +1,139 @@
|
||||
namespace Fusion.Statistics {
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
|
||||
public class FusionNetworkObjectStatsGraphCombine : MonoBehaviour {
|
||||
|
||||
[SerializeField] private Text _titleText;
|
||||
[SerializeField] private Dropdown _statDropdown;
|
||||
[SerializeField] private NetworkObjectStat _statsToRender;
|
||||
[SerializeField] private RectTransform _rect;
|
||||
[SerializeField] private RectTransform _combinedGraphRender;
|
||||
[SerializeField] private Button _toggleButton;
|
||||
|
||||
private float _headerHeight = 50;
|
||||
private float _graphHeight = 150;
|
||||
|
||||
private Dictionary<NetworkObjectStat, FusionNetworkObjectStatsGraph> _statsGraphs;
|
||||
[SerializeField]
|
||||
private FusionNetworkObjectStatsGraph _statsGraphPrefab;
|
||||
|
||||
private ContentSizeFitter _parentContentSizeFitter;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique identifier of the network object.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The network object identifier.
|
||||
/// </value>
|
||||
public NetworkId NetworkObjectID => _networkObject.Id;
|
||||
|
||||
private NetworkObject _networkObject;
|
||||
private FusionStatistics _fusionStatistics;
|
||||
private FusionNetworkObjectStatistics _objectStatisticsInstance;
|
||||
|
||||
public void SetupNetworkObject(NetworkObject networkObject, FusionStatistics fusionStatistics, FusionNetworkObjectStatistics objectStatisticsInstance) {
|
||||
_networkObject = networkObject;
|
||||
_fusionStatistics = fusionStatistics;
|
||||
_objectStatisticsInstance = objectStatisticsInstance;
|
||||
}
|
||||
|
||||
private void Start() {
|
||||
_statsGraphs = new Dictionary<NetworkObjectStat, FusionNetworkObjectStatsGraph>();
|
||||
_parentContentSizeFitter = GetComponentInParent<ContentSizeFitter>();
|
||||
|
||||
List<Dropdown.OptionData> options = new List<Dropdown.OptionData>();
|
||||
|
||||
options.Add(new Dropdown.OptionData("Toggle Stats"));
|
||||
|
||||
foreach (var option in Enum.GetNames(typeof(NetworkObjectStat))) {
|
||||
options.Add(new Dropdown.OptionData(option));
|
||||
}
|
||||
|
||||
_statDropdown.options = options;
|
||||
|
||||
_statDropdown.onValueChanged.AddListener(OnDropDownChanged);
|
||||
|
||||
UpdateHeight();
|
||||
|
||||
_titleText.text = _networkObject.Name;
|
||||
}
|
||||
|
||||
private void OnDropDownChanged(int arg0) {
|
||||
if (arg0 <= 0) return; // No stat selected.
|
||||
arg0--; // Remove the first label
|
||||
|
||||
NetworkObjectStat stat = (NetworkObjectStat)(1 << arg0);
|
||||
|
||||
if ((_statsToRender & stat) == stat) {
|
||||
_statsToRender &= ~stat; // Removed the flag
|
||||
DestroyStatGraph(stat);
|
||||
} else {
|
||||
_statsToRender |= stat; // Set the flag
|
||||
InstantiateStatGraph(stat);
|
||||
}
|
||||
|
||||
UpdateHeight();
|
||||
|
||||
// Set the first label again.
|
||||
_statDropdown.SetValueWithoutNotify(0);
|
||||
}
|
||||
|
||||
private void InstantiateStatGraph(NetworkObjectStat stat) {
|
||||
FusionNetworkObjectStatsGraph graph = Instantiate(_statsGraphPrefab, _combinedGraphRender);
|
||||
graph.SetupNetworkObjectStat(NetworkObjectID, stat);
|
||||
_statsGraphs.Add(stat, graph);
|
||||
}
|
||||
|
||||
private void DestroyStatGraph(NetworkObjectStat stat) {
|
||||
_statsGraphs[stat].gameObject.SetActive(false);
|
||||
Destroy(_statsGraphs[stat].gameObject);
|
||||
_statsGraphs.Remove(stat);
|
||||
}
|
||||
|
||||
private void UpdateHeight(float overrideValue = -1) {
|
||||
var sizeDelta = _rect.sizeDelta;
|
||||
var height = overrideValue >= 0 ? overrideValue : _headerHeight + _statsGraphs.Count * _graphHeight;
|
||||
_rect.sizeDelta = new Vector2(sizeDelta.x,height);
|
||||
|
||||
// Need to refresh vertical scroll
|
||||
_parentContentSizeFitter.enabled = false;
|
||||
_parentContentSizeFitter.enabled = true;
|
||||
}
|
||||
|
||||
private void OnDisable() {
|
||||
if (_statsGraphs == null) return;
|
||||
foreach (var graph in _statsGraphs.Values) {
|
||||
graph.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable() {
|
||||
if (_statsGraphs == null) return;
|
||||
foreach (var graph in _statsGraphs.Values) {
|
||||
graph.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleRenderDisplay() {
|
||||
var active = _combinedGraphRender.gameObject.activeSelf;
|
||||
_combinedGraphRender.gameObject.SetActive(!active);
|
||||
|
||||
if (active) {
|
||||
OnDisable();
|
||||
UpdateHeight(_headerHeight);
|
||||
_toggleButton.transform.rotation = Quaternion.Euler(0, 0, 90);
|
||||
} else {
|
||||
OnEnable();
|
||||
UpdateHeight();
|
||||
_toggleButton.transform.rotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
public void DestroyCombinedGraph() {
|
||||
_fusionStatistics.MonitorNetworkObject(_networkObject, _objectStatisticsInstance, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19334f7ed30f4e8ea9f48a51534f09dd
|
||||
timeCreated: 1711030624
|
||||
262
Assets/Photon/Fusion/Runtime/Statistics/FusionStatistics.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
namespace Fusion.Statistics {
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
[RequireComponent(typeof(NetworkRunner))]
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Fusion/Statistics/Fusion Statistics")]
|
||||
public class FusionStatistics : SimulationBehaviour, ISpawned {
|
||||
internal List<FusionStatsGraphBase> ActiveGraphs => _statsGraph;
|
||||
|
||||
// Setup prefabs
|
||||
private GameObject _statsCanvasPrefab;
|
||||
private FusionNetworkObjectStatsGraphCombine _objectGraphCombinePrefab;
|
||||
|
||||
private const string STATS_CANVAS_PREFAB_PATH = "FusionStatsResources/FusionStatsRenderPanel";
|
||||
private const string STATS_OBJECT_COMBINE_PREFAB_PATH = "FusionStatsResources/NetworkObjectStatistics";
|
||||
|
||||
private List<FusionStatsGraphBase> _statsGraph;
|
||||
private FusionStatsPanelHeader _header;
|
||||
private FusionStatsConfig _config;
|
||||
private FusionStatsCanvas _statsCanvas;
|
||||
private GameObject _statsPanelObject;
|
||||
private Dictionary<FusionNetworkObjectStatistics, FusionNetworkObjectStatsGraphCombine> _objectStatsGraphCombines;
|
||||
|
||||
[InlineHelp]
|
||||
[ExpandableEnum]
|
||||
[SerializeField] private RenderSimStats _statsEnabled;
|
||||
|
||||
[InlineHelp]
|
||||
[SerializeField] private CanvasAnchor _canvasAnchor = CanvasAnchor.TopRight;
|
||||
|
||||
|
||||
[FormerlySerializedAs("_statsConfig")] [SerializeField]
|
||||
[Header("Custom configuration to override default values.\nSelect only one stat flag per configuration.")]
|
||||
private List<FusionStatisticsStatCustomConfig> _statsCustomConfig = new List<FusionStatisticsStatCustomConfig>();
|
||||
|
||||
internal List<FusionStatisticsStatCustomConfig> StatsCustomConfig => _statsCustomConfig;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the statistics panel is active.
|
||||
/// </summary>
|
||||
public bool IsPanelActive => _statsPanelObject != false;
|
||||
|
||||
[System.Serializable]
|
||||
public struct FusionStatisticsStatCustomConfig {
|
||||
public RenderSimStats Stat;
|
||||
public float Threshold1;
|
||||
public float Threshold2;
|
||||
public float Threshold3;
|
||||
public bool IgnoreZeroOnBuffer;
|
||||
public bool IgnoreZeroOnAverageCalculation;
|
||||
public int AccumulateTimeMs;
|
||||
}
|
||||
|
||||
private void Awake() {
|
||||
_statsGraph = new List<FusionStatsGraphBase>();
|
||||
_statsCanvasPrefab = Resources.Load<GameObject>(STATS_CANVAS_PREFAB_PATH);
|
||||
_objectGraphCombinePrefab = Resources.Load<FusionNetworkObjectStatsGraphCombine>(STATS_OBJECT_COMBINE_PREFAB_PATH);
|
||||
|
||||
if (_statsCanvasPrefab == null || _objectGraphCombinePrefab == null) {
|
||||
Log.Error($"Error loading the required assets for Fusion Statistics, destroying stats instance. Make sure that the following paths are valid for the Fusion Statistics resource assets: \n 1. {STATS_CANVAS_PREFAB_PATH} \n 2. {STATS_OBJECT_COMBINE_PREFAB_PATH}");
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ISpawned.Spawned() {
|
||||
SetupStatisticsPanel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the custom configuration for Fusion Statistics.
|
||||
/// </summary>
|
||||
/// <param name="customConfig">The list of custom configurations for Fusion Statistics.</param>
|
||||
public void SetStatsCustomConfig(List<FusionStatisticsStatCustomConfig> customConfig) {
|
||||
if (customConfig == default) {
|
||||
Log.Warn("Trying to set a null Fusion Statistics custom stats config");
|
||||
return;
|
||||
}
|
||||
|
||||
_statsCustomConfig = customConfig;
|
||||
ApplyCustomConfig();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the anchor position of the Fusion Statistics canvas.
|
||||
/// </summary>
|
||||
/// <param name="anchor">The anchor position of the canvas (TopLeft or TopRight).</param>
|
||||
public void SetCanvasAnchor(CanvasAnchor anchor) {
|
||||
_canvasAnchor = anchor;
|
||||
if (_statsCanvas == false) return;
|
||||
_statsCanvas.SetCanvasAnchor(anchor);
|
||||
}
|
||||
|
||||
private void ApplyCustomConfig() {
|
||||
if (!_header) return;
|
||||
_header.ApplyStatsConfig(_statsCustomConfig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from a custom editor script.
|
||||
/// Will update any editor information into the fusion statistics.
|
||||
/// </summary>
|
||||
public void OnEditorChange() {
|
||||
RenderEnabledStats();
|
||||
ApplyCustomConfig();
|
||||
SetCanvasAnchor(_canvasAnchor);
|
||||
}
|
||||
|
||||
private void RenderEnabledStats() {
|
||||
if (IsPanelActive == false) return;
|
||||
_header.SetStatsToRender(_statsEnabled);
|
||||
}
|
||||
|
||||
internal void UpdateStatsEnabled(RenderSimStats stats) {
|
||||
_statsEnabled = stats;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the statistics panel for Fusion statistic tracking.
|
||||
/// </summary>
|
||||
public void SetupStatisticsPanel() {
|
||||
if (IsPanelActive) return;
|
||||
|
||||
// Was not registered on the Runner yet
|
||||
if (Runner == null) {
|
||||
var runner = GetComponent<NetworkRunner>();
|
||||
|
||||
if (runner.IsRunning == false) {
|
||||
Log.Warn($"Network Runner on ({runner.gameObject}) is not yet running.");
|
||||
return;
|
||||
}
|
||||
|
||||
runner.AddGlobal(this);
|
||||
// Return because when spawned is called the setup method will be called again.
|
||||
return;
|
||||
}
|
||||
|
||||
_objectStatsGraphCombines = new Dictionary<FusionNetworkObjectStatistics, FusionNetworkObjectStatsGraphCombine>();
|
||||
|
||||
_statsPanelObject = Instantiate(_statsCanvasPrefab, transform);
|
||||
_statsCanvas = _statsPanelObject.GetComponentInChildren<FusionStatsCanvas>();
|
||||
_statsCanvas.SetupStatsCanvas(this, _canvasAnchor, DestroyStatisticsPanel);
|
||||
_header = _statsPanelObject.GetComponentInChildren<FusionStatsPanelHeader>();
|
||||
_header.SetupHeader(Runner.LocalPlayer.ToString(), this);
|
||||
_config = _statsPanelObject.GetComponentInChildren<FusionStatsConfig>(true);
|
||||
|
||||
_statsPanelObject.AddComponent<FusionBasicBillboard>();
|
||||
ApplyCustomConfig();
|
||||
|
||||
Runner.AddVisibilityNodes(_statsPanelObject);
|
||||
|
||||
if (_statsEnabled != 0)
|
||||
RenderEnabledStats();
|
||||
|
||||
// Setup Event system
|
||||
if (!EventSystem.current) {
|
||||
Log.Debug("Fusion Statistics: No event system detected, creating one.");
|
||||
new GameObject("EventSystem-FusionStatistics", typeof(EventSystem), typeof(StandaloneInputModule));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the world anchor for Fusion Statistics. Set null to return to screen space overlay.
|
||||
/// </summary>
|
||||
/// <param name="anchor">The FusionStatsWorldAnchor component that defines the anchor object. Null to return to screen space overlay.</param>
|
||||
/// <param name="scale">The scale of the statistics panel.</param>
|
||||
public void SetWorldAnchor(FusionStatsWorldAnchor anchor, float scale) {
|
||||
_config.SetWorldCanvasScale(scale);
|
||||
|
||||
if (anchor == null) {
|
||||
_config.ResetToCanvasAnchor();
|
||||
} else {
|
||||
_config.SetWorldAnchor(anchor.transform);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the statistics panel.
|
||||
/// </summary>
|
||||
public void DestroyStatisticsPanel() {
|
||||
var keys = _objectStatsGraphCombines?.Keys.ToArray();
|
||||
if (keys != null) {
|
||||
foreach (var fusionNetworkObjectStatistics in keys) {
|
||||
MonitorNetworkObject(fusionNetworkObjectStatistics.NetworkObject, fusionNetworkObjectStatistics, false);
|
||||
}
|
||||
}
|
||||
|
||||
_objectStatsGraphCombines?.Clear();
|
||||
_statsGraph.Clear();
|
||||
|
||||
Destroy(_statsPanelObject);
|
||||
_statsPanelObject = null;
|
||||
|
||||
if (Runner) {
|
||||
if (Runner.TryGetFusionStatistics(out var statisticsManager)) {
|
||||
statisticsManager.ObjectStatisticsManager.ClearMonitoredNetworkObjects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool MonitorNetworkObject(NetworkObject networkObject, FusionNetworkObjectStatistics objectStatisticsInstance, bool monitor) {
|
||||
|
||||
if (Runner.TryGetFusionStatistics(out var statisticsManager)) {
|
||||
statisticsManager.ObjectStatisticsManager.MonitorNetworkObjectStatistics(networkObject.Id, monitor);
|
||||
}
|
||||
|
||||
if (monitor) {
|
||||
|
||||
// If Id already monitored on the stats, return false to destroy the object statistics instance.
|
||||
if (_objectStatsGraphCombines.ContainsKey(objectStatisticsInstance))
|
||||
return false;
|
||||
|
||||
var graphCombine = Instantiate(_objectGraphCombinePrefab, _header.ContentRect);
|
||||
graphCombine.SetupNetworkObject(networkObject, this, objectStatisticsInstance);
|
||||
_objectStatsGraphCombines.Add(objectStatisticsInstance, graphCombine);
|
||||
} else {
|
||||
|
||||
if (_objectStatsGraphCombines.Remove(objectStatisticsInstance, out var graphCombine)) {
|
||||
Destroy(graphCombine.gameObject);
|
||||
Destroy(objectStatisticsInstance);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateAllGraphs(FusionStatisticsManager statisticsManager) {
|
||||
var now = DateTime.Now;
|
||||
foreach (var statsGraphBase in _statsGraph) {
|
||||
statsGraphBase.UpdateGraph(Runner, statisticsManager, ref now);
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterGraph(FusionStatsGraphBase graph) {
|
||||
_statsGraph.Add(graph);
|
||||
}
|
||||
|
||||
public void UnregisterGraph(FusionStatsGraphBase graph) {
|
||||
_statsGraph.Remove(graph);
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
// Safety exit
|
||||
if (!Runner) return;
|
||||
|
||||
|
||||
Profiler.BeginSample("Fusion Statistics Update Graph");
|
||||
|
||||
// Collect and update
|
||||
if (Runner.TryGetFusionStatistics(out var statisticsManager)) {
|
||||
UpdateAllGraphs(statisticsManager);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c6080750a33c9d428004642d0e07dd6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- _statsCanvasPrefab: {fileID: 6292187590335715622, guid: 367c5caf25960d8419724c6c96708538,
|
||||
type: 3}
|
||||
- _objectGraphCombinePrefab: {fileID: 7935946544523926548, guid: 7cc7f808e527f6e4f98257acbf47ad87,
|
||||
type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
207
Assets/Photon/Fusion/Runtime/Statistics/FusionStatsCanvas.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
namespace Fusion.Statistics {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// The side to attach the statistics panel anchor.
|
||||
/// </summary>
|
||||
public enum CanvasAnchor {TopLeft, TopRight}
|
||||
|
||||
|
||||
public class FusionStatsCanvas : MonoBehaviour, IDragHandler, IEndDragHandler, IBeginDragHandler {
|
||||
[Header("General References")]
|
||||
[SerializeField] private Canvas _canvas;
|
||||
[SerializeField] private CanvasScaler _canvasScaler;
|
||||
[SerializeField] private RectTransform _canvasPanel;
|
||||
|
||||
[Space] [Header("Panel References")]
|
||||
[SerializeField] private RectTransform _contentPanel;
|
||||
[SerializeField] private RectTransform _contentContainer;
|
||||
[SerializeField] private RectTransform _bottomPanel;
|
||||
[SerializeField] private FusionStatsPanelHeader _header;
|
||||
|
||||
[Space] [Header("Misc")]
|
||||
[SerializeField] private Button _hideButton;
|
||||
[SerializeField] private Button _closeButton;
|
||||
|
||||
[Space] [Header("World Anchor Panel Settings")]
|
||||
[SerializeField] private FusionStatsConfig _config;
|
||||
|
||||
private bool _isColapsed => !_contentPanel.gameObject.activeSelf;
|
||||
|
||||
private CanvasAnchor _anchor;
|
||||
|
||||
private enum DragMode {None, DragCanvas, ResizeContent}
|
||||
|
||||
private DragMode _dragMode;
|
||||
private static int _statsCanvasActiveCount = 0;
|
||||
|
||||
internal void SetupStatsCanvas(FusionStatistics fusionStatistics, CanvasAnchor canvasAnchor, UnityAction closeButtonAction) {
|
||||
_anchor = canvasAnchor;
|
||||
_canvasPanel.anchoredPosition = GetDefinedAnchorPosition();
|
||||
var maxOffsetMultiplier = Mathf.Min(_statsCanvasActiveCount, 3);
|
||||
_canvasPanel.anchoredPosition += Vector2.down * (FusionStatisticsHelper.DEFAULT_HEADER_HEIGHT * maxOffsetMultiplier);
|
||||
|
||||
//Setup buttons
|
||||
_closeButton.onClick.RemoveAllListeners();
|
||||
_closeButton.onClick.AddListener(closeButtonAction);
|
||||
|
||||
_hideButton.onClick.RemoveAllListeners();
|
||||
_hideButton.onClick.AddListener(ToggleHide);
|
||||
|
||||
// Setup runner statistics ref
|
||||
_config.SetupStatisticReference(fusionStatistics);
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData) {
|
||||
if (_config.IsWorldAnchored) return;
|
||||
|
||||
if (_dragMode != DragMode.None) return; // Already dragging.
|
||||
var dragBeginPos = eventData.pressPosition;
|
||||
var rectT = _bottomPanel;
|
||||
dragBeginPos = rectT.InverseTransformPoint(dragBeginPos);
|
||||
var resize = rectT.rect.Contains(dragBeginPos) && eventData.button == PointerEventData.InputButton.Right;
|
||||
_dragMode = resize ? DragMode.ResizeContent : DragMode.DragCanvas;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData) {
|
||||
if (_config.IsWorldAnchored) return;
|
||||
|
||||
switch (_dragMode) {
|
||||
case DragMode.DragCanvas:
|
||||
_canvasPanel.anchoredPosition += eventData.delta / _canvas.scaleFactor;
|
||||
break;
|
||||
case DragMode.ResizeContent:
|
||||
UpdateContentContainerHeight(eventData.delta.y / _canvas.scaleFactor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData) {
|
||||
if (_config.IsWorldAnchored) return;
|
||||
|
||||
if (CheckDraggableRectVisibility(_canvasPanel) == false)
|
||||
SnapPanelBackToOriginPos();
|
||||
|
||||
if (_dragMode == DragMode.ResizeContent) {
|
||||
var currentSize = _contentPanel.sizeDelta.y;
|
||||
var visibleGraphHeight = 0f;
|
||||
var remaining = 0f;
|
||||
for (int i = 0; i < _contentContainer.childCount; i++) {
|
||||
var prevHeight = visibleGraphHeight;
|
||||
visibleGraphHeight += ((RectTransform)_contentContainer.GetChild(i)).sizeDelta.y + 10;
|
||||
|
||||
if (visibleGraphHeight >= currentSize) {
|
||||
if (currentSize - prevHeight < visibleGraphHeight - currentSize) {
|
||||
remaining = currentSize - prevHeight;
|
||||
} else {
|
||||
remaining = -(visibleGraphHeight - currentSize);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
UpdateContentContainerHeight(remaining);
|
||||
}
|
||||
|
||||
_dragMode = DragMode.None;
|
||||
}
|
||||
|
||||
public void SnapPanelBackToOriginPos() {
|
||||
_canvasPanel.anchoredPosition = GetDefinedAnchorPosition();
|
||||
}
|
||||
|
||||
private void UpdateContentContainerHeight(float yDelta) {
|
||||
var height = _contentPanel.sizeDelta.y;
|
||||
var targetHeight = height - yDelta;
|
||||
SetContentPanelHeight(targetHeight);
|
||||
}
|
||||
|
||||
internal void ToggleHide() {
|
||||
var active = _contentPanel.gameObject.activeSelf;
|
||||
_hideButton.transform.rotation = active ? Quaternion.Euler(0, 0, 90) : Quaternion.identity;
|
||||
_contentPanel.gameObject.SetActive(!active);
|
||||
_bottomPanel.gameObject.SetActive(!active);
|
||||
}
|
||||
|
||||
// Better offscreen check for later.
|
||||
private bool CheckDraggableRectVisibility(RectTransform rectTransform) {
|
||||
var anchoredPos = rectTransform.anchoredPosition;
|
||||
var size = rectTransform.rect.size;
|
||||
|
||||
if (Mathf.Abs(anchoredPos.x) >= _canvasScaler.referenceResolution.x * .5f + size.x * .5f)
|
||||
return false;
|
||||
|
||||
// anchor is on top.
|
||||
if (anchoredPos.y >= _canvasScaler.referenceResolution.y * .5f + size.y || anchoredPos.y <= -_canvasScaler.referenceResolution.y * .5f)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetContentPanelHeight(float value) {
|
||||
if (value < FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT) {
|
||||
value = FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT;
|
||||
}else {
|
||||
var maxHeight = Screen.height / _canvas.scaleFactor - 2 * FusionStatisticsHelper.DEFAULT_HEADER_HEIGHT;
|
||||
if (value > maxHeight) {
|
||||
value = maxHeight;
|
||||
}
|
||||
}
|
||||
|
||||
_contentPanel.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, value);
|
||||
_contentPanel.gameObject.SetActive(false);
|
||||
_contentPanel.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
private void AdaptContentHeightToGraphs() {
|
||||
var neededHeight = 0f;
|
||||
for (int i = 0; i < _contentContainer.childCount; i++) {
|
||||
neededHeight += ((RectTransform)_contentContainer.GetChild(i)).sizeDelta.y + 10; // +10 spacing
|
||||
}
|
||||
|
||||
float maxHeight = Screen.height / _canvas.scaleFactor - 2 * FusionStatisticsHelper.DEFAULT_HEADER_HEIGHT;
|
||||
|
||||
if (neededHeight > maxHeight) {
|
||||
neededHeight = maxHeight;
|
||||
}
|
||||
if (neededHeight < FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT) {
|
||||
neededHeight = FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT;
|
||||
}
|
||||
|
||||
SetContentPanelHeight(neededHeight);
|
||||
}
|
||||
|
||||
private void OnEnable() {
|
||||
_statsCanvasActiveCount++;
|
||||
_header.OnRenderStatsUpdate += AdaptContentHeightToGraphs;
|
||||
}
|
||||
|
||||
private void OnDisable() {
|
||||
_statsCanvasActiveCount--;
|
||||
_header.OnRenderStatsUpdate -= AdaptContentHeightToGraphs;
|
||||
}
|
||||
|
||||
public void SetCanvasAnchor(CanvasAnchor anchor) {
|
||||
_anchor = anchor;
|
||||
SnapPanelBackToOriginPos();
|
||||
}
|
||||
|
||||
private Vector2 GetDefinedAnchorPosition() {
|
||||
var refRes = _canvasScaler.referenceResolution;
|
||||
switch (_anchor) {
|
||||
case CanvasAnchor.TopRight:
|
||||
return refRes * .5f - Vector2.right * (_canvasPanel.sizeDelta.x * .5f);
|
||||
case CanvasAnchor.TopLeft:
|
||||
refRes.x *= -1;
|
||||
return refRes * .5f + Vector2.right * (_canvasPanel.sizeDelta.x * .5f);
|
||||
default:
|
||||
return Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25ab394f9fec45f692c631c30839e2ee
|
||||
timeCreated: 1712603842
|
||||
107
Assets/Photon/Fusion/Runtime/Statistics/FusionStatsConfig.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
namespace Fusion.Statistics {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class FusionStatsConfig : MonoBehaviour {
|
||||
|
||||
public bool IsWorldAnchored => _worldTransformAnchor != null;
|
||||
|
||||
[SerializeField] private Button _worldAnchorButtonPrefab;
|
||||
[SerializeField] private Transform _worldAnchorListContainer;
|
||||
[SerializeField] private GameObject _configPanel;
|
||||
[SerializeField] private Canvas _canvas;
|
||||
[SerializeField] private RectTransform _renderPanelRectTransform;
|
||||
|
||||
private Transform _worldTransformAnchor;
|
||||
private float _worldCanvasScale = 0.005f;
|
||||
|
||||
private FusionStatistics _fusionStatistics;
|
||||
|
||||
private static List<Transform> _worldAnchorCandidates = new List<Transform>();
|
||||
private static event Action _onWorldAnchorCandidatesUpdate;
|
||||
|
||||
internal static void SetWorldAnchorCandidate(Transform candidate, bool register) {
|
||||
if (register) {
|
||||
if (_worldAnchorCandidates.Contains(candidate) == false)
|
||||
_worldAnchorCandidates.Add(candidate);
|
||||
} else {
|
||||
_worldAnchorCandidates.Remove(candidate);
|
||||
}
|
||||
|
||||
_onWorldAnchorCandidatesUpdate?.Invoke();
|
||||
}
|
||||
|
||||
internal void SetupStatisticReference(FusionStatistics fusionStatistics) {
|
||||
_fusionStatistics = fusionStatistics;
|
||||
}
|
||||
|
||||
public void ToggleConfigPanel() {
|
||||
_configPanel.SetActive(!_configPanel.activeSelf);
|
||||
}
|
||||
|
||||
public void ToggleUseWorldAnchor(bool value) {
|
||||
// If true, the buttons will trigger the re-parenting logic.
|
||||
if (value == false) {
|
||||
ResetToCanvasAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetWorldAnchor(Transform worldTransformAnchor) {
|
||||
_canvas.renderMode = RenderMode.WorldSpace;
|
||||
_renderPanelRectTransform.localScale = Vector3.one * _worldCanvasScale;
|
||||
_renderPanelRectTransform.localPosition = Vector3.zero;
|
||||
|
||||
|
||||
if (worldTransformAnchor == _worldTransformAnchor) return;
|
||||
_renderPanelRectTransform.SetParent(worldTransformAnchor);
|
||||
_worldTransformAnchor = worldTransformAnchor;
|
||||
_renderPanelRectTransform.localPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
public void SetWorldCanvasScale(float value) {
|
||||
_worldCanvasScale = value;
|
||||
}
|
||||
|
||||
internal void ResetToCanvasAnchor() {
|
||||
// Was called from editor destroy
|
||||
if (!_fusionStatistics)
|
||||
return;
|
||||
|
||||
var childPanel = (RectTransform)_renderPanelRectTransform.GetChild(0);
|
||||
|
||||
_renderPanelRectTransform.SetParent(_fusionStatistics.transform);
|
||||
_canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
_renderPanelRectTransform.localScale = Vector3.one;
|
||||
_renderPanelRectTransform.localPosition = Vector3.zero;
|
||||
childPanel.localPosition = Vector3.zero;
|
||||
childPanel.anchoredPosition = Vector3.zero;
|
||||
_worldTransformAnchor = default;
|
||||
}
|
||||
|
||||
private void UpdateWorldAnchorButtons() {
|
||||
// Clear all old buttons, ok because it should not be frequent
|
||||
for (int i = _worldAnchorListContainer.childCount-1; i >= 0 ; i--) {
|
||||
Destroy(_worldAnchorListContainer.GetChild(i).gameObject);
|
||||
}
|
||||
|
||||
foreach (var candidate in _worldAnchorCandidates) {
|
||||
var button = Instantiate(_worldAnchorButtonPrefab, _worldAnchorListContainer);
|
||||
button.onClick.AddListener(() => SetWorldAnchor(candidate));
|
||||
button.GetComponentInChildren<Text>().text = candidate.name;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable() {
|
||||
_onWorldAnchorCandidatesUpdate -= UpdateWorldAnchorButtons;
|
||||
_onWorldAnchorCandidatesUpdate += UpdateWorldAnchorButtons;
|
||||
UpdateWorldAnchorButtons();
|
||||
}
|
||||
|
||||
private void OnDestroy() {
|
||||
_onWorldAnchorCandidatesUpdate -= UpdateWorldAnchorButtons;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 586894e5cee94d0e857cf1dbc7716646
|
||||
timeCreated: 1712679394
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace Fusion.Statistics {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class FusionStatsGraphDefault : FusionStatsGraphBase {
|
||||
internal RenderSimStats Stat => _selectedStats;
|
||||
private RenderSimStats _selectedStats;
|
||||
[SerializeField] private Text _descriptionText;
|
||||
|
||||
protected override void Initialize(int accumulateTimeMs) {
|
||||
base.Initialize(accumulateTimeMs);
|
||||
_descriptionText.text = _selectedStats.ToString();
|
||||
if (_statsAdditionalInfo.TryGetValue(Stat, out var info)) {
|
||||
_descriptionText.text += $" {info}";
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateGraph(NetworkRunner runner, FusionStatisticsManager statisticsManager,
|
||||
ref DateTime now) {
|
||||
var value = FusionStatisticsHelper.GetStatDataFromSnapshot(_selectedStats, statisticsManager.CompleteSnapshot);
|
||||
AddValueToBuffer(value, ref now);
|
||||
}
|
||||
|
||||
public virtual void ApplyCustomStatsConfig(FusionStatistics.FusionStatisticsStatCustomConfig config) {
|
||||
SetThresholds(config.Threshold1, config.Threshold2, config.Threshold3);
|
||||
SetIgnoreZeroValues(config.IgnoreZeroOnAverageCalculation, config.IgnoreZeroOnBuffer);
|
||||
SetAccumulateTime(config.AccumulateTimeMs);
|
||||
}
|
||||
|
||||
internal void SetupDefaultGraph(RenderSimStats stat) {
|
||||
_selectedStats = stat;
|
||||
|
||||
FusionStatisticsHelper.GetStatGraphDefaultSettings(_selectedStats, out var valueTextFormat,
|
||||
out var valueTextMultiplier, out var ignoreZeroOnAverage, out var ignoreZeroOnBuffer, out var bufferTimeSpan);
|
||||
|
||||
SetValueTextFormat(valueTextFormat);
|
||||
SetValueTextMultiplier(valueTextMultiplier);
|
||||
SetIgnoreZeroValues(ignoreZeroOnAverage, ignoreZeroOnBuffer);
|
||||
Initialize(bufferTimeSpan);
|
||||
}
|
||||
|
||||
private Dictionary<RenderSimStats, string> _statsAdditionalInfo = new Dictionary<RenderSimStats, string>() {
|
||||
{ RenderSimStats.InPackets, "(Per second)" },
|
||||
{ RenderSimStats.OutPackets, "(Per second)" },
|
||||
{ RenderSimStats.InObjectUpdates, "(Per second)" },
|
||||
{ RenderSimStats.OutObjectUpdates, "(Per second)" },
|
||||
{ RenderSimStats.InBandwidth, "(Per second)" },
|
||||
{ RenderSimStats.OutBandwidth, "(Per second)" },
|
||||
{ RenderSimStats.InputInBandwidth, "(Per second)" },
|
||||
{ RenderSimStats.InputOutBandwidth, "(Per second)" },
|
||||
{ RenderSimStats.WordsWrittenSize, "(Per second)" },
|
||||
{ RenderSimStats.WordsWrittenCount, "(Per second)" },
|
||||
{ RenderSimStats.WordsReadCount, "(Per second)" },
|
||||
{ RenderSimStats.WordsReadSize, "(Per second)" },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1c807bdcb1b9874697735bf2b27b24c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,89 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: FusionStatsGraphMaterial
|
||||
m_Shader: {fileID: 4800000, guid: f723a494700aee146aa96072604b48c0, type: 3}
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
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_Ints: []
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _FadeColorIntensity: 0.25
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _LinesThickness: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _PointsThickness: 2
|
||||
- _SideFalloff: 1
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _AverageColor: {r: 1, g: 1, b: 1, a: 0}
|
||||
- _BaseColor: {r: 0, g: 1, b: 0, a: 1}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Threshold1Color: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _Threshold2Color: {r: 1, g: 0.5019608, b: 0, a: 1}
|
||||
- _Threshold3Color: {r: 1, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20f9b98d6ad29584c912ad547627b2cf
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,176 @@
|
||||
Shader "Fusion/Fusion Stats Graph"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_BaseColor ("Base Color", Color) = (0.0, 1.0, 0.0, 1.0)
|
||||
_AverageColor ("Average Color", Color) = (1.0, 1.0, 1.0, 0.0)
|
||||
_Threshold1Color ("Threshold 1 Color", Color) = (1.0, 1.0, 0.0, 1.0)
|
||||
_Threshold2Color ("Threshold 2 Color", Color) = (1.0, 0.5, 0.0, 1.0)
|
||||
_Threshold3Color ("Threshold 3 Color", Color) = (1.0, 0.0, 0.0, 1.0)
|
||||
|
||||
_FadeColorIntensity ("Fade Color Intensity", Float) = 1.0
|
||||
_PointsThickness ("Points Thickness", Float) = 1.0
|
||||
_LinesThickness ("Lines Thickness", Float) = 1.0
|
||||
_SideFalloff ("Side Falloff", Float) = 1.0
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"Queue" = "Transparent"
|
||||
"RenderType" = "Transparent"
|
||||
"PreviewType" = "Plane"
|
||||
"IgnoreProjector" = "True"
|
||||
"CanUseSpriteAtlas" = "True"
|
||||
}
|
||||
|
||||
Cull Off
|
||||
Lighting Off
|
||||
ZWrite Off
|
||||
ZTest Off
|
||||
Blend One OneMinusSrcAlpha
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float4 color : COLOR;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
fixed4 color : COLOR;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
|
||||
UNITY_VERTEX_OUTPUT_STEREO
|
||||
};
|
||||
|
||||
fixed4 _BaseColor;
|
||||
fixed4 _AverageColor;
|
||||
fixed4 _Threshold1Color;
|
||||
fixed4 _Threshold2Color;
|
||||
fixed4 _Threshold3Color;
|
||||
|
||||
fixed _Threshold1;
|
||||
fixed _Threshold2;
|
||||
fixed _Threshold3;
|
||||
fixed _FadeColorIntensity;
|
||||
fixed _PointsThickness;
|
||||
fixed _LinesThickness;
|
||||
fixed _SideFalloff;
|
||||
|
||||
uniform float _Values[512];
|
||||
uniform float _Samples;
|
||||
uniform float _Average;
|
||||
|
||||
v2f vert(appdata input)
|
||||
{
|
||||
v2f output;
|
||||
|
||||
UNITY_SETUP_INSTANCE_ID(input);
|
||||
UNITY_INITIALIZE_OUTPUT(v2f, output);
|
||||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
||||
|
||||
output.vertex = UnityObjectToClipPos(input.vertex);
|
||||
output.texcoord = input.texcoord;
|
||||
output.color = input.color;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f input) : SV_Target
|
||||
{
|
||||
fixed4 color = input.color;
|
||||
|
||||
fixed x = input.texcoord.x;
|
||||
fixed y = input.texcoord.y;
|
||||
|
||||
float value = _Values[floor(x * _Samples)];
|
||||
|
||||
color = _BaseColor;
|
||||
|
||||
if (_Threshold1 > 0.0 && value >= _Threshold1)
|
||||
{
|
||||
color = _Threshold1Color;
|
||||
}
|
||||
if (_Threshold2 > 0.0 && value >= _Threshold2)
|
||||
{
|
||||
color = _Threshold2Color;
|
||||
}
|
||||
if (_Threshold3 > 0.0 && value >= _Threshold3)
|
||||
{
|
||||
color = _Threshold3Color;
|
||||
}
|
||||
|
||||
if (y > value)
|
||||
{
|
||||
color.a = 0.0;
|
||||
}
|
||||
else if (y < value - 0.01 * _PointsThickness)
|
||||
{
|
||||
color.a = y * _FadeColorIntensity;
|
||||
}
|
||||
else
|
||||
{
|
||||
color.a = 1.0;
|
||||
}
|
||||
|
||||
if (_LinesThickness > 0.0)
|
||||
{
|
||||
if (_AverageColor.a > 0.0 && y < _Average && y > _Average - 0.01 * _LinesThickness)
|
||||
{
|
||||
color = _AverageColor;
|
||||
}
|
||||
|
||||
if (_Threshold1Color.a > 0.0 && y < _Threshold1 && y > _Threshold1 - 0.01 * _LinesThickness)
|
||||
{
|
||||
color = _Threshold1Color;
|
||||
}
|
||||
|
||||
if (_Threshold2Color.a > 0.0 && y < _Threshold2 && y > _Threshold2 - 0.01 * _LinesThickness)
|
||||
{
|
||||
color = _Threshold2Color;
|
||||
}
|
||||
|
||||
if (_Threshold3Color.a > 0.0 && y < _Threshold3 && y > _Threshold3 - 0.01 * _LinesThickness)
|
||||
{
|
||||
color = _Threshold3Color;
|
||||
}
|
||||
}
|
||||
|
||||
if (_SideFalloff > 0.0)
|
||||
{
|
||||
float sideFalloff = 0.01 * _SideFalloff;
|
||||
|
||||
if (x < sideFalloff)
|
||||
{
|
||||
color.a *= 1.0 - (sideFalloff - x) / sideFalloff;
|
||||
}
|
||||
else if (x > 1.0 - sideFalloff)
|
||||
{
|
||||
color.a *= (1.0 - x) / sideFalloff;
|
||||
}
|
||||
}
|
||||
|
||||
color.rgb *= color.a;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f723a494700aee146aa96072604b48c0
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,283 @@
|
||||
namespace Fusion.Statistics {
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// List of all simulation stats able to render on a graph.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum RenderSimStats {
|
||||
/// <summary>
|
||||
/// Incoming packets.
|
||||
/// </summary>
|
||||
InPackets = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Outgoing packets.
|
||||
/// </summary>
|
||||
OutPackets = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Round Trip Time.
|
||||
/// </summary>
|
||||
RTT = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// In Bandwidth in Bytes.
|
||||
/// </summary>
|
||||
InBandwidth = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// Out Bandwidth in Bytes.
|
||||
/// </summary>
|
||||
OutBandwidth = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// Amount of re-simulation ticks executed.
|
||||
/// </summary>
|
||||
Resimulations = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// Amount of forward ticks executed.
|
||||
/// </summary>
|
||||
ForwardTicks = 1 << 6,
|
||||
|
||||
/// <summary>
|
||||
/// Average measured time between two input/state packets (from same client) received by the server.
|
||||
/// </summary>
|
||||
InputReceiveDelta = 1 << 7,
|
||||
|
||||
/// <summary>
|
||||
/// Time sync abruptly reset count.
|
||||
/// </summary>
|
||||
TimeResets = 1 << 8,
|
||||
|
||||
/// <summary>
|
||||
/// Average measured time between two state packets (from server) received by the client.
|
||||
/// </summary>
|
||||
StateReceiveDelta = 1 << 9,
|
||||
|
||||
/// <summary>
|
||||
/// Average buffering for prediction.
|
||||
/// </summary>
|
||||
SimulationTimeOffset = 1 << 10,
|
||||
|
||||
/// <summary>
|
||||
/// How much the simulation is currently sped up / slowed down.
|
||||
/// </summary>
|
||||
SimulationSpeed = 1 << 11,
|
||||
|
||||
/// <summary>
|
||||
/// Average buffering for interpolation.
|
||||
/// </summary>
|
||||
InterpolationOffset = 1 << 12,
|
||||
|
||||
/// <summary>
|
||||
/// How much interpolation is currently sped up / slowed down.
|
||||
/// </summary>
|
||||
InterpolationSpeed = 1 << 13,
|
||||
|
||||
/// <summary>
|
||||
/// Input in bandwidth.
|
||||
/// </summary>
|
||||
InputInBandwidth = 1 << 14,
|
||||
|
||||
/// <summary>
|
||||
/// Input out bandwidth.
|
||||
/// </summary>
|
||||
InputOutBandwidth = 1 << 15,
|
||||
|
||||
/// <summary>
|
||||
/// Average size for received packet.
|
||||
/// </summary>
|
||||
AverageInPacketSize = 1 << 16,
|
||||
|
||||
/// <summary>
|
||||
/// Average size for sent packet.
|
||||
/// </summary>
|
||||
AverageOutPacketSize = 1 << 17,
|
||||
|
||||
/// <summary>
|
||||
/// Amount of object updates received.
|
||||
/// </summary>
|
||||
InObjectUpdates = 1 << 18,
|
||||
|
||||
/// <summary>
|
||||
/// Amount of object updates sent.
|
||||
/// </summary>
|
||||
OutObjectUpdates = 1 << 19,
|
||||
|
||||
/// <summary>
|
||||
/// Memory in use for the object allocator.
|
||||
/// </summary>
|
||||
ObjectsAllocatedMemoryInUse = 1 << 20,
|
||||
|
||||
/// <summary>
|
||||
/// Memory in use for the general allocator.
|
||||
/// </summary>
|
||||
GeneralAllocatedMemoryInUse = 1 << 21,
|
||||
|
||||
/// <summary>
|
||||
/// Memory free for the object allocator.
|
||||
/// </summary>
|
||||
ObjectsAllocatedMemoryFree = 1 << 22,
|
||||
|
||||
/// <summary>
|
||||
/// Memory free for the general allocator.
|
||||
/// </summary>
|
||||
GeneralAllocatedMemoryFree = 1 << 23,
|
||||
|
||||
/// <summary>
|
||||
/// Amount of written words. How many networked changes are being sent.
|
||||
/// </summary>
|
||||
WordsWrittenCount = 1 << 24,
|
||||
|
||||
/// <summary>
|
||||
/// Size of all last written words in Bytes.
|
||||
/// </summary>
|
||||
WordsWrittenSize = 1 << 25,
|
||||
|
||||
/// <summary>
|
||||
/// Amount of read words. How many networked changes are being received.
|
||||
/// </summary>
|
||||
WordsReadCount = 1 << 26,
|
||||
|
||||
/// <summary>
|
||||
/// Size of all last read words in Bytes.
|
||||
/// </summary>
|
||||
WordsReadSize = 1 << 27,
|
||||
}
|
||||
|
||||
public class FusionStatsPanelHeader : MonoBehaviour {
|
||||
public event Action OnRenderStatsUpdate;
|
||||
|
||||
[SerializeField] private Text _statsHeaderTitle;
|
||||
[SerializeField] private Dropdown _statsDropdown;
|
||||
[SerializeField] private FusionStatsGraphDefault _defaultGraphPrefab;
|
||||
|
||||
public RectTransform ContentRect;
|
||||
|
||||
private Dictionary<RenderSimStats,FusionStatsGraphDefault> _defaultStatsGraph;
|
||||
private FusionStatistics _fusionStatistics;
|
||||
private RenderSimStats _statsToRender;
|
||||
|
||||
public void SetupHeader(string title, FusionStatistics fusionStatistics) {
|
||||
_statsHeaderTitle.text = title;
|
||||
_fusionStatistics = fusionStatistics;
|
||||
|
||||
SetupDropdown();
|
||||
}
|
||||
|
||||
private void SetupDropdown() {
|
||||
_defaultStatsGraph = new Dictionary<RenderSimStats, FusionStatsGraphDefault>();
|
||||
|
||||
List<Dropdown.OptionData> options = new List<Dropdown.OptionData>();
|
||||
|
||||
options.Add(new Dropdown.OptionData("Toggle Stats"));
|
||||
|
||||
foreach (var option in Enum.GetNames(typeof(RenderSimStats))) {
|
||||
options.Add(new Dropdown.OptionData(option));
|
||||
}
|
||||
|
||||
_statsDropdown.options = options;
|
||||
|
||||
_statsDropdown.onValueChanged.AddListener(OnDropDownChanged);
|
||||
}
|
||||
|
||||
internal void SetStatsToRender(RenderSimStats stats) {
|
||||
// Early exit
|
||||
if (stats == _statsToRender) return;
|
||||
|
||||
// For each possible stat
|
||||
foreach (RenderSimStats renderSimStat in Enum.GetValues(typeof(RenderSimStats))) {
|
||||
// If it is set on the stats received
|
||||
if ((stats & renderSimStat) == renderSimStat) {
|
||||
// And if it is not already set on the stats to render... add it
|
||||
if ((_statsToRender & renderSimStat) != renderSimStat) {
|
||||
AddStat(renderSimStat);
|
||||
}
|
||||
}
|
||||
// else if is NOT set on the stats received
|
||||
else {
|
||||
// And if it is set on the stats to render... remove
|
||||
if ((_statsToRender & renderSimStat) == renderSimStat) {
|
||||
RemoveStat(renderSimStat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure they are equal now.
|
||||
_statsToRender = stats;
|
||||
}
|
||||
|
||||
private void AddStat(RenderSimStats stat) {
|
||||
_statsToRender |= stat; // Set the flag
|
||||
InstantiateStatGraph(stat);
|
||||
InvokeRenderStatsUpdate();
|
||||
}
|
||||
|
||||
private void RemoveStat(RenderSimStats stat) {
|
||||
_statsToRender &= ~stat; // Removed the flag
|
||||
DestroyStatGraph(stat);
|
||||
InvokeRenderStatsUpdate();
|
||||
}
|
||||
|
||||
private void InvokeRenderStatsUpdate() {
|
||||
OnRenderStatsUpdate?.Invoke();
|
||||
}
|
||||
|
||||
private void OnDropDownChanged(int arg0) {
|
||||
if (arg0 <= 0) return; // No stat selected.
|
||||
arg0--; // Remove the first label
|
||||
|
||||
RenderSimStats stat = (RenderSimStats)(1 << arg0);
|
||||
|
||||
if ((_statsToRender & stat) == stat) {
|
||||
RemoveStat(stat);
|
||||
} else {
|
||||
AddStat(stat);
|
||||
}
|
||||
|
||||
// Set the first label again.
|
||||
_statsDropdown.SetValueWithoutNotify(0);
|
||||
|
||||
_fusionStatistics.UpdateStatsEnabled(_statsToRender);
|
||||
}
|
||||
|
||||
private void InstantiateStatGraph(RenderSimStats stat) {
|
||||
FusionStatsGraphDefault graph = Instantiate(_defaultGraphPrefab, ContentRect);
|
||||
graph.SetupDefaultGraph(stat);
|
||||
TryApplyCustomStatConfig(graph);
|
||||
_defaultStatsGraph.Add(stat, graph);
|
||||
}
|
||||
|
||||
private void DestroyStatGraph(RenderSimStats stat) {
|
||||
if (_defaultStatsGraph.Remove(stat, out var statsGraphDefault)) {
|
||||
Destroy(statsGraphDefault.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void TryApplyCustomStatConfig(FusionStatsGraphDefault graph) {
|
||||
// Need to do this way because unity cannot serialize a dictionary.
|
||||
foreach (var config in _fusionStatistics.StatsCustomConfig) {
|
||||
if (config.Stat == graph.Stat) {
|
||||
ApplyCustomStatsConfig(graph, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyCustomStatsConfig(FusionStatsGraphDefault graph, FusionStatistics.FusionStatisticsStatCustomConfig config) {
|
||||
graph.ApplyCustomStatsConfig(config);
|
||||
}
|
||||
|
||||
internal void ApplyStatsConfig(List<FusionStatistics.FusionStatisticsStatCustomConfig> statsConfig) {
|
||||
foreach (var config in statsConfig) {
|
||||
if (_defaultStatsGraph.TryGetValue(config.Stat, out var graph)) {
|
||||
ApplyCustomStatsConfig(graph, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0672ffa0bdc147e7b368e081ab5e7285
|
||||
timeCreated: 1710192229
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Fusion.Statistics {
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Fusion/Statistics/Statistics World Anchor")]
|
||||
public class FusionStatsWorldAnchor : MonoBehaviour {
|
||||
private void OnEnable() {
|
||||
FusionStatsConfig.SetWorldAnchorCandidate(transform, true);
|
||||
}
|
||||
|
||||
private void OnDisable() {
|
||||
FusionStatsConfig.SetWorldAnchorCandidate(transform, false);
|
||||
}
|
||||
|
||||
private void OnDestroy() {
|
||||
// Saving stats if is child
|
||||
var stats = transform.GetComponentInChildren<FusionStatsCanvas>();
|
||||
if (stats) {
|
||||
stats.transform.SetParent(null);
|
||||
stats.GetComponentInChildren<FusionStatsConfig>(true).ResetToCanvasAnchor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b922ea457e8e4de6bfea00a8cc1eca80
|
||||
timeCreated: 1712606226
|
||||
8
Assets/Photon/Fusion/Runtime/Statistics/Prefabs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bbab8d6d9806b548839f21543e696d4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,202 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &3987400527868405841
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4827688222978096223}
|
||||
- component: {fileID: 3929318550392185910}
|
||||
- component: {fileID: 7855319467316828452}
|
||||
- component: {fileID: 4920168020725175909}
|
||||
m_Layer: 5
|
||||
m_Name: FusionStatsSimpleButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4827688222978096223
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3987400527868405841}
|
||||
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: 860521090280365962}
|
||||
m_Father: {fileID: 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 &3929318550392185910
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3987400527868405841}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7855319467316828452
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3987400527868405841}
|
||||
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.29411766, g: 0.29411766, b: 0.29411766, 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: 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 &4920168020725175909
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3987400527868405841}
|
||||
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: 7855319467316828452}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &4034818165790845292
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 860521090280365962}
|
||||
- component: {fileID: 8155235640972728683}
|
||||
- component: {fileID: 889677207960826122}
|
||||
m_Layer: 5
|
||||
m_Name: Text (Legacy)
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &860521090280365962
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4034818165790845292}
|
||||
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: 4827688222978096223}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0.000061035156, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8155235640972728683
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4034818165790845292}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &889677207960826122
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4034818165790845292}
|
||||
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: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Button
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e3a30446d6463e48adea83d18ce9654
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,384 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1719597503058426708
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1719597503058426707}
|
||||
- component: {fileID: 1719597503058426706}
|
||||
m_Layer: 5
|
||||
m_Name: NOStatGraph
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1719597503058426707
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1719597503058426708}
|
||||
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: 6113166891111545665}
|
||||
- {fileID: 6239836229493852532}
|
||||
m_Father: {fileID: 0}
|
||||
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: 400, y: 150}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1719597503058426706
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1719597503058426708}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6c65e6f8cc0e421195e5884e060e7ead, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_render: {fileID: 6113166891111545665}
|
||||
_header: {fileID: 6239836229493852532}
|
||||
_targetImage: {fileID: 4962068735173936647}
|
||||
_toggleButton: {fileID: 0}
|
||||
_ignoreZeroedValuesOnAverageCalculation: 0
|
||||
_ignoreZeroedValuesOnBuffer: 0
|
||||
_valuesTextUpdateDelay: 0.1
|
||||
_valueTextMultiplier: 1
|
||||
_averageValueText: {fileID: 5977692791235129321}
|
||||
_peakValueText: {fileID: 5180300036338728672}
|
||||
_currentValueText: {fileID: 8872655689014498417}
|
||||
_threshold1: 0
|
||||
_threshold2: 0
|
||||
_threshold3: 0
|
||||
_threshold1Text: {fileID: 574183341331817218}
|
||||
_threshold2Text: {fileID: 4974124732164616916}
|
||||
_threshold3Text: {fileID: 7292999253169489219}
|
||||
_maxSamples: 128
|
||||
_valueTextFormat: '{0:0}'
|
||||
_description: {fileID: 391098838509034737}
|
||||
--- !u!1 &6453443907668438141
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1788213164568613159}
|
||||
- component: {fileID: 4074940008736195761}
|
||||
- component: {fileID: 391098838509034737}
|
||||
m_Layer: 5
|
||||
m_Name: Description
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1788213164568613159
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6453443907668438141}
|
||||
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: 6239836229493852532}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0.8, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4074940008736195761
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6453443907668438141}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &391098838509034737
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6453443907668438141}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Description
|
||||
--- !u!1 &8718060512283005892
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6239836229493852532}
|
||||
- component: {fileID: 384158204715830663}
|
||||
- component: {fileID: 423454910494282654}
|
||||
m_Layer: 5
|
||||
m_Name: Header
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6239836229493852532
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8718060512283005892}
|
||||
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: 1788213164568613159}
|
||||
m_Father: {fileID: 1719597503058426707}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0.85}
|
||||
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 &384158204715830663
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8718060512283005892}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &423454910494282654
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8718060512283005892}
|
||||
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.3529412, g: 0.5882353, 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!1001 &1719597502569185417
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 1719597503058426707}
|
||||
m_Modifications:
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_RootOrder
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 0.85
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 9126926557282158578, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_Name
|
||||
value: StatisticsRenderGraph
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: a09170bc25723ba48b6d4d36f6201acd, type: 3}
|
||||
--- !u!114 &574183341331817218 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 1164976986725983115, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &4962068735173936647 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 5981329958659966606, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &4974124732164616916 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 5970252233686725213, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &5180300036338728672 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 5780690898318835305, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &5977692791235129321 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 4983298122956582752, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!224 &6113166891111545665 stripped
|
||||
RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!114 &7292999253169489219 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 8280093310795793866, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &8872655689014498417 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 7854063927993816312, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1719597502569185417}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 302a42a4eb4d5e540b803b1f86597505
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,625 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &2059135424099053782
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2059135424099053777}
|
||||
- component: {fileID: 2059135424099053778}
|
||||
- component: {fileID: 2059135424099053776}
|
||||
m_Layer: 5
|
||||
m_Name: ToggleButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2059135424099053777
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2059135424099053782}
|
||||
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: 6870472896872226928}
|
||||
m_Father: {fileID: 6662754291284625420}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0.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 &2059135424099053778
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2059135424099053782}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2059135424099053776
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2059135424099053782}
|
||||
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: 0
|
||||
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: 0}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls:
|
||||
- m_Target: {fileID: 2059135424270465704}
|
||||
m_TargetAssemblyTypeName: Fusion.Stats.FusionStatsGraphBase, Fusion.Unity
|
||||
m_MethodName: ToggleRenderDisplay
|
||||
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 &2059135424237535789
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2059135424237535788}
|
||||
- component: {fileID: 2059135424270465704}
|
||||
m_Layer: 5
|
||||
m_Name: SingleStatistics
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2059135424237535788
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2059135424237535789}
|
||||
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: 1070322759179670889}
|
||||
- {fileID: 6662754291284625420}
|
||||
m_Father: {fileID: 0}
|
||||
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: 400, y: 150}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2059135424270465704
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2059135424237535789}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a1c807bdcb1b9874697735bf2b27b24c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_render: {fileID: 1070322759179670889}
|
||||
_header: {fileID: 6662754291284625420}
|
||||
_targetImage: {fileID: 2220300178287962159}
|
||||
_toggleButton: {fileID: 2059135424099053776}
|
||||
_ignoreZeroedValuesOnAverageCalculation: 0
|
||||
_ignoreZeroedValuesOnBuffer: 0
|
||||
_valuesTextUpdateDelay: 0.1
|
||||
_valueTextMultiplier: 1
|
||||
_averageValueText: {fileID: 646794221100057025}
|
||||
_peakValueText: {fileID: 2155191676243792072}
|
||||
_currentValueText: {fileID: 2391087390145165913}
|
||||
_threshold1: 0
|
||||
_threshold2: 0
|
||||
_threshold3: 0
|
||||
_threshold1Text: {fileID: 6772060006189485354}
|
||||
_threshold2Text: {fileID: 2237018056329157884}
|
||||
_threshold3Text: {fileID: 4555716653057387371}
|
||||
_maxSamples: 128
|
||||
_valueTextFormat: '{0:0}'
|
||||
_selectedStats: 0
|
||||
_descriptionText: {fileID: 3003985804431238575}
|
||||
--- !u!1 &2885396740209662036
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6662754291284625420}
|
||||
- component: {fileID: 6532386780719339218}
|
||||
- component: {fileID: 3096909071055530399}
|
||||
m_Layer: 5
|
||||
m_Name: Header
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6662754291284625420
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2885396740209662036}
|
||||
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: 8019411793580211070}
|
||||
- {fileID: 2059135424099053777}
|
||||
m_Father: {fileID: 2059135424237535788}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -12.5}
|
||||
m_SizeDelta: {x: 0, y: 25}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6532386780719339218
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2885396740209662036}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &3096909071055530399
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2885396740209662036}
|
||||
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.39215687, g: 0.39215687, b: 0.39215687, 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!1 &4311662245131508133
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6870472896872226928}
|
||||
- component: {fileID: 4798023581314036480}
|
||||
- component: {fileID: 3314414533859350682}
|
||||
m_Layer: 5
|
||||
m_Name: Icon
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6870472896872226928
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4311662245131508133}
|
||||
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: 2059135424099053777}
|
||||
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 &4798023581314036480
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4311662245131508133}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &3314414533859350682
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4311662245131508133}
|
||||
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: 21300000, guid: 330babd635d5dfc4691ae3151ffc4491, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 1
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &5877711169838791531
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8019411793580211070}
|
||||
- component: {fileID: 4664219767356560693}
|
||||
- component: {fileID: 3003985804431238575}
|
||||
m_Layer: 5
|
||||
m_Name: Description
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8019411793580211070
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5877711169838791531}
|
||||
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: 6662754291284625420}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.1, y: 0}
|
||||
m_AnchorMax: {x: 0.9, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: -4}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4664219767356560693
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5877711169838791531}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &3003985804431238575
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5877711169838791531}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Description
|
||||
--- !u!1001 &5607514626138009249
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 2059135424237535788}
|
||||
m_Modifications:
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_Pivot.x
|
||||
value: 0.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_Pivot.y
|
||||
value: 0.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_RootOrder
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.x
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 125
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 62.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 9126926557282158578, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_Name
|
||||
value: StatisticsRenderGraph
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 9126926557282158578, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
propertyPath: m_IsActive
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: a09170bc25723ba48b6d4d36f6201acd, type: 3}
|
||||
--- !u!114 &646794221100057025 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 4983298122956582752, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!224 &1070322759179670889 stripped
|
||||
RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 4831069612263668680, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!114 &2155191676243792072 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 5780690898318835305, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &2220300178287962159 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 5981329958659966606, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &2237018056329157884 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 5970252233686725213, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &2391087390145165913 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 7854063927993816312, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &4555716653057387371 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 8280093310795793866, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &6772060006189485354 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 1164976986725983115, guid: a09170bc25723ba48b6d4d36f6201acd,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 5607514626138009249}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 483568e790e53a243a4f436e924e90b9
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,958 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &724195450048490934
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2252466015236110801}
|
||||
- component: {fileID: 8237614070168901424}
|
||||
- component: {fileID: 1164976986725983115}
|
||||
m_Layer: 5
|
||||
m_Name: Threshold 1
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2252466015236110801
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 724195450048490934}
|
||||
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: 3852939355018933397}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0.5}
|
||||
m_AnchorMax: {x: 1, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8237614070168901424
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 724195450048490934}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1164976986725983115
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 724195450048490934}
|
||||
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: 8
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 1
|
||||
m_MinSize: 5
|
||||
m_MaxSize: 15
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 1
|
||||
--- !u!1 &1346113333905028555
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1996528426999223811}
|
||||
- component: {fileID: 7493037385389740767}
|
||||
- component: {fileID: 5981329958659966606}
|
||||
m_Layer: 5
|
||||
m_Name: GraphRender
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1996528426999223811
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1346113333905028555}
|
||||
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: 4831069612263668680}
|
||||
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}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7493037385389740767
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1346113333905028555}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5981329958659966606
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1346113333905028555}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 2100000, guid: 20f9b98d6ad29584c912ad547627b2cf, type: 2}
|
||||
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: 21300000, guid: 2f112e6067c75b34f8c6233878db13b4, type: 3}
|
||||
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!1 &1713622682841279402
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8245948005965945133}
|
||||
- component: {fileID: 2944837472607786133}
|
||||
- component: {fileID: 88432356876806002}
|
||||
m_Layer: 5
|
||||
m_Name: Current
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8245948005965945133
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1713622682841279402}
|
||||
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: 4831069612263668680}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.7, y: 0}
|
||||
m_AnchorMax: {x: 0.85, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 25}
|
||||
m_SizeDelta: {x: 0, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2944837472607786133
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1713622682841279402}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &88432356876806002
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1713622682841279402}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 'Current:'
|
||||
--- !u!1 &1866382379870605257
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 630422623976466404}
|
||||
- component: {fileID: 4635913912757587435}
|
||||
- component: {fileID: 8280093310795793866}
|
||||
m_Layer: 5
|
||||
m_Name: Threshold 3
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &630422623976466404
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1866382379870605257}
|
||||
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: 3852939355018933397}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0.5}
|
||||
m_AnchorMax: {x: 1, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4635913912757587435
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1866382379870605257}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &8280093310795793866
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1866382379870605257}
|
||||
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: 8
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 1
|
||||
m_MinSize: 5
|
||||
m_MaxSize: 15
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 3
|
||||
--- !u!1 &2926125212941636726
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7767554146471260023}
|
||||
- component: {fileID: 9159602532881435272}
|
||||
- component: {fileID: 7854063927993816312}
|
||||
m_Layer: 5
|
||||
m_Name: CurrentValue
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7767554146471260023
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2926125212941636726}
|
||||
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: 4831069612263668680}
|
||||
m_RootOrder: 3
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.85, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 25}
|
||||
m_SizeDelta: {x: 0, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &9159602532881435272
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2926125212941636726}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7854063927993816312
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2926125212941636726}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 0.0
|
||||
--- !u!1 &3091450967103008972
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8724134812417612050}
|
||||
- component: {fileID: 2037306754755500012}
|
||||
- component: {fileID: 5780690898318835305}
|
||||
m_Layer: 5
|
||||
m_Name: PeakValue
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8724134812417612050
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3091450967103008972}
|
||||
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: 4831069612263668680}
|
||||
m_RootOrder: 7
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.15, y: 0}
|
||||
m_AnchorMax: {x: 0.3, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 25}
|
||||
m_SizeDelta: {x: 0, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2037306754755500012
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3091450967103008972}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5780690898318835305
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3091450967103008972}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 0.0
|
||||
--- !u!1 &3122924414019610630
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3141646064265744334}
|
||||
- component: {fileID: 7432501649756783534}
|
||||
- component: {fileID: 5759711218940510673}
|
||||
m_Layer: 5
|
||||
m_Name: Peak
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3141646064265744334
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3122924414019610630}
|
||||
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: 4831069612263668680}
|
||||
m_RootOrder: 6
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0.15, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 25}
|
||||
m_SizeDelta: {x: 0, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7432501649756783534
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3122924414019610630}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5759711218940510673
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3122924414019610630}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 'Peak:'
|
||||
--- !u!1 &4466228370271718180
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3852939355018933397}
|
||||
m_Layer: 5
|
||||
m_Name: Thresholds Texts
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3852939355018933397
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4466228370271718180}
|
||||
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: 2252466015236110801}
|
||||
- {fileID: 7848575700833239251}
|
||||
- {fileID: 630422623976466404}
|
||||
m_Father: {fileID: 4831069612263668680}
|
||||
m_RootOrder: 8
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0.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 &4748543092155706786
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1197363314016853701}
|
||||
- component: {fileID: 6559507284176787114}
|
||||
- component: {fileID: 4983298122956582752}
|
||||
m_Layer: 5
|
||||
m_Name: AverageValue
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1197363314016853701
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4748543092155706786}
|
||||
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: 4831069612263668680}
|
||||
m_RootOrder: 5
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.55, y: 0}
|
||||
m_AnchorMax: {x: 0.7, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 25}
|
||||
m_SizeDelta: {x: 0, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6559507284176787114
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4748543092155706786}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &4983298122956582752
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4748543092155706786}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 0.0
|
||||
--- !u!1 &6021428339324464465
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 517706616007655284}
|
||||
- component: {fileID: 5597891647223780865}
|
||||
- component: {fileID: 1335454418943084614}
|
||||
m_Layer: 5
|
||||
m_Name: Average
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &517706616007655284
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6021428339324464465}
|
||||
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: 4831069612263668680}
|
||||
m_RootOrder: 4
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.3, y: 0}
|
||||
m_AnchorMax: {x: 0.55, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 25}
|
||||
m_SizeDelta: {x: 0, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5597891647223780865
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6021428339324464465}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1335454418943084614
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6021428339324464465}
|
||||
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: 14
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 1
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 20
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 'Average:'
|
||||
--- !u!1 &6109184620530364220
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4722110937780803752}
|
||||
- component: {fileID: 2696435566306223433}
|
||||
- component: {fileID: 5094385119256644395}
|
||||
m_Layer: 5
|
||||
m_Name: Background
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4722110937780803752
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6109184620530364220}
|
||||
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: 4831069612263668680}
|
||||
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 &2696435566306223433
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6109184620530364220}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5094385119256644395
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6109184620530364220}
|
||||
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.627451}
|
||||
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!1 &6188757312191444877
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7848575700833239251}
|
||||
- component: {fileID: 5649024345479520547}
|
||||
- component: {fileID: 5970252233686725213}
|
||||
m_Layer: 5
|
||||
m_Name: Threshold 2
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7848575700833239251
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6188757312191444877}
|
||||
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: 3852939355018933397}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0.5}
|
||||
m_AnchorMax: {x: 1, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5649024345479520547
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6188757312191444877}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5970252233686725213
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6188757312191444877}
|
||||
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: 8
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 1
|
||||
m_MinSize: 5
|
||||
m_MaxSize: 15
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 2
|
||||
--- !u!1 &9126926557282158578
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4831069612263668680}
|
||||
m_Layer: 5
|
||||
m_Name: StatisticsRenderGraph
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4831069612263668680
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 9126926557282158578}
|
||||
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: 4722110937780803752}
|
||||
- {fileID: 1996528426999223811}
|
||||
- {fileID: 8245948005965945133}
|
||||
- {fileID: 7767554146471260023}
|
||||
- {fileID: 517706616007655284}
|
||||
- {fileID: 1197363314016853701}
|
||||
- {fileID: 3141646064265744334}
|
||||
- {fileID: 8724134812417612050}
|
||||
- {fileID: 3852939355018933397}
|
||||
m_Father: {fileID: 0}
|
||||
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}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a09170bc25723ba48b6d4d36f6201acd
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Photon/Fusion/Runtime/Statistics/Resources.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fb8caeac2583754bba8211a64c5937d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48d535affc4755b4ca6cc5030fcefe8e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 367c5caf25960d8419724c6c96708538
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7cc7f808e527f6e4f98257acbf47ad87
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Photon/Fusion/Runtime/Statistics/StatsIcons.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9547e9072f77f75438aff775104614e7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5853bc00e6bfda84ea9030e0486a1c44
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 200
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 256
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 604f27d227e3caa44a1d6626d599fbdb
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 200
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 128
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 865 B |
@@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3f33adb909e26443914391fba875e4c
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 200
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 256
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 330babd635d5dfc4691ae3151ffc4491
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 200
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 128
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Photon/Fusion/Runtime/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e22d12b23fafcf42a3b720254974ed9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ac8b97c4c9f1e34ca713fc9ba9144be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,120 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Fusion.Analyzer;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Fusion {
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Automatically adds a <see cref="RunnerVisibilityLink"/> for each indicated component.
|
||||
/// These indicated components will be limited to no more than one enabled instance when running in Multi-Peer mode.
|
||||
/// </summary>
|
||||
[AddComponentMenu("Fusion/Enable On Single Runner")]
|
||||
public class EnableOnSingleRunner : Fusion.Behaviour {
|
||||
|
||||
/// <summary>
|
||||
/// If more than one runner instance is visible, this indicates which peer's clone of this entity should be visible.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
[SerializeField]
|
||||
#pragma warning disable IDE0044 // Add readonly modifier
|
||||
public RunnerVisibilityLink.PreferredRunners PreferredRunner;
|
||||
#pragma warning restore IDE0044 // Add readonly modifier
|
||||
|
||||
/// <summary>
|
||||
/// Collection of components that will be marked for Multi-Peer mode as objects that should only have one enabled instance.
|
||||
/// </summary>
|
||||
[InlineHelp]
|
||||
public UnityEngine.Component[] Components = new Component[0];
|
||||
|
||||
/// <summary>
|
||||
/// Prefix for the GUIDs of <see cref="RunnerVisibilityLink"/> components which are added at runtime.
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
[SerializeField]
|
||||
private string _guid = System.Guid.NewGuid().ToString().Substring(0, 19);
|
||||
|
||||
/// <summary>
|
||||
/// At runtime startup, this adds a <see cref="RunnerVisibilityLink"/> for each component reference to this GameObject.
|
||||
/// </summary>
|
||||
internal void AddNodes(List<RunnerVisibilityLink> existingNodes) {
|
||||
for(int i = 0; i < Components.Length; ++i) {
|
||||
var found = false;
|
||||
foreach (var existingNode in existingNodes) {
|
||||
if (existingNode.Component == Components[i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) continue;
|
||||
var node = Components[i].gameObject.AddComponent<RunnerVisibilityLink>();
|
||||
node.Guid = _guid + i;
|
||||
node.Component = Components[i];
|
||||
node.SetupOnSingleRunnerLink(PreferredRunner);
|
||||
existingNodes.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds visual/audio components on this GameObject, and adds them to the Components collection.
|
||||
/// </summary>
|
||||
[EditorButton("Find on GameObject", EditorButtonVisibility.EditMode, dirtyObject: true)]
|
||||
public void FindRecognizedTypes() {
|
||||
Components = FindRecognizedComponentsOnGameObject(gameObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds visual/audio nested components on this GameObject and its children, and adds them to the Components collection.
|
||||
/// </summary>
|
||||
[EditorButton("Find in Nested Children", EditorButtonVisibility.EditMode, dirtyObject: true)]
|
||||
public void FindNestedRecognizedTypes() {
|
||||
Components = FindRecognizedNestedComponents(gameObject);
|
||||
}
|
||||
|
||||
[StaticField(StaticFieldResetMode.None)]
|
||||
private static readonly List<Component> reusableComponentsList = new List<UnityEngine.Component>();
|
||||
[StaticField(StaticFieldResetMode.None)]
|
||||
private static readonly List<Component> reusableComponentsList2 = new List<UnityEngine.Component>();
|
||||
|
||||
private static Component[] FindRecognizedComponentsOnGameObject(GameObject go) {
|
||||
try {
|
||||
go.GetComponents(reusableComponentsList);
|
||||
reusableComponentsList2.Clear();
|
||||
foreach (var comp in reusableComponentsList) {
|
||||
var type = comp.GetType();
|
||||
if (type.IsRecognizedByRunnerVisibility()) {
|
||||
reusableComponentsList2.Add(comp);
|
||||
}
|
||||
}
|
||||
return reusableComponentsList2.ToArray();
|
||||
} finally {
|
||||
reusableComponentsList.Clear();
|
||||
reusableComponentsList2.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static Component[] FindRecognizedNestedComponents(GameObject go) {
|
||||
try {
|
||||
go.transform.GetNestedComponentsInChildren<UnityEngine.Component, NetworkObject>(reusableComponentsList, true);
|
||||
reusableComponentsList2.Clear();
|
||||
foreach (var comp in reusableComponentsList) {
|
||||
var type = comp.GetType();
|
||||
if (type.IsRecognizedByRunnerVisibility()) {
|
||||
reusableComponentsList2.Add(comp);
|
||||
}
|
||||
}
|
||||
return reusableComponentsList2.ToArray();
|
||||
} finally {
|
||||
reusableComponentsList.Clear();
|
||||
reusableComponentsList2.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d73b0a95be81246699cf0d9ecdc01863
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,85 @@
|
||||
namespace Fusion {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Add this Component to the NetworkRunner Prefab or GameObject. If Interest Management is enabled in NetworkProjectConfig ReplicationFeatures,
|
||||
/// gizmos will be shown that indicate active Area Of Interest cells. These gizmos are currently NOT applicable to Shared Mode and will only
|
||||
/// render for the Server/Host peer.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(NetworkRunner))]
|
||||
[ScriptHelp(BackColor = ScriptHeaderBackColor.Sand)]
|
||||
[DisallowMultipleComponent]
|
||||
public class RunnerAOIGizmos : SimulationBehaviour {
|
||||
#if UNITY_EDITOR
|
||||
|
||||
[Flags]
|
||||
public enum GizmoOptionsEnum {
|
||||
ShowActiveServerZones = 1,
|
||||
ShowPlayerInterest = 2,
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct CustomOptions {
|
||||
public Color ServerZonesColor;
|
||||
public Color PlayerInterestColor;
|
||||
}
|
||||
|
||||
[ExpandableEnum(AlwaysExpanded = true)]
|
||||
public GizmoOptionsEnum GizmoOptions = GizmoOptionsEnum.ShowActiveServerZones | GizmoOptionsEnum.ShowPlayerInterest;
|
||||
|
||||
public CustomOptions Customization = new CustomOptions() {
|
||||
ServerZonesColor = new Color(0.25f, 0.25f, 0.25f, 0.75f),
|
||||
PlayerInterestColor = new Color(255f / 255f, 21f / 255f, 21 / 255f, 0.2f),
|
||||
};
|
||||
|
||||
private List<(Vector3 center, Vector3 size, int playerCount, int objectCount)> _reusableGizmoData;
|
||||
|
||||
private void OnEnabled() {
|
||||
|
||||
}
|
||||
|
||||
private void OnDrawGizmos() {
|
||||
|
||||
if (enabled == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GizmoOptions == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var runner = Runner;
|
||||
|
||||
if ((object)runner == null || runner.IsRunning == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var datas = _reusableGizmoData ??= new List<(Vector3 center, Vector3 size, int playerCount, int objectCount)>();
|
||||
var colors = Customization;
|
||||
|
||||
runner.GetAreaOfInterestGizmoData(datas);
|
||||
|
||||
for (int i = 0; i < datas.Count; i++) {
|
||||
var data = datas[i];
|
||||
var c = datas[i].center;
|
||||
var s = datas[i].size;
|
||||
|
||||
// Draw server actives zone boxes
|
||||
if (data.objectCount > 0) {
|
||||
Gizmos.color = colors.ServerZonesColor;
|
||||
Gizmos.DrawWireCube(data.center, data.size);
|
||||
}
|
||||
|
||||
// Draw player interest regions
|
||||
if (data.playerCount > 0) {
|
||||
Gizmos.color = colors.PlayerInterestColor;
|
||||
Gizmos.DrawCube(c, s);
|
||||
}
|
||||
}
|
||||
Gizmos.color = Color.white;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a09b7c3c2f0604fef93beb7057001dbb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,85 @@
|
||||
namespace Fusion {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sockets;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// When running in Multi-Peer mode, this component automatically will register the associated
|
||||
/// <see cref="NetworkRunner" /> with <see cref="NetworkRunnerVisibilityExtensions" />,
|
||||
/// and will automatically attach loaded scene objects and spawned objects with the peers visibility handling.
|
||||
/// </summary>
|
||||
[ScriptHelp(BackColor = ScriptHeaderBackColor.Sand)]
|
||||
[DisallowMultipleComponent]
|
||||
public class RunnerEnableVisibility : Behaviour, INetworkRunnerCallbacks {
|
||||
|
||||
private void Awake() {
|
||||
var runner = GetComponentInParent<NetworkRunner>();
|
||||
if (runner) {
|
||||
// Optimistically register this as if we are running multi-peer (can't know yet)
|
||||
runner.EnableVisibilityExtension();
|
||||
|
||||
// Just to be safe against double registration.
|
||||
runner.ObjectAcquired -= RunnerOnObjectAcquired;
|
||||
runner.ObjectAcquired += RunnerOnObjectAcquired;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy() {
|
||||
if (TryGetComponent<NetworkRunner>(out var runner)) {
|
||||
runner.DisableVisibilityExtension();
|
||||
runner.RemoveCallbacks(this);
|
||||
runner.ObjectAcquired -= RunnerOnObjectAcquired;
|
||||
}
|
||||
}
|
||||
|
||||
private void RunnerOnObjectAcquired(NetworkRunner runner, NetworkObject obj) {
|
||||
if (runner.IsRunning == false) return;
|
||||
if (runner.Config.PeerMode == NetworkProjectConfig.PeerModes.Single) {
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
|
||||
runner.AddVisibilityNodes(obj.gameObject);
|
||||
}
|
||||
|
||||
public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress) {
|
||||
}
|
||||
|
||||
void INetworkRunnerCallbacks.OnSceneLoadDone(NetworkRunner runner) {
|
||||
if (runner.IsRunning == false) return;
|
||||
if (runner.Config.PeerMode == NetworkProjectConfig.PeerModes.Single) {
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
|
||||
var scene = runner.SimulationUnityScene;
|
||||
|
||||
if (scene.IsValid())
|
||||
foreach (var obj in scene.GetRootGameObjects())
|
||||
runner.AddVisibilityNodes(obj);
|
||||
}
|
||||
|
||||
#region Unused
|
||||
|
||||
void INetworkRunnerCallbacks.OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
|
||||
void INetworkRunnerCallbacks.OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
|
||||
void INetworkRunnerCallbacks.OnPlayerJoined(NetworkRunner runner, PlayerRef player) { }
|
||||
void INetworkRunnerCallbacks.OnPlayerLeft(NetworkRunner runner, PlayerRef player) { }
|
||||
void INetworkRunnerCallbacks.OnInput(NetworkRunner runner, NetworkInput input) { }
|
||||
void INetworkRunnerCallbacks.OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { }
|
||||
void INetworkRunnerCallbacks.OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason) { }
|
||||
void INetworkRunnerCallbacks.OnConnectedToServer(NetworkRunner runner) { }
|
||||
void INetworkRunnerCallbacks.OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason) { }
|
||||
void INetworkRunnerCallbacks.OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { }
|
||||
void INetworkRunnerCallbacks.OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason) { }
|
||||
void INetworkRunnerCallbacks.OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { }
|
||||
void INetworkRunnerCallbacks.OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList) { }
|
||||
void INetworkRunnerCallbacks.OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
|
||||
void INetworkRunnerCallbacks.OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
|
||||
void INetworkRunnerCallbacks.OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment<byte> data) { }
|
||||
void INetworkRunnerCallbacks.OnSceneLoadStart(NetworkRunner runner) { }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8edbe7108d8a43ab838cf8b8d9453df
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,80 @@
|
||||
namespace Fusion
|
||||
{
|
||||
using LagCompensation;
|
||||
using UnityEngine;
|
||||
|
||||
[ScriptHelp(BackColor = ScriptHeaderBackColor.Sand)]
|
||||
[DisallowMultipleComponent]
|
||||
public class RunnerLagCompensationGizmos : Behaviour
|
||||
{
|
||||
public bool DrawSnapshotHistory;
|
||||
public bool DrawBroadphaseNodes;
|
||||
|
||||
public Color StateAuthHitboxCollor = Color.green;
|
||||
public Color NonStateAuthHitboxCollor = Color.cyan;
|
||||
|
||||
private NetworkRunner _runner;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_runner = GetComponentInParent<NetworkRunner>();
|
||||
|
||||
if (_runner == null) {
|
||||
Debug.LogWarning($"{this} was not able to find the NetworkRunner reference. Destroying the component.");
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (_runner == null || _runner.IsRunning == false || _runner.GetVisible() == false || _runner.LagCompensation?.DrawInfo == default) return;
|
||||
|
||||
if (DrawBroadphaseNodes)
|
||||
{
|
||||
RenderBHVBroadphase();
|
||||
}
|
||||
|
||||
if (DrawSnapshotHistory)
|
||||
{
|
||||
RenderHitboxHistory();
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderHitboxHistory()
|
||||
{
|
||||
Gizmos.color = _runner.IsServer ? StateAuthHitboxCollor : NonStateAuthHitboxCollor;
|
||||
|
||||
foreach (var snapshotDrawInfo in _runner.LagCompensation.DrawInfo.SnapshotHistoryDraw) {
|
||||
foreach (var colliderDrawInfo in snapshotDrawInfo) {
|
||||
Gizmos.matrix = colliderDrawInfo.LocalToWorldMatrix;
|
||||
switch (colliderDrawInfo.Type) {
|
||||
case HitboxTypes.Box:
|
||||
Gizmos.DrawWireCube(colliderDrawInfo.Offset, colliderDrawInfo.BoxExtents * 2);
|
||||
break;
|
||||
case HitboxTypes.Sphere:
|
||||
Gizmos.DrawWireSphere(colliderDrawInfo.Offset, colliderDrawInfo.Radius);
|
||||
break;
|
||||
case HitboxTypes.Capsule:
|
||||
LagCompensationDraw.GizmosDrawWireCapsule(colliderDrawInfo.CapsuleTopCenter, colliderDrawInfo.CapsuleBottomCenter, colliderDrawInfo.Radius);
|
||||
break;
|
||||
default:
|
||||
Debug.LogWarning($"HitboxType {colliderDrawInfo.Type} not supported to draw.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Gizmos.matrix = Matrix4x4.identity;
|
||||
}
|
||||
|
||||
private void RenderBHVBroadphase()
|
||||
{
|
||||
var initialColor = Color.green;
|
||||
|
||||
foreach (var nodeDrawInfo in _runner.LagCompensation.DrawInfo.BVHDraw) {
|
||||
Gizmos.color = initialColor + Color.red * nodeDrawInfo.Depth / nodeDrawInfo.MaxDepth;
|
||||
Gizmos.DrawWireCube(nodeDrawInfo.Bounds.center, nodeDrawInfo.Bounds.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7551cd937fd7ae84eb38a9dbbcd67c6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,245 @@
|
||||
|
||||
namespace Fusion {
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Fusion.Analyzer;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Flags a MonoBehaviour class as a RunnerVisibilityControl recognized type.
|
||||
/// Will be included in runner visibility handling, and will be found by <see cref="EnableOnSingleRunner"/> component finds.
|
||||
/// </summary>
|
||||
public interface IRunnerVisibilityRecognizedType {
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies visible/audible components (such as renderers, canvases, lights) that should be enabled/disabled by runner visibility handling.
|
||||
/// Automatically added to scene objects and spawned objects during play if running in <see cref="NetworkProjectConfig.PeerModes.Multiple"/>.
|
||||
/// Additionally this component can be added manually at development time to identify specific Behaviours or Renderers you would like to restrict to one enabled copy at a time.
|
||||
/// </summary>
|
||||
[AddComponentMenu("")]
|
||||
public sealed class RunnerVisibilityLink : MonoBehaviour {
|
||||
|
||||
/// <summary>
|
||||
/// The peer runner that will be used if more than one runner is visible, and this node was manually added by developer (indicating only one instance should be visible at a time).
|
||||
/// </summary>
|
||||
public enum PreferredRunners {
|
||||
/// <summary>
|
||||
/// The first visible runner will be used.
|
||||
/// </summary>
|
||||
Auto,
|
||||
/// <summary>
|
||||
/// The server peer/runner will be used if visible.
|
||||
/// </summary>
|
||||
Server,
|
||||
/// <summary>
|
||||
/// The first client peer/runner will be used if visible.
|
||||
/// </summary>
|
||||
Client,
|
||||
/// <summary>
|
||||
/// The components will only be enabled on the instance that has input authority over the NetworkObject. Unlike the other options, this expects a NetworkObject to work and it will search its children and parents for it.
|
||||
/// </summary>
|
||||
InputAuthority,
|
||||
}
|
||||
|
||||
private enum ComponentType {
|
||||
None,
|
||||
Renderer,
|
||||
Behaviour
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If more than one runner instance is visible, this indicates which peer's clone of this entity should be visible.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
#pragma warning disable IDE0044 // Add readonly modifier
|
||||
public PreferredRunners PreferredRunner;
|
||||
#pragma warning restore IDE0044 // Add readonly modifier
|
||||
|
||||
/// <summary>
|
||||
/// The associated component with this node. This Behaviour or Renderer will be enabled/disabled when its NetworkRunner.IsVisible value is changed.
|
||||
/// </summary>
|
||||
public Component Component;
|
||||
|
||||
public bool IsOnSingleRunner { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Guid is used for common objects (user flagged components that should only run in one instance), to identify matching clones.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
[ReadOnly]
|
||||
internal string Guid;
|
||||
|
||||
// TODO: This can be removed later. Here for backwards compat for the short term as users may still be using this component.
|
||||
// Ultimately this component will always be invisible.
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
internal bool _showAtRuntime;
|
||||
|
||||
// cached runtime
|
||||
internal NetworkRunner _runner;
|
||||
private ComponentType _componentType;
|
||||
private NetworkObject _networkObject;
|
||||
private bool _originalState;
|
||||
|
||||
/// <summary>
|
||||
/// Set to false to indicate that this object should remain disabled even when <see cref="NetworkRunner.IsVisible"/> is set to true.
|
||||
/// </summary>
|
||||
public bool DefaultState {
|
||||
get {
|
||||
return _originalState;
|
||||
}
|
||||
set {
|
||||
_originalState = value;
|
||||
}
|
||||
}
|
||||
|
||||
// internal LinkedListNode<RunnerVisibilityNode> _node;
|
||||
|
||||
internal bool Enabled {
|
||||
get { return _componentType == ComponentType.Renderer ? (Component as Renderer).enabled : (Component as UnityEngine.Behaviour).enabled; }
|
||||
set {
|
||||
if (Component == null) {
|
||||
return;
|
||||
}
|
||||
if (_componentType == ComponentType.Renderer)
|
||||
(Component as Renderer).enabled = value;
|
||||
else {
|
||||
(Component as UnityEngine.Behaviour).enabled = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: Can be removed most likely now that Node is not user accessible.
|
||||
// Reset finds the first viable component and automatically adds it
|
||||
private void Reset() {
|
||||
_showAtRuntime = true;
|
||||
Guid = System.Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
private bool AssociateComponent(Component component) {
|
||||
Component = component;
|
||||
var type = component.GetType();
|
||||
if (component as Renderer != null) {
|
||||
_componentType = ComponentType.Renderer;
|
||||
return true;
|
||||
} else if (component as UnityEngine.Behaviour != null) {
|
||||
_componentType = ComponentType.Behaviour;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnValidate() {
|
||||
|
||||
if (Component != null) {
|
||||
if (Component.transform != transform) {
|
||||
Debug.LogWarning($"{nameof(RunnerVisibilityLink)} can only be associated with components on the same GameObject.");
|
||||
Component = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (AssociateComponent(Component))
|
||||
return;
|
||||
|
||||
Debug.LogWarning($"{nameof(RunnerVisibilityLink)} can only be associated with Components that can be enabled/disabled.");
|
||||
Component = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake() {
|
||||
// TODO: once deprecated, make this flag always the case and remove the bool check.
|
||||
if (!_showAtRuntime)
|
||||
this.hideFlags = HideFlags.HideInInspector;
|
||||
}
|
||||
|
||||
private void OnDestroy() {
|
||||
this.UnregisterNode();
|
||||
}
|
||||
|
||||
internal void Initialize(UnityEngine.Component comp, NetworkRunner runner) {
|
||||
_runner = runner;
|
||||
|
||||
// First look into children
|
||||
_networkObject = GetComponentInChildren<NetworkObject>();
|
||||
if (!_networkObject)
|
||||
_networkObject = GetComponentInParent<NetworkObject>();
|
||||
|
||||
if (!_networkObject && PreferredRunner == PreferredRunners.InputAuthority)
|
||||
Log.Warn($"No NetworkObject found for RunnerVisibilityLink on {gameObject.name} with preferred runner as Input Authority. EnableOnSingleRunner will always disable it.");
|
||||
|
||||
if (comp is Renderer renderer) {
|
||||
_componentType = ComponentType.Renderer;
|
||||
_originalState = renderer.enabled;
|
||||
renderer.enabled = runner.GetVisible() && _originalState;
|
||||
//_node = node;
|
||||
Component = comp;
|
||||
} else if (comp is UnityEngine.Behaviour behaviour) {
|
||||
_componentType = ComponentType.Behaviour;
|
||||
_originalState = behaviour.enabled;
|
||||
behaviour.enabled = runner.GetVisible() && _originalState;
|
||||
// _node = node;
|
||||
Component = comp;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the visibility state of this node.
|
||||
/// </summary>
|
||||
/// <param name="enabled"></param>
|
||||
public void SetEnabled(bool enabled) {
|
||||
if (enabled) {
|
||||
|
||||
// If this object was originally disabled, we will want to keep it that way, unless it looks like the user enabled the object directly since the last time this was called.
|
||||
if (_originalState == false) {
|
||||
|
||||
// TODO: These only partially work
|
||||
// User has directly enabled this object - assume it is meant to be enabled
|
||||
if (Enabled) {
|
||||
_originalState = true;
|
||||
} else {
|
||||
// original state was disabled, so leave it that way.
|
||||
return;
|
||||
}
|
||||
}
|
||||
Enabled = true;
|
||||
|
||||
} else {
|
||||
|
||||
// TODO: These only partially work
|
||||
// Detect/store if user has manually disabled the component
|
||||
//if (_originalState == true && Enabled == false) {
|
||||
// _originalState = false;
|
||||
//}
|
||||
|
||||
Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsInputAuth() {
|
||||
if (_networkObject && _networkObject.IsValid) {
|
||||
return _networkObject.HasInputAuthority;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void SetupOnSingleRunnerLink(PreferredRunners preferredRunner) {
|
||||
PreferredRunner = preferredRunner;
|
||||
IsOnSingleRunner = true;
|
||||
}
|
||||
|
||||
internal void InvokeRefreshCommonObjectVisibilities(float time) {
|
||||
StopAllCoroutines();
|
||||
Invoke(nameof(RetryRefreshCommonLinks), time);
|
||||
}
|
||||
|
||||
private void RetryRefreshCommonLinks() {
|
||||
NetworkRunnerVisibilityExtensions.RetryRefreshCommonLinks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 972a7cfee50c64022a98777550cfb7d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
namespace Fusion {
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Flag component which indicates a NetworkObject has already been factored into a Runner's VisibilityNode list.
|
||||
/// </summary>
|
||||
[AddComponentMenu("")]
|
||||
internal class RunnerVisibilityLinksRoot : MonoBehaviour {
|
||||
private void Awake() {
|
||||
this.hideFlags = HideFlags.HideInInspector;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c370cac09f73d42fab172498cc96e499
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||