460 lines
18 KiB
C#
460 lines
18 KiB
C#
using BNG;
|
|
using Fusion.Sockets;
|
|
using Fusion.XR.Host.Rig;
|
|
using Photon.Realtime;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Security.Policy;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.UI;
|
|
using static Unity.Collections.Unicode;
|
|
|
|
namespace Fusion.Addons.ConnectionManagerAddon
|
|
{
|
|
/**
|
|
*
|
|
* Handles:
|
|
* - connection launch (either with room name or matchmaking session properties)
|
|
* - user representation spawn on connection
|
|
**/
|
|
public class ConnectionManager : MonoBehaviour, INetworkRunnerCallbacks
|
|
{
|
|
public GameObject[] chairs;
|
|
public bool presentation;
|
|
public GameObject Loading;
|
|
[System.Flags]
|
|
public enum ConnectionCriterias
|
|
{
|
|
RoomName = 1,
|
|
SessionProperties = 2
|
|
}
|
|
public Transform itemPos;
|
|
[System.Serializable]
|
|
public struct StringSessionProperty
|
|
{
|
|
public string propertyName;
|
|
public string value;
|
|
}
|
|
public void Update()
|
|
{
|
|
if (Application.loadedLevelName.Equals("Lobby"))
|
|
Destroy(gameObject);
|
|
if (Input.GetKeyDown(KeyCode.I))
|
|
{
|
|
FusionRig.instance.transform.position = usersPlace[0].transform.position;
|
|
}
|
|
if (runner.IsConnectedToServer&&presentation&&!PlayerTeleport.instance.chair&&runner.LocalPlayer.PlayerId>1)
|
|
{
|
|
chairs[runner.LocalPlayer.PlayerId].GetComponent<Chair>().SetSit();
|
|
|
|
}
|
|
Loading.gameObject.SetActive(!runner||! runner.IsConnectedToServer);
|
|
}
|
|
[Header("Room configuration")]
|
|
public GameMode gameMode = GameMode.Shared;
|
|
public string roomName = "SampleFusion";
|
|
public bool connectOnStart = true;
|
|
[Tooltip("Set it to 0 to use the DefaultPlayers value, from the Global NetworkProjectConfig (simulation section)")]
|
|
public int playerCount = 0;
|
|
public static ConnectionManager instance;
|
|
[Header("Room selection criteria")]
|
|
public ConnectionCriterias connectionCriterias = ConnectionCriterias.RoomName;
|
|
[Tooltip("If connectionCriterias include SessionProperties, additionalSessionProperties (editable in the inspector) will be added to sessionProperties")]
|
|
public List<StringSessionProperty> additionalSessionProperties = new List<StringSessionProperty>();
|
|
public Dictionary<string, SessionProperty> sessionProperties;
|
|
|
|
[Header("Fusion settings")]
|
|
[Tooltip("Fusion runner. Automatically created if not set")]
|
|
public NetworkRunner runner;
|
|
public INetworkSceneManager sceneManager;
|
|
|
|
//[Header("Local user spawner")]
|
|
// public NetworkObject userPrefab;
|
|
public NetworkObject whiteboardPrefab;
|
|
|
|
[Header("Event")]
|
|
public UnityEvent onWillConnect = new UnityEvent();
|
|
|
|
[Header("Info")]
|
|
public List<StringSessionProperty> actualSessionProperties = new List<StringSessionProperty>();
|
|
|
|
// Dictionary of spawned user prefabs, to store them on the server for host topology, and destroy them on disconnection (for shared topology, use Network Objects's "Destroy When State Authority Leaves" option)
|
|
private Dictionary<PlayerRef, NetworkObject> _spawnedUsers = new Dictionary<PlayerRef, NetworkObject>();
|
|
|
|
bool ShouldConnectWithRoomName => (connectionCriterias & ConnectionManager.ConnectionCriterias.RoomName) != 0;
|
|
bool ShouldConnectWithSessionProperties => (connectionCriterias & ConnectionManager.ConnectionCriterias.SessionProperties) != 0;
|
|
|
|
private void Awake()
|
|
{
|
|
if (!EN.instance)
|
|
{
|
|
|
|
//Application.LoadLevel(0);
|
|
Destroy(gameObject);
|
|
return;
|
|
}
|
|
// Check if a runner exist on the same game object
|
|
if (runner == null) runner = GetComponent<NetworkRunner>();
|
|
instance = this;
|
|
// Create the Fusion runner and let it know that we will be providing user input
|
|
if (runner == null) runner = gameObject.AddComponent<NetworkRunner>();
|
|
runner.ProvideInput = true;
|
|
|
|
}
|
|
public void createChairs()
|
|
{
|
|
for (int i = 0; i < chairs.Length; i++)
|
|
{
|
|
chairs[i].GetComponent<Chair>().enabled = true;
|
|
chairs[i].GetComponentInChildren<VRCanvas>().enabled = true;
|
|
}
|
|
}
|
|
|
|
private async void Start()
|
|
{
|
|
chairs = GameObject.FindGameObjectsWithTag("chair");
|
|
//Invoke("createChairs", 5);
|
|
PlaySound("intro");
|
|
// Launch the connection at start
|
|
if (connectOnStart) await Connect();
|
|
|
|
}
|
|
|
|
Dictionary<string, SessionProperty> AllConnectionSessionProperties
|
|
{
|
|
get
|
|
{
|
|
var propDict = new Dictionary<string, SessionProperty>();
|
|
actualSessionProperties = new List<StringSessionProperty>();
|
|
if (sessionProperties != null)
|
|
{
|
|
foreach (var prop in sessionProperties)
|
|
{
|
|
propDict.Add(prop.Key, prop.Value);
|
|
actualSessionProperties.Add(new StringSessionProperty { propertyName = prop.Key, value = prop.Value });
|
|
}
|
|
}
|
|
if (additionalSessionProperties != null)
|
|
{
|
|
foreach (var additionalProperty in additionalSessionProperties)
|
|
{
|
|
propDict[additionalProperty.propertyName] = additionalProperty.value;
|
|
actualSessionProperties.Add(additionalProperty);
|
|
}
|
|
|
|
}
|
|
return propDict;
|
|
}
|
|
}
|
|
public Transform pos;
|
|
public virtual NetworkSceneInfo CurrentSceneInfo()
|
|
{
|
|
var activeScene = SceneManager.GetActiveScene();
|
|
SceneRef sceneRef = default;
|
|
|
|
if (activeScene.buildIndex < 0 || activeScene.buildIndex >= SceneManager.sceneCountInBuildSettings)
|
|
{
|
|
Debug.LogError("Current scene is not part of the build settings");
|
|
}
|
|
else
|
|
{
|
|
sceneRef = SceneRef.FromIndex(activeScene.buildIndex);
|
|
}
|
|
|
|
var sceneInfo = new NetworkSceneInfo();
|
|
if (sceneRef.IsValid)
|
|
{
|
|
sceneInfo.AddSceneRef(sceneRef, LoadSceneMode.Single);
|
|
}
|
|
return sceneInfo;
|
|
}
|
|
|
|
public async Task Connect()
|
|
{
|
|
// Create the scene manager if it does not exist
|
|
if (sceneManager == null) sceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>();
|
|
if (onWillConnect != null) onWillConnect.Invoke();
|
|
|
|
// Start or join (depends on gamemode) a session with a specific name
|
|
var args = new StartGameArgs()
|
|
{
|
|
GameMode = gameMode,
|
|
Scene = CurrentSceneInfo(),
|
|
SceneManager = sceneManager
|
|
};
|
|
// Connection criteria
|
|
if (ShouldConnectWithRoomName)
|
|
{
|
|
args.SessionName = roomName;
|
|
}
|
|
if (ShouldConnectWithSessionProperties)
|
|
{
|
|
args.SessionProperties = AllConnectionSessionProperties;
|
|
}
|
|
// Room details
|
|
if (playerCount > 0)
|
|
{
|
|
args.PlayerCount = playerCount;
|
|
}
|
|
|
|
await runner.StartGame(args);
|
|
|
|
string prop = "";
|
|
if (runner.SessionInfo.Properties != null && runner.SessionInfo.Properties.Count > 0)
|
|
{
|
|
prop = "SessionProperties: ";
|
|
foreach (var p in runner.SessionInfo.Properties) prop += $" ({p.Key}={p.Value.PropertyValue}) ";
|
|
}
|
|
Debug.Log($"Session info: Room name {runner.SessionInfo.Name}. Region: {runner.SessionInfo.Region}. {prop}");
|
|
if ((connectionCriterias & ConnectionManager.ConnectionCriterias.RoomName) == 0)
|
|
{
|
|
roomName = runner.SessionInfo.Name;
|
|
}
|
|
}
|
|
|
|
#region Player spawn
|
|
public void OnPlayerJoinedSharedMode(NetworkRunner runner, PlayerRef player)
|
|
{
|
|
if (player == runner.LocalPlayer)
|
|
{
|
|
// Spawn the user prefab for the local user
|
|
// pos.transform.position = usersPlace[runner.SessionInfo.PlayerCount - 1].transform.position;
|
|
// NetworkObject networkPlayerObject = runner.Spawn(EN.instance.SelectedUser.character, position: pos.transform.position, rotation: transform.rotation, player, (runner, obj) => {
|
|
// });
|
|
|
|
}
|
|
}
|
|
NetworkObject laser,marker, tablet;
|
|
public NetworkObject Marker;
|
|
public NetworkObject Tablet;
|
|
public NetworkObject Laser;
|
|
public NetworkObject spark;
|
|
|
|
internal void CreateTablet(Transform trans)
|
|
{
|
|
if (tablet)
|
|
runner.Despawn(tablet);
|
|
// if (marker)
|
|
// runner.Despawn(marker);
|
|
//if (marker)
|
|
// runner.Despawn(marker);
|
|
|
|
//if (laser)
|
|
// runner.Despawn(laser);
|
|
tablet = runner.Spawn(Tablet, position: itemPos.position, rotation: itemPos.rotation, inputAuthority: runner.LocalPlayer, (runner, obj) => {
|
|
// obj.GetComponent<MarkerNetwork>().DrawColor = color;
|
|
|
|
|
|
});
|
|
}
|
|
internal void CreateLaser(Transform trans)
|
|
{
|
|
//if (ereaser)
|
|
// runner.Despawn(ereaser);
|
|
//if (marker)
|
|
// runner.Despawn(marker);
|
|
if (laser)
|
|
runner.Despawn(laser);
|
|
laser = runner.Spawn(Laser, position: (trans.transform.position + new Vector3(0, 0, .0f)), rotation: trans.rotation, inputAuthority: runner.LocalPlayer, (runner, obj) => {
|
|
// obj.GetComponent<MarkerNetwork>().DrawColor = color;
|
|
|
|
|
|
});
|
|
} internal void CreateSpark(NetworkObject item,Transform trans)
|
|
{
|
|
//if (ereaser)
|
|
// runner.Despawn(ereaser);
|
|
//if (marker)
|
|
// runner.Despawn(marker);
|
|
if (spark)
|
|
runner.Despawn(spark);
|
|
spark = runner.Spawn(item, position: (trans.transform.position + new Vector3(0, 0, .0f)), rotation: trans.rotation, inputAuthority: runner.LocalPlayer, (runner, obj) => {
|
|
// obj.GetComponent<MarkerNetwork>().DrawColor = color;
|
|
|
|
|
|
});
|
|
}
|
|
internal void CreateImage(Transform trans, NetworkObject obj,string url)
|
|
{
|
|
|
|
runner.Spawn(obj, position: (trans.transform.position + new Vector3(0, 0, .0f)), rotation: trans.rotation, inputAuthority: runner.LocalPlayer, (runner, obj) => {
|
|
|
|
obj.GetComponent<ImagePlayer>().Show(url);
|
|
});
|
|
}
|
|
internal void CreateVideo(Transform trans, NetworkObject obj,string url)
|
|
{
|
|
|
|
runner.Spawn(obj, position: (trans.transform.position + new Vector3(0, 0, .0f)), rotation: trans.rotation, inputAuthority: runner.LocalPlayer, (runner, obj) => {
|
|
|
|
obj.GetComponent<VideoPlayerManager>().Show(url);
|
|
});
|
|
}
|
|
|
|
internal void CreateMarker(Transform trans, Color color)
|
|
{
|
|
if (marker)
|
|
runner.Despawn(marker);
|
|
|
|
marker = runner.Spawn(Marker, position: (trans.transform.position + new Vector3(0, 0, .0f)), rotation: trans.rotation, inputAuthority: runner.LocalPlayer, (runner, obj) => {
|
|
obj.GetComponent<MarkerNetwork>().DrawColor = color;
|
|
|
|
|
|
});
|
|
}
|
|
public NetworkObject networkPlayerObject;
|
|
public void OnPlayerJoinedHostMode(NetworkRunner runner, PlayerRef player)
|
|
{
|
|
if (player != runner.LocalPlayer)
|
|
return;
|
|
// The user's prefab has to be spawned by the host
|
|
pos.transform.position = usersPlace[runner.SessionInfo.PlayerCount - 1].transform.position;
|
|
// We make sure to give the input authority to the connecting player for their user's object
|
|
|
|
if ( EN.instance.SelectedUser.character != null)
|
|
{
|
|
Debug.Log($"OnPlayerJoined. PlayerId: {player.PlayerId}" + usersPlace[runner.SessionInfo.PlayerCount - 1].transform.position.ToString());
|
|
|
|
networkPlayerObject = runner.Spawn(EN.instance.Me.character, position: pos.position, rotation: transform.rotation, inputAuthority: player, (runner, obj) => {
|
|
|
|
obj.GetComponent<playerManager>().player = player;
|
|
// obj.GetComponent<playerManager>().RPC_RequestCharacterSpawn(player);
|
|
});
|
|
|
|
|
|
// Keep track of the player avatars so we can remove it when they disconnect
|
|
_spawnedUsers.Add(player, networkPlayerObject);
|
|
}
|
|
if (player.PlayerId == runner.LocalPlayer.PlayerId)
|
|
FusionRig.instance.transform.position = pos.position;
|
|
}
|
|
|
|
// Despawn the user object upon disconnection
|
|
public void OnPlayerLeftHostMode(NetworkRunner runner, PlayerRef player)
|
|
{
|
|
// Find and remove the players avatar (only the host would have stored the spawned game object)
|
|
if (_spawnedUsers.TryGetValue(player, out NetworkObject networkObject))
|
|
{
|
|
runner.Despawn(networkObject);
|
|
_spawnedUsers.Remove(player);
|
|
}
|
|
}
|
|
// public GameObject[] users;
|
|
#endregion
|
|
|
|
#region INetworkRunnerCallbacks
|
|
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
|
|
{
|
|
print(player.PlayerId + "==" + runner.LocalPlayer.PlayerId + "," + runner.SessionInfo.PlayerCount);
|
|
// if ((runner.SessionInfo.PlayerCount == 1) && player.PlayerId == runner.LocalPlayer.PlayerId)
|
|
// whiteboard = runner.Spawn(whiteboardPrefab, position: wbPostion.position,
|
|
// rotation: wbPostion.rotation);
|
|
// if (runner.Topology == Topologies.ClientServer)
|
|
{
|
|
OnPlayerJoinedHostMode(runner, player);
|
|
}
|
|
// else
|
|
{
|
|
|
|
// OnPlayerJoinedSharedMode(runner, player);
|
|
}
|
|
}
|
|
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
|
|
{
|
|
if (runner.Topology == Topologies.ClientServer)
|
|
{
|
|
OnPlayerLeftHostMode(runner, player);
|
|
}
|
|
}
|
|
NetworkObject whiteboard;
|
|
public Transform wbPostion;
|
|
public Transform[] usersPlace;
|
|
#endregion
|
|
|
|
#region INetworkRunnerCallbacks (debug log only)
|
|
public void OnConnectedToServer(NetworkRunner runner)
|
|
{
|
|
Debug.Log("OnConnectedToServer:" + runner.IsServer);
|
|
|
|
|
|
}
|
|
public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason)
|
|
{
|
|
Debug.Log("Shutdown: " + shutdownReason);
|
|
//Application.LoadLevel(0);
|
|
}
|
|
public void OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason)
|
|
{
|
|
Debug.Log("OnDisconnectedFromServer: " + reason);
|
|
Application.LoadLevel(0);
|
|
|
|
}
|
|
public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason)
|
|
{
|
|
Debug.Log("OnConnectFailed: " + reason);
|
|
Application.LoadLevel(0);
|
|
}
|
|
#endregion
|
|
|
|
#region Unused INetworkRunnerCallbacks
|
|
|
|
public void OnInput(NetworkRunner runner, NetworkInput input) { }
|
|
public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { }
|
|
public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { }
|
|
public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { }
|
|
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList) { }
|
|
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
|
|
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
|
|
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ArraySegment<byte> data) { }
|
|
public void OnSceneLoadDone(NetworkRunner runner) { }
|
|
public void OnSceneLoadStart(NetworkRunner runner) { }
|
|
public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
|
|
public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
|
|
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment<byte> data) { }
|
|
public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress) { }
|
|
|
|
|
|
#endregion
|
|
|
|
public void PlaySound(string soundName,float volume=1f)
|
|
{
|
|
// بارگذاری صدا از پوشه Resources
|
|
AudioClip clip = Resources.Load<AudioClip>("sounds/" + soundName);
|
|
|
|
if (clip != null)
|
|
{
|
|
// ایجاد یک GameObject جدید برای پخش صدا
|
|
GameObject audioObject = new GameObject("AudioSource_" + soundName);
|
|
|
|
AudioSource audioSource = audioObject.AddComponent<AudioSource>();
|
|
audioSource.volume = volume;
|
|
audioSource.spatialBlend = 1;
|
|
|
|
// تنظیم clip و پخش صدا
|
|
audioSource.clip = clip;
|
|
audioSource.Play();
|
|
|
|
// حذف GameObject بعد از پایان صدا
|
|
Destroy(audioObject, clip.length);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("Sound not found: " + soundName);
|
|
}
|
|
}
|
|
|
|
internal void CreateImage(Transform trans, NetworkObject obj, RawImage rawImage)
|
|
{
|
|
runner.Spawn(obj, position: (trans.transform.position + new Vector3(0, 0, .0f)), rotation: trans.rotation, inputAuthority: runner.LocalPlayer, (runner, obj) => {
|
|
|
|
obj.GetComponent<ImagePlayer>().Show(rawImage);
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
}
|