TouhouLS/TouhouStation/Assets/Code/Networking/NetworkManager.cs

314 lines
8.1 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ExitGames.Client.Photon.LoadBalancing;
using ExitGames.Client.Photon;
using Hashtable = ExitGames.Client.Photon.Hashtable;
public class NetworkManager : MonoBehaviour {
#region Inspector
public string serverAddress, appID, gameVersion;
[Header("Debug")]
public ParticleSystem NetworkDebugParticles;
public bool quickLoadTestingLobby;
public bool expectedOnline = false;
public byte expectedMaxPlayers = 2;
#endregion
#region Particles
public static bool visParticles = true;
// Spawn a particle on an entity, used for visualizing updates
public static void netParticle(EntityBase eb, Color pColor) {
if (!visParticles) return;
if (instance.NetworkDebugParticles) {
var pparams = new ParticleSystem.EmitParams();
pparams.position = eb.transform.position;
pparams.startColor = pColor;
instance.NetworkDebugParticles.Emit(pparams, 1);
}
}
#endregion
#region Network Helpers
public static NetLogic net { get; private set; }
// A time value that is 'approximately' (+/- 10ms most of the time) synced across clients
public static double ServerTime {
get {
if (net == null || net.loadBalancingPeer == null)
return Time.realtimeSinceStartup;
return net.loadBalancingPeer.ServerTimeInMilliSeconds * (1d/1000d);
}
}
public static float ServerTimeFloat {
get {
if (net == null || net.loadBalancingPeer == null)
return Time.realtimeSinceStartup;
return net.loadBalancingPeer.ServerTimeInMilliSeconds * (1f / 1000f);
}
}
/// <summary>
/// On non WebSocketSecure platforms, encryption handshake must occur before opCustom can be sent.
/// This is important in cases such as getting the room or region list.
/// </summary>
public static bool delayForEncrypt {
get {
// We use secure websockets in UnityGL, so no encrypt handshake needs to occur
#if UNITY_WEBGL
return true;
#else
return !net.loadBalancingPeer.IsEncryptionAvailable;
#endif
}
}
/// <summary>
/// Returns true if able to send network connections.
/// </summary>
public static bool isReady {
get {
if (net == null) return false;
return net.IsConnectedAndReady;
}
}
/// <summary>
/// If this client is considered owner of the room.
/// </summary>
public static bool isMaster {
get {
// If have no networking, we're the owner.
if (net == null) return true;
if (!inRoom) return true;
return net.LocalPlayer.IsMasterClient;
}
}
public static bool isMasterID(int authorityID){
if (net == null) return true;
if (!inRoom) return true;
return net.CurrentRoom.MasterClientId == authorityID;
}
/// <summary>
/// Boolean for if we are on the name server. Used for awaiting the name server connection.
/// Can be set to true to connect to name server.
/// </summary>
/// <value><c>true</c> if on name server; otherwise, <c>false</c>.</value>//
public static bool onNameServer {
get {
if (net == null) return false;
return net.State.Equals(ClientState.ConnectedToNameServer);
} set {
if (value) net.ConnectToNameServer();
}
}
/// <summary>
/// Boolean to check if the network is in the master lobby, will be true after we've found a region.
/// </summary>
/// <value><c>true</c> if on master lobby; otherwise, <c>false</c>.</value>
public static bool onMasterLobby {
get {
if (net == null) return false;
return net.State.Equals(ClientState.JoinedLobby);
}
}
/// <summary>
/// Boolean to check if we're in a room or not.
/// </summary>
/// <value><c>true</c> if in room; otherwise, <c>false</c>.</value>
public static bool inRoom{
get {
if (net == null) return false;
return net.State.Equals(ClientState.Joined);
}
}
public static bool expectedState{
get {
if (instance.expectedOnline){
if (net != null && net.State.Equals(ClientState.Joined)){
return net.CurrentRoom.PlayerCount == instance.expectedMaxPlayers;
}
return false;
}
return true;
}
}
/// <summary>
/// Enqueue a network update to be sent. Network events are processed both on Update and LateUpdate timings.
/// </summary>
public static bool netMessage(byte eventCode, object eventContent, bool sendReliable = false, RaiseEventOptions options = null) {
if (!inRoom || !isReady) return false; // Only actually send messages when in game and ready
if (options == null) options = RaiseEventOptions.Default;
return net.OpRaiseEvent(eventCode, eventContent, sendReliable, options);
}
/// <summary>
/// Get the local player id. if isOnline isn't true, this will be -1
/// </summary>
public static int localID {
get {
if (net == null) return 0;
return net.LocalPlayer.ID;
}
}
#endregion
public static event System.Action<EventData> netHook;
public static event System.Action<EventData> onLeave;
public static event System.Action<EventData> onJoin;
private static NetworkManager _instance;
public static NetworkManager instance {
get {
if (_instance) return _instance;
_instance = FindObjectOfType<NetworkManager>();
if (_instance) return _instance;
throw new System.Exception("Network manager not instanced in scene");
}
set {
_instance = value;
}
}
public void Awake() {
if (_instance != null) {
Destroy(gameObject);
return;
}
Debug.Log("Aweake");
instance = this;
DontDestroyOnLoad(gameObject);
// Initialize network
net = new NetLogic();
}
void OnDestroy() {
if (net == null) return;
// Only do service
if (_instance == this) {
net.Service(); // Service before disconnect to clear any blockers
net.Disconnect();
}
}
void Update() {
net.Service();
}
void LateUpdate () {
net.Service();
}
public class NetLogic : LoadBalancingClient {
public NetLogic() {
// Setup and launch network service
AppId = NetworkManager.instance.appID;
AppVersion = NetworkManager.instance.gameVersion;
AutoJoinLobby = true;
// Register custom type handlers
StreamCustomTypes.Register();
// TDCustomTypes.Register();
// StreamINightTypes.Register(); // Specific to Impurrishable Night
#if UNITY_WEBGL
Debug.Log("Using secure websockets");
this.TransportProtocol = ConnectionProtocol.WebSocketSecure;
#endif
}
public event System.Action GamelistRefresh;
public override void OnEvent(EventData photonEvent) {
base.OnEvent(photonEvent);
switch(photonEvent.Code) {
case EventCode.GameList:
case EventCode.GameListUpdate:
Debug.Log("Server List recieved");
if (GamelistRefresh != null) GamelistRefresh();
break;
case EventCode.Join:
if (onJoin != null)
onJoin(photonEvent);
break;
case EventCode.Leave:
if (onLeave != null)
onLeave(photonEvent);
break;
}
if (netHook != null)
netHook(photonEvent);
}
/// <summary>
/// Joins a specific room by name. If the room doesn't exist (yet), it will be created implicitiy.
/// Creates custom properties automatically for the room.
/// </summary>
/// <param name="roomName"></param>
/// <param name="options"></param>
/// <param name="lobby"></param>
/// <param name="startingScene"></param>
/// <returns></returns>
public bool OpJoinOrCreateRoomWithProperties(string roomName, RoomOptions options, TypedLobby lobby, string startingScene = "lobby") {
PlayerProperties.CreatePlayerHashtable();
options.CustomRoomProperties = RoomProperties.CreateRoomHashtable();
return OpJoinOrCreateRoom(roomName, options, lobby);
}
public bool OpCreateRoomWithProperties(string roomName, RoomOptions options, TypedLobby lobby, string startingScene = "lobby") {
PlayerProperties.CreatePlayerHashtable();
options.CustomRoomProperties = RoomProperties.CreateRoomHashtable();
return OpCreateRoom(roomName, options, lobby);
}
public bool OpJoinRoomWithProperties(string roomName) {
PlayerProperties.CreatePlayerHashtable();
return OpJoinRoom(roomName);
}
}
}