quantum-space-buddies/QSB/QSBNetworkManager.cs
2021-11-11 19:34:25 +00:00

305 lines
9.4 KiB
C#

using OWML.Common;
using OWML.Utils;
using QSB.Animation.Player;
using QSB.Animation.Player.Thrusters;
using QSB.ClientServerStateSync;
using QSB.DeathSync;
using QSB.Events;
using QSB.Instruments;
using QSB.OrbSync.TransformSync;
using QSB.Patches;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.PoolSync;
using QSB.ShipSync.TransformSync;
using QSB.Anglerfish.TransformSync;
using QSB.TimeSync;
using QSB.Tools.ProbeTool.TransformSync;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using QuantumUNET.Components;
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB
{
public class QSBNetworkManager : QNetworkManager
{
public static QSBNetworkManager Instance { get; private set; }
public event Action OnNetworkManagerReady;
public event Action OnClientConnected;
public event Action<NetworkError> OnClientDisconnected;
public event Action<NetworkError> OnClientErrorThrown;
public bool IsReady { get; private set; }
public GameObject OrbPrefab { get; private set; }
public GameObject ShipPrefab { get; private set; }
public GameObject AnglerPrefab { get; private set; }
public string PlayerName { get; private set; }
private const int MaxConnections = 128;
private const int MaxBufferedPackets = 64;
private AssetBundle _assetBundle;
private GameObject _probePrefab;
private bool _everConnected;
public new void Awake()
{
base.Awake();
Instance = this;
PlayerName = GetPlayerName();
_assetBundle = QSBCore.NetworkAssetBundle;
playerPrefab = _assetBundle.LoadAsset<GameObject>("assets/NETWORK_Player_Body.prefab");
SetupNetworkId(playerPrefab, 1);
SetupNetworkTransform(playerPrefab);
playerPrefab.AddComponent<PlayerTransformSync>();
playerPrefab.AddComponent<AnimationSync>();
playerPrefab.AddComponent<CrouchSync>();
playerPrefab.AddComponent<WakeUpSync>();
playerPrefab.AddComponent<JetpackAccelerationSync>();
playerPrefab.AddComponent<InstrumentsManager>();
ShipPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkship.prefab");
SetupNetworkId(ShipPrefab, 2);
SetupNetworkTransform(ShipPrefab);
ShipPrefab.AddComponent<ShipTransformSync>();
spawnPrefabs.Add(ShipPrefab);
_probePrefab = _assetBundle.LoadAsset<GameObject>("assets/networkprobe.prefab");
SetupNetworkId(_probePrefab, 3);
SetupNetworkTransform(_probePrefab);
_probePrefab.AddComponent<PlayerProbeSync>();
spawnPrefabs.Add(_probePrefab);
OrbPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkorb.prefab");
SetupNetworkId(OrbPrefab, 4);
SetupNetworkTransform(OrbPrefab);
OrbPrefab.AddComponent<NomaiOrbTransformSync>();
spawnPrefabs.Add(OrbPrefab);
AnglerPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkangler.prefab");
SetupNetworkId(AnglerPrefab, 5);
SetupNetworkTransform(AnglerPrefab);
AnglerPrefab.AddComponent<AnglerTransformSync>();
spawnPrefabs.Add(AnglerPrefab);
ConfigureNetworkManager();
}
private string GetPlayerName()
{
try
{
var profileManager = StandaloneProfileManager.SharedInstance;
profileManager.Initialize();
var profile = profileManager._currentProfile;
var profileName = profile.profileName;
return profileName;
}
catch (Exception ex)
{
DebugLog.ToConsole($"Error - Exception when getting player name : {ex}", MessageType.Error);
return "Player";
}
}
private void SetupNetworkId(GameObject go, int assetId)
{
var ident = go.AddComponent<QNetworkIdentity>();
ident.LocalPlayerAuthority = true;
var networkIdentity = go.GetComponent<NetworkIdentity>();
ident.SetValue("m_AssetId", assetId);
ident.SetValue("m_SceneId", networkIdentity.GetComponent<NetworkIdentity>().sceneId);
}
private void SetupNetworkTransform(GameObject go)
{
foreach (var item in go.GetComponents<NetworkTransformChild>())
{
var child = go.AddComponent<QNetworkTransformChild>();
child.Target = item.target;
child.m_ChildIndex = item.childIndex;
Destroy(item);
}
Destroy(go.GetComponent<NetworkTransform>());
Destroy(go.GetComponent<NetworkIdentity>());
}
private void ConfigureNetworkManager()
{
networkAddress = QSBCore.DefaultServerIP;
networkPort = QSBCore.Port;
maxConnections = MaxConnections;
customConfig = true;
connectionConfig.AddChannel(QosType.Reliable);
connectionConfig.AddChannel(QosType.Unreliable);
this.SetValue("m_MaxBufferedPackets", MaxBufferedPackets);
channels.Add(QosType.Reliable);
channels.Add(QosType.Unreliable);
DebugLog.DebugWrite("Network Manager ready.", MessageType.Success);
}
public override void OnStartServer()
{
DebugLog.DebugWrite("OnStartServer", MessageType.Info);
if (QSBWorldSync.OldDialogueTrees.Count == 0 && QSBSceneManager.IsInUniverse)
{
QSBWorldSync.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
}
}
public override void OnServerAddPlayer(QNetworkConnection connection, short playerControllerId) // Called on the server when a client joins
{
DebugLog.DebugWrite($"OnServerAddPlayer {playerControllerId}", MessageType.Info);
base.OnServerAddPlayer(connection, playerControllerId);
QNetworkServer.SpawnWithClientAuthority(Instantiate(_probePrefab), connection);
}
public override void OnStartClient(QNetworkClient _)
{
var config = QSBCore.Helper.Config;
config.SetSettingsValue("defaultServerIP", networkAddress);
QSBCore.Helper.Storage.Save(config, Constants.ModConfigFileName);
}
public override void OnClientError(QNetworkConnection conn, int errorCode)
=> OnClientErrorThrown?.SafeInvoke((NetworkError)errorCode);
public override void OnClientConnect(QNetworkConnection connection) // Called on the client when connecting to a server
{
DebugLog.DebugWrite("OnClientConnect", MessageType.Info);
base.OnClientConnect(connection);
OnClientConnected?.SafeInvoke();
QSBEventManager.Init();
gameObject.AddComponent<RespawnOnDeath>();
gameObject.AddComponent<ServerStateManager>();
gameObject.AddComponent<ClientStateManager>();
if (QSBSceneManager.IsInUniverse)
{
WorldObjectManager.Rebuild(QSBSceneManager.CurrentScene);
}
var specificType = QNetworkServer.active ? QSBPatchTypes.OnServerClientConnect : QSBPatchTypes.OnNonServerClientConnect;
QSBPatchManager.DoPatchType(specificType);
QSBPatchManager.DoPatchType(QSBPatchTypes.OnClientConnect);
OnNetworkManagerReady?.SafeInvoke();
IsReady = true;
QSBCore.UnityEvents.RunWhen(() => QSBEventManager.Ready && PlayerTransformSync.LocalInstance != null,
() => QSBEventManager.FireEvent(EventNames.QSBPlayerJoin, PlayerName));
if (!QSBCore.IsHost)
{
QSBCore.UnityEvents.RunWhen(() => QSBEventManager.Ready && PlayerTransformSync.LocalInstance != null,
() => QSBEventManager.FireEvent(EventNames.QSBRequestStateResync));
}
_everConnected = true;
}
public override void OnStopClient() // Called on the client when closing connection
{
DebugLog.DebugWrite("OnStopClient", MessageType.Info);
DebugLog.ToConsole("Disconnecting from server...", MessageType.Info);
Destroy(GetComponent<RespawnOnDeath>());
Destroy(GetComponent<ServerStateManager>());
Destroy(GetComponent<ClientStateManager>());
QSBEventManager.Reset();
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
RemoveWorldObjects();
NomaiOrbTransformSync.OrbTransformSyncs.Clear();
QSBWorldSync.OldDialogueTrees.Clear();
if (WakeUpSync.LocalInstance != null)
{
WakeUpSync.LocalInstance.OnDisconnect();
}
if (_everConnected)
{
var specificType = QNetworkServer.active ? QSBPatchTypes.OnServerClientConnect : QSBPatchTypes.OnNonServerClientConnect;
QSBPatchManager.DoUnpatchType(specificType);
QSBPatchManager.DoUnpatchType(QSBPatchTypes.OnClientConnect);
}
IsReady = false;
_everConnected = false;
}
public override void OnClientDisconnect(QNetworkConnection conn)
{
base.OnClientDisconnect(conn);
OnClientDisconnected?.SafeInvoke(conn.LastError);
}
public override void OnServerDisconnect(QNetworkConnection connection) // Called on the server when any client disconnects
{
base.OnServerDisconnect(connection);
DebugLog.DebugWrite("OnServerDisconnect", MessageType.Info);
foreach (var item in NomaiOrbTransformSync.OrbTransformSyncs)
{
if (item is null)
{
continue;
}
var identity = item.GetComponent<QNetworkIdentity>();
if (identity.ClientAuthorityOwner == connection)
{
identity.RemoveClientAuthority(connection);
}
}
}
public override void OnStopServer()
{
DebugLog.DebugWrite("OnStopServer", MessageType.Info);
Destroy(GetComponent<RespawnOnDeath>());
QSBEventManager.Reset();
DebugLog.ToConsole("Server stopped!", MessageType.Info);
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
base.OnStopServer();
}
private void RemoveWorldObjects()
{
QSBWorldSync.RemoveWorldObjects<IWorldObjectTypeSubset>();
QSBWorldSync.RemoveWorldObjects<IWorldObject>();
foreach (var platform in Resources.FindObjectsOfTypeAll<CustomNomaiRemoteCameraPlatform>())
{
Destroy(platform);
}
foreach (var camera in Resources.FindObjectsOfTypeAll<CustomNomaiRemoteCamera>())
{
Destroy(camera);
}
foreach (var streaming in Resources.FindObjectsOfTypeAll<CustomNomaiRemoteCameraStreaming>())
{
Destroy(streaming);
}
WorldObjectManager.SetNotReady();
}
}
}