using OWML.Common; using QSB.Events; using QSB.Player; using QSB.QuantumSync.WorldObjects; using QSB.Utility; using QSB.WorldSync; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEngine; namespace QSB.QuantumSync { internal class QuantumManager : WorldObjectManager { public static QuantumShrine Shrine { get; private set; } public static QuantumManager Instance { get; private set; } public override void Awake() { base.Awake(); Instance = this; QSBPlayerManager.OnRemovePlayer += PlayerLeave; } public override void OnDestroy() { base.OnDestroy(); QSBPlayerManager.OnRemovePlayer -= PlayerLeave; } protected override void RebuildWorldObjects(OWScene scene) { DebugLog.DebugWrite("Rebuilding quantum objects...", MessageType.Warning); QSBWorldSync.Init(); QSBWorldSync.Init(); QSBWorldSync.Init(); QSBWorldSync.Init(); QSBWorldSync.Init(); QSBWorldSync.Init(); QSBWorldSync.Init(); if (scene == OWScene.SolarSystem) { Shrine = Resources.FindObjectsOfTypeAll().First(); } } public void PlayerLeave(uint playerId) { if (!QSBCore.IsServer) { return; } var quantumObjects = QSBWorldSync.GetWorldObjects().ToList(); for (var i = 0; i < quantumObjects.Count; i++) { var obj = quantumObjects[i]; if (obj.ControllingPlayer == playerId) { var idToSend = obj.IsEnabled ? QSBPlayerManager.LocalPlayerId : 0u; QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, i, idToSend); } } } public void OnRenderObject() { if (!QSBCore.WorldObjectsReady || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug) { return; } if (Shrine != null) { Popcron.Gizmos.Sphere(Shrine.transform.position, 10f, Color.magenta); } } public static Tuple> IsVisibleUsingCameraFrustum(ShapeVisibilityTracker tracker, bool ignoreLocalCamera) { var playersWithCameras = QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera); if (playersWithCameras.Count == 0) { DebugLog.ToConsole($"Warning - Trying to run IsVisibleUsingCameraFrustum when there are no players!", MessageType.Warning); return new Tuple>(false, null); } if (!tracker.gameObject.activeInHierarchy) { return new Tuple>(false, null); } var frustumMethod = tracker.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance); var playersWhoCanSee = new List(); var foundPlayers = false; foreach (var player in playersWithCameras) { if (player.Camera == null) { DebugLog.ToConsole($"Warning - Camera is null for id:{player.PlayerId}!", MessageType.Warning); continue; } var isInFrustum = (bool)frustumMethod.Invoke(tracker, new object[] { player.Camera.GetFrustumPlanes() }); if (isInFrustum) { playersWhoCanSee.Add(player); foundPlayers = true; } } return new Tuple>(foundPlayers, playersWhoCanSee); } public static bool IsVisible(ShapeVisibilityTracker tracker, bool ignoreLocalCamera) { return tracker.gameObject.activeInHierarchy && IsVisibleUsingCameraFrustum(tracker, ignoreLocalCamera).First && QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera) .Any(x => VisibilityOccluder.CanYouSee(tracker, x.Camera.mainCamera.transform.position)); } public static IEnumerable GetEntangledPlayers(QuantumObject obj) { if (!WorldObjectManager.AllReady) { return Enumerable.Empty(); } var worldObj = GetObject(obj); return QSBPlayerManager.PlayerList.Where(x => x.EntangledObject == worldObj); } public static IQSBQuantumObject GetObject(QuantumObject unityObject) { IQSBQuantumObject worldObj = null; if (unityObject.GetType() == typeof(SocketedQuantumObject) || unityObject.GetType() == typeof(QuantumShrine)) { worldObj = QSBWorldSync.GetWorldFromUnity((SocketedQuantumObject)unityObject); } else if (unityObject.GetType() == typeof(MultiStateQuantumObject)) { worldObj = QSBWorldSync.GetWorldFromUnity((MultiStateQuantumObject)unityObject); } else if (unityObject.GetType() == typeof(QuantumShuffleObject)) { worldObj = QSBWorldSync.GetWorldFromUnity((QuantumShuffleObject)unityObject); } else if (unityObject.GetType() == typeof(QuantumMoon)) { worldObj = QSBWorldSync.GetWorldFromUnity((QuantumMoon)unityObject); } else if (unityObject.GetType() == typeof(EyeProxyQuantumMoon)) { worldObj = QSBWorldSync.GetWorldFromUnity((EyeProxyQuantumMoon)unityObject); } else { DebugLog.ToConsole($"Warning - couldn't work out type of QuantumObject {unityObject.name}.", MessageType.Warning); } return worldObj; } } }