Merge pull request #250 from misternebula/quantum-sync-fixes

more quantum sync fixes
This commit is contained in:
_nebula 2021-02-22 10:54:19 +00:00 committed by GitHub
commit 807af5ad2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 468 additions and 169 deletions

View File

@ -22,7 +22,7 @@
public static string ExitQuantumMoon = "PlayerExitQuantumMoon";
// Custom event names -- change if you want! These can be anything, as long as both
// sides of the GlobalMessenger (fireevent and setuplistener) reference the same thing.
// sides of the GlobalMessenger (fireevent and addlistener) reference the same thing.
public static string QSBPlayerDeath = "QSBPlayerDeath";
public static string QSBPlayerJoin = "QSBPlayerJoin";
public static string QSBPlayerReady = "QSBPlayerReady";
@ -49,5 +49,6 @@
public static string QSBTextTranslated = "QSBTextTranslated";
public static string QSBEnterShrine = "QSBEnterShrine";
public static string QSBExitShrine = "QSBExitShrine";
public static string QSBPlayerEntangle = "QSBPlayerEntangle";
}
}

View File

@ -2,7 +2,6 @@
{
public enum EventType
{
Sector,
ServerTime,
AnimTrigger,
PlayerState,
@ -34,6 +33,7 @@
IdentifyFrequency,
IdentifySignal,
TextTranslated,
EnterLeave
EnterLeave,
PlayerEntangle
}
}

View File

@ -43,6 +43,7 @@ namespace QSB.Events
new ChangeAnimTypeEvent(),
new CrouchEvent(),
new ServerTimeEvent(),
new PlayerEntangledEvent(),
// World Objects
new ElevatorEvent(),
new GeyserEvent(),

View File

@ -1,8 +1,6 @@
using OWML.Utils;
using QSB.Events;
using QSB.Utility;
using QSB.WorldSync;
using UnityEngine.UI;
namespace QSB.OrbSync.WorldObjects
{
@ -11,20 +9,12 @@ namespace QSB.OrbSync.WorldObjects
public bool Activated { get; private set; }
private bool _initialized;
private Text _debugBoxText;
public override void OnRemoval()
=> UnityEngine.Object.Destroy(_debugBoxText.gameObject);
public override void Init(NomaiInterfaceSlot slot, int id)
{
ObjectId = id;
AttachedObject = slot;
_initialized = true;
if (QSBCore.DebugMode)
{
_debugBoxText = DebugBoxManager.CreateBox(AttachedObject.transform, 0, AttachedObject.IsActivated().ToString()).GetComponent<Text>();
}
}
public void HandleEvent(bool state, int orbId)
@ -34,10 +24,6 @@ namespace QSB.OrbSync.WorldObjects
return;
}
QSBEventManager.FireEvent(EventNames.QSBOrbSlot, ObjectId, orbId, state);
if (QSBCore.DebugMode)
{
_debugBoxText.text = state.ToString();
}
}
public void SetState(bool state, int orbId)
@ -51,10 +37,6 @@ namespace QSB.OrbSync.WorldObjects
var ev = state ? "OnSlotActivated" : "OnSlotDeactivated";
QSBWorldSync.RaiseEvent(AttachedObject, ev);
Activated = state;
if (QSBCore.DebugMode)
{
_debugBoxText.text = state.ToString();
}
}
}
}

View File

@ -0,0 +1,46 @@
using QSB.Events;
using QSB.QuantumSync;
using QSB.WorldSync.Events;
namespace QSB.Player.Events
{
internal class PlayerEntangledEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.PlayerEntangle;
public override void SetupListener() => GlobalMessenger<int>.AddListener(EventNames.QSBPlayerEntangle, Handler);
public override void CloseListener() => GlobalMessenger<int>.RemoveListener(EventNames.QSBPlayerEntangle, Handler);
private void Handler(int id) => SendEvent(CreateMessage(id));
private WorldObjectMessage CreateMessage(int id) => new WorldObjectMessage
{
AboutId = LocalPlayerId,
ObjectId = id
};
public override void OnReceiveLocal(bool server, WorldObjectMessage message)
{
var player = QSBPlayerManager.LocalPlayer;
if (message.ObjectId == -1)
{
player.EntangledObject = null;
return;
}
var quantumObject = QuantumManager.GetObject(message.ObjectId);
player.EntangledObject = quantumObject;
}
public override void OnReceiveRemote(bool server, WorldObjectMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
if (message.ObjectId == -1)
{
player.EntangledObject = null;
return;
}
var quantumObject = QuantumManager.GetObject(message.ObjectId);
player.EntangledObject = quantumObject;
}
}
}

View File

@ -0,0 +1,33 @@
using OWML.Utils;
using QSB.Events;
using QSB.QuantumSync;
using UnityEngine;
namespace QSB.Player
{
internal class PlayerEntanglementWatcher : MonoBehaviour
{
private QuantumObject _previousCollidingQuantumObject;
private void Update()
{
var controller = Locator.GetPlayerController();
if (controller == null)
{
return;
}
var collidingQuantumObject = controller.GetValue<QuantumObject>("_collidingQuantumObject");
if (_previousCollidingQuantumObject != collidingQuantumObject)
{
var objectIndex = (collidingQuantumObject != null)
? QuantumManager.GetId(QuantumManager.GetObject(collidingQuantumObject))
: -1;
QSBEventManager.FireEvent(
EventNames.QSBPlayerEntangle,
objectIndex);
_previousCollidingQuantumObject = collidingQuantumObject;
}
}
}
}

View File

@ -1,4 +1,5 @@
using QSB.Animation;
using QSB.QuantumSync;
using QSB.Tools;
using QSB.Utility;
using System.Linq;
@ -39,6 +40,7 @@ namespace QSB.Player
// Misc
public bool IsInMoon;
public bool IsInShrine;
public IQSBQuantumObject EntangledObject;
public PlayerInfo(uint id)
{

View File

@ -19,12 +19,12 @@ namespace QSB.Player
var localInstance = PlayerTransformSync.LocalInstance;
if (localInstance == null)
{
DebugLog.DebugWrite($"Error - Trying to get LocalPlayerId when the local PlayerTransformSync instance is null.", MessageType.Error);
DebugLog.ToConsole($"Error - Trying to get LocalPlayerId when the local PlayerTransformSync instance is null.", MessageType.Error);
return uint.MaxValue;
}
if (localInstance.NetIdentity == null)
{
DebugLog.DebugWrite($"Error - Trying to get LocalPlayerId when the local PlayerTransformSync instance's QNetworkIdentity is null.", MessageType.Error);
DebugLog.ToConsole($"Error - Trying to get LocalPlayerId when the local PlayerTransformSync instance's QNetworkIdentity is null.", MessageType.Error);
return uint.MaxValue;
}
return localInstance.NetIdentity.NetId.Value;
@ -41,7 +41,7 @@ namespace QSB.Player
if (!QSBNetworkManager.Instance.IsReady)
{
var method = new StackTrace().GetFrame(1).GetMethod();
DebugLog.DebugWrite($"Warning - GetPlayer() (id<{id}>) called when Network Manager not ready! Is a Player Sync Object still active? " +
DebugLog.ToConsole($"Warning - GetPlayer() (id<{id}>) called when Network Manager not ready! Is a Player Sync Object still active? " +
$"{Environment.NewLine} Called from {method.DeclaringType.Name}.{method.Name}", MessageType.Warning);
}
@ -99,12 +99,12 @@ namespace QSB.Player
PlayerSyncObjects.Any(x => x != null && x.AttachedNetId == id && x.IsLocalPlayer);
}
public static List<OWCamera> GetPlayerCameras(bool includeLocalCamera = true)
public static List<PlayerInfo> GetPlayersWithCameras(bool includeLocalCamera = true)
{
var cameraList = PlayerList.Where(x => x.Camera != null && x.PlayerId != LocalPlayerId).Select(x => x.Camera).ToList();
var cameraList = PlayerList.Where(x => x.Camera != null && x.PlayerId != LocalPlayerId).ToList();
if (includeLocalCamera)
{
cameraList.Add(Locator.GetActiveCamera());
cameraList.Add(LocalPlayer);
}
return cameraList;
}

View File

@ -144,7 +144,9 @@
<Compile Include="OrbSync\Events\OrbUserEvent.cs" />
<Compile Include="OrbSync\WorldObjects\QSBOrbSlot.cs" />
<Compile Include="Patches\QSBPatchManager.cs" />
<Compile Include="Player\Events\PlayerEntangledEvent.cs" />
<Compile Include="Player\Events\ServerSendPlayerStatesEvent.cs" />
<Compile Include="Player\PlayerEntanglementWatcher.cs" />
<Compile Include="Player\PlayerMapMarker.cs" />
<Compile Include="Player\PlayerSyncObject.cs" />
<Compile Include="QSBInputManager.cs" />

View File

@ -8,6 +8,7 @@ using QSB.OrbSync;
using QSB.Patches;
using QSB.Player;
using QSB.QuantumSync;
using QSB.QuantumSync.WorldObjects;
using QSB.SectorSync;
using QSB.TimeSync;
using QSB.TranslationSync;
@ -15,6 +16,7 @@ using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using QuantumUNET.Components;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
@ -46,6 +48,7 @@ namespace QSB
public static int Port { get; private set; }
public static bool DebugMode { get; private set; }
public static bool ShowLinesInDebug { get; private set; }
public static int SocketedObjToDebug { get; private set; }
public static AssetBundle NetworkAssetBundle { get; private set; }
public static AssetBundle InstrumentAssetBundle { get; private set; }
public static AssetBundle ConversationAssetBundle { get; private set; }
@ -55,6 +58,7 @@ namespace QSB
public static GameObject GameObjectInstance => _thisInstance.gameObject;
private static QSBCore _thisInstance;
private const float _debugLineSpacing = 11f;
public void Awake()
{
@ -92,6 +96,7 @@ namespace QSB
gameObject.AddComponent<QuantumManager>();
gameObject.AddComponent<SpiralManager>();
gameObject.AddComponent<RepeatingManager>();
gameObject.AddComponent<PlayerEntanglementWatcher>();
DebugBoxManager.Init();
@ -104,10 +109,13 @@ namespace QSB
public void OnGUI()
{
GUI.Label(new Rect(220, 10, 200f, 20f), $"Rough FPS : {1f / Time.smoothDeltaTime}");
GUI.Label(new Rect(220, 40, 200f, 20f), $"HasWokenUp : {QSBCore.HasWokenUp}");
var offset = 10f;
GUI.Label(new Rect(220, 10, 200f, 20f), $"FPS : {Mathf.Round(1f / Time.smoothDeltaTime)}");
offset += _debugLineSpacing;
GUI.Label(new Rect(220, offset, 200f, 20f), $"HasWokenUp : {HasWokenUp}");
offset += _debugLineSpacing;
if (!QSBCore.HasWokenUp || !QSBCore.DebugMode)
if (!HasWokenUp || !DebugMode)
{
return;
}
@ -117,34 +125,41 @@ namespace QSB
return;
}
var offset = 70f;
GUI.Label(new Rect(220, offset, 200f, 20f), $"QM Visible : {Locator.GetQuantumMoon().IsVisible()}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $"QM Locked : {Locator.GetQuantumMoon().IsLocked()}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $"QM Illuminated : {Locator.GetQuantumMoon().IsIlluminated()}");
offset += 30f;
//GUI.Label(new Rect(220, offset, 200f, 20f), $"Shrine player in dark? : {QuantumManager.Instance.Shrine.IsPlayerInDarkness()}");
//offset += 30f;
offset += _debugLineSpacing;
GUI.Label(new Rect(220, offset, 200f, 20f), $"Shrine player in dark? : {QuantumManager.Instance.Shrine.IsPlayerInDarkness()}");
offset += _debugLineSpacing;
GUI.Label(new Rect(220, offset, 200f, 20f), $"QM Visible by :");
offset += _debugLineSpacing;
var tracker = Locator.GetQuantumMoon().GetValue<ShapeVisibilityTracker>("_visibilityTracker");
foreach (var camera in QSBPlayerManager.GetPlayerCameras())
foreach (var player in QSBPlayerManager.GetPlayersWithCameras())
{
GUI.Label(new Rect(220, offset, 200f, 20f), $"- {camera.name} : {tracker.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(tracker, new object[] { camera.GetFrustumPlanes() })}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $" - {player.PlayerId} : {tracker.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(tracker, new object[] { player.Camera.GetFrustumPlanes() })}");
offset += _debugLineSpacing;
}
// Used for diagnosing specific socketed objects. Just set <index> to be the correct index.
/*
var index = 110;
var socketedObject = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject>(index);
GUI.Label(new Rect(220, offset, 200f, 20f), $"{index} Controller : {socketedObject.ControllingPlayer}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $"{index} Visible : {socketedObject.AttachedObject.IsVisible()}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $"{index} Locked : {socketedObject.AttachedObject.IsLocked()}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $"{index} Illuminated : {socketedObject.AttachedObject.IsIlluminated()}");
offset += 30f;
var offset2 = 10f;
GUI.Label(new Rect(440, offset2, 200f, 20f), $"Owned Objects :");
offset2 += _debugLineSpacing;
foreach (var obj in QSBWorldSync.GetWorldObjects<IQSBQuantumObject>().Where(x => x.ControllingPlayer == QSBPlayerManager.LocalPlayerId))
{
GUI.Label(new Rect(440, offset2, 200f, 20f), $"- {(obj as IWorldObject).Name}");
offset2 += _debugLineSpacing;
}
if (SocketedObjToDebug == -1)
{
return;
}
// Used for diagnosing specific socketed objects.
// 110 = Cave Twin entanglement shard
// 342 = Timber Hearth museum shard
var socketedObject = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject>(SocketedObjToDebug);
GUI.Label(new Rect(220, offset, 200f, 20f), $"{SocketedObjToDebug} Controller : {socketedObject.ControllingPlayer}");
offset += _debugLineSpacing;
GUI.Label(new Rect(220, offset, 200f, 20f), $"{SocketedObjToDebug} Illuminated : {socketedObject.AttachedObject.IsIlluminated()}");
offset += _debugLineSpacing;
var socketedTrackers = socketedObject.AttachedObject.GetComponentsInChildren<ShapeVisibilityTracker>();
if (socketedTrackers == null || socketedTrackers.Length == 0)
{
@ -156,20 +171,31 @@ namespace QSB
GUI.Label(new Rect(220, offset, 200f, 20f), $"- Uses a null.");
return;
}
foreach (var camera in QSBPlayerManager.GetPlayerCameras())
GUI.Label(new Rect(220, offset, 200f, 20f), $"Visible by :");
offset += _debugLineSpacing;
foreach (var player in QSBPlayerManager.GetPlayersWithCameras())
{
GUI.Label(new Rect(220, offset, 200f, 20f), $"- {camera.name} : {socketedTrackers.Any(x => (bool)x.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(x, new object[] { camera.GetFrustumPlanes() }))}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $" - {player.PlayerId} : {socketedTrackers.Any(x => (bool)x.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(x, new object[] { player.Camera.GetFrustumPlanes() }))}");
offset += _debugLineSpacing;
}
*/
offset = 10f;
GUI.Label(new Rect(440, offset, 200f, 20f), $"Owned Objects :");
offset += 30f;
foreach (var obj in QSBWorldSync.GetWorldObjects<IQSBQuantumObject>().Where(x => x.ControllingPlayer == QSBPlayerManager.LocalPlayerId))
GUI.Label(new Rect(220, offset, 200f, 20f), $"Entangled Players :");
offset += _debugLineSpacing;
foreach (var player in QuantumManager.GetEntangledPlayers(socketedObject.AttachedObject))
{
GUI.Label(new Rect(440, offset, 200f, 20f), $"- {(obj as IWorldObject).Name}");
offset += 30f;
GUI.Label(new Rect(220, offset, 200f, 20f), $" - {player.PlayerId}");
offset += _debugLineSpacing;
}
var sockets = socketedObject.AttachedObject.GetValue<List<QuantumSocket>>("_socketList");
foreach (var socket in sockets)
{
GUI.Label(new Rect(220, offset, 200f, 20f), $"- {socket.name} :");
offset += _debugLineSpacing;
GUI.Label(new Rect(220, offset, 200f, 20f), $" - Visible:{socket.GetVisibilityObject().IsVisible()}");
offset += _debugLineSpacing;
GUI.Label(new Rect(220, offset, 200f, 20f), $" - Illuminated:{socket.GetVisibilityObject().IsIlluminated()}");
offset += _debugLineSpacing;
GUI.Label(new Rect(220, offset, 200f, 20f), $" - Occupied?:{socket.IsOccupied()}");
offset += _debugLineSpacing;
}
}
@ -187,6 +213,7 @@ namespace QSB
FindObjectsOfType<DebugZOverride>().ToList().ForEach(x => Destroy(x.gameObject));
}
ShowLinesInDebug = config.GetSettingsValue<bool>("showLinesInDebug");
SocketedObjToDebug = config.GetSettingsValue<int>("socketedObjToDebug");
}
}
}

View File

@ -43,6 +43,7 @@ namespace QSB
private GameObject _shipPrefab;
private GameObject _cameraPrefab;
private GameObject _probePrefab;
private bool _everConnected;
public void Awake()
{
@ -200,6 +201,8 @@ namespace QSB
QSBCore.Helper.Events.Unity.RunWhen(() => QSBEventManager.Ready && PlayerTransformSync.LocalInstance != null,
() => QSBEventManager.FireEvent(EventNames.QSBPlayerStatesRequest));
}
_everConnected = true;
}
public override void OnStopClient() // Called on the client when closing connection
@ -215,14 +218,18 @@ namespace QSB
QSBWorldSync.OrbSyncList.Clear();
QSBWorldSync.OldDialogueTrees.Clear();
var specificType = QNetworkServer.active ? QSBPatchTypes.OnServerClientConnect : QSBPatchTypes.OnNonServerClientConnect;
QSBPatchManager.DoUnpatchType(specificType);
QSBPatchManager.DoUnpatchType(QSBPatchTypes.OnClientConnect);
if (_everConnected)
{
var specificType = QNetworkServer.active ? QSBPatchTypes.OnServerClientConnect : QSBPatchTypes.OnNonServerClientConnect;
QSBPatchManager.DoUnpatchType(specificType);
QSBPatchManager.DoUnpatchType(QSBPatchTypes.OnClientConnect);
}
_lobby.CanEditName = true;
QSBCore.HasWokenUp = false;
IsReady = false;
_everConnected = false;
}
public override void OnServerDisconnect(QNetworkConnection connection) // Called on the server when any client disconnects

View File

@ -26,7 +26,7 @@ namespace QSB.QuantumSync.Events
return false;
}
var obj = QuantumManager.Instance.GetObject(message.ObjectId);
var obj = QuantumManager.GetObject(message.ObjectId);
// Deciding if to change the object's owner
// Message
@ -42,13 +42,13 @@ namespace QSB.QuantumSync.Events
public override void OnReceiveLocal(bool server, QuantumAuthorityMessage message)
{
var obj = QuantumManager.Instance.GetObject(message.ObjectId);
var obj = QuantumManager.GetObject(message.ObjectId);
obj.ControllingPlayer = message.AuthorityOwner;
}
public override void OnReceiveRemote(bool server, QuantumAuthorityMessage message)
{
var obj = QuantumManager.Instance.GetObject(message.ObjectId);
var obj = QuantumManager.GetObject(message.ObjectId);
obj.ControllingPlayer = message.AuthorityOwner;
if (obj.ControllingPlayer == 0 && obj.IsEnabled)
{

View File

@ -1,4 +1,5 @@
using QSB.Events;
using OWML.Common;
using QSB.Events;
using QSB.Patches;
using QSB.Player;
using QSB.QuantumSync.WorldObjects;
@ -44,8 +45,109 @@ namespace QSB.QuantumSync.Patches
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("CheckPlayerFogProximity");
}
public static bool Socketed_ChangeQuantumState(SocketedQuantumObject __instance)
=> QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject, SocketedQuantumObject>(__instance).ControllingPlayer == QSBPlayerManager.LocalPlayerId;
public static bool Socketed_ChangeQuantumState(
SocketedQuantumObject __instance,
ref bool __result,
bool skipInstantVisibilityCheck,
List<QuantumSocket> ____childSockets,
List<QuantumSocket> ____socketList,
ref QuantumSocket ____recentlyObscuredSocket,
QuantumSocket ____occupiedSocket)
{
var socketedWorldObject = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject, SocketedQuantumObject>(__instance);
if (socketedWorldObject.ControllingPlayer != QSBPlayerManager.LocalPlayerId)
{
return false;
}
foreach (var socket in ____childSockets)
{
if (socket.IsOccupied())
{
__result = false;
return false;
}
}
if (____socketList.Count <= 1)
{
DebugLog.ToConsole($"Error - Not enough quantum sockets in list for {__instance.name}!", MessageType.Error);
__result = false;
return false;
}
var list = new List<QuantumSocket>();
foreach (var socket in ____socketList)
{
if (!socket.IsOccupied() && socket.IsActive())
{
list.Add(socket);
}
}
if (list.Count == 0)
{
__result = false;
return false;
}
if (____recentlyObscuredSocket != null)
{
__instance.GetType().GetMethod("MoveToSocket", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { ____recentlyObscuredSocket });
____recentlyObscuredSocket = null;
__result = true;
return false;
}
var occupiedSocket = ____occupiedSocket;
for (var i = 0; i < 20; i++)
{
var index = UnityEngine.Random.Range(0, list.Count);
__instance.GetType().GetMethod("MoveToSocket", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { list[index] });
if (skipInstantVisibilityCheck)
{
__result = true;
return false;
}
bool socketNotSuitable;
var isSocketIlluminated = (bool)__instance.GetType().GetMethod("CheckIllumination", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null);
var playersEntangled = QuantumManager.GetEntangledPlayers(__instance);
if (playersEntangled.Count() != 0)
{
// socket not suitable if illuminated
socketNotSuitable = isSocketIlluminated;
}
else
{
var checkVisInstant = (bool)__instance.GetType().GetMethod("CheckVisibilityInstantly", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null);
if (isSocketIlluminated)
{
// socket not suitable if object is visible
socketNotSuitable = checkVisInstant;
}
else
{
// socket not suitable if player is inside object
socketNotSuitable = playersEntangled.Any(x => __instance.CheckPointInside(x.CameraBody.transform.position));
}
}
if (!socketNotSuitable)
{
__result = true;
return false;
}
list.RemoveAt(index);
if (list.Count == 0)
{
break;
}
}
__instance.GetType().GetMethod("MoveToSocket", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { occupiedSocket });
__result = false;
return false;
}
public static void Socketed_MoveToSocket(SocketedQuantumObject __instance, QuantumSocket socket)
{

View File

@ -44,12 +44,12 @@ namespace QSB.QuantumSync.Patches
public static bool RenderIsVisibleUsingCameraFrustum(RendererVisibilityTracker __instance, ref bool __result, Renderer ____renderer, bool ____checkFrustumOcclusion)
{
__result = QSBPlayerManager.GetPlayerCameras()
.Any(x => GeometryUtility.TestPlanesAABB(x.GetFrustumPlanes(), ____renderer.bounds))
&& (!____checkFrustumOcclusion || QSBPlayerManager.GetPlayerCameras()
__result = QSBPlayerManager.GetPlayersWithCameras()
.Any(x => GeometryUtility.TestPlanesAABB(x.Camera.GetFrustumPlanes(), ____renderer.bounds))
&& (!____checkFrustumOcclusion || QSBPlayerManager.GetPlayersWithCameras()
.Any(x => !(bool)__instance.GetType()
.GetMethod("IsOccludedFromPosition", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(__instance, new object[] { x.transform.position })));
.Invoke(__instance, new object[] { x.Camera.transform.position })));
return false;
}

View File

@ -131,7 +131,7 @@ namespace QSB.QuantumSync.Patches
}
else
{
DebugLog.DebugWrite("Warning - Quantum moon orbit position occupied! Aborting collapse.", MessageType.Warning);
DebugLog.ToConsole("Warning - Quantum moon orbit position occupied! Aborting collapse.", MessageType.Warning);
}
}
if (flag)

View File

@ -4,6 +4,7 @@ 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;
@ -69,29 +70,92 @@ namespace QSB.QuantumSync
public static bool IsVisibleUsingCameraFrustum(ShapeVisibilityTracker tracker, bool ignoreLocalCamera)
{
return tracker.gameObject.activeInHierarchy
&& QSBPlayerManager.GetPlayerCameras(!ignoreLocalCamera)
&& QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera)
.Any(x => (bool)tracker.GetType()
.GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(tracker, new object[] { x.GetFrustumPlanes() }));
.Invoke(tracker, new object[] { x.Camera.GetFrustumPlanes() }));
}
public static bool IsVisible(ShapeVisibilityTracker tracker, bool ignoreLocalCamera)
{
return tracker.gameObject.activeInHierarchy
&& IsVisibleUsingCameraFrustum(tracker, ignoreLocalCamera)
&& QSBPlayerManager.GetPlayerCameras(!ignoreLocalCamera)
.Any(x => VisibilityOccluder.CanYouSee(tracker, x.mainCamera.transform.position));
&& QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera)
.Any(x => VisibilityOccluder.CanYouSee(tracker, x.Camera.mainCamera.transform.position));
}
public int GetId(IQSBQuantumObject obj)
=> QSBWorldSync
.GetWorldObjects<IQSBQuantumObject>()
.ToList()
.IndexOf(obj);
public static IEnumerable<PlayerInfo> GetEntangledPlayers(QuantumObject obj)
{
var worldObj = GetObject(obj);
return QSBPlayerManager.PlayerList.Where(x => x.EntangledObject == worldObj);
}
public IQSBQuantumObject GetObject(int id)
=> QSBWorldSync
public static IQSBQuantumObject GetObject(QuantumObject unityObject)
{
IQSBQuantumObject worldObj = null;
if (unityObject.GetType() == typeof(SocketedQuantumObject) || unityObject.GetType() == typeof(QuantumShrine))
{
worldObj = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject, SocketedQuantumObject>((SocketedQuantumObject)unityObject);
}
else if (unityObject.GetType() == typeof(MultiStateQuantumObject))
{
worldObj = QSBWorldSync.GetWorldObject<QSBMultiStateQuantumObject, MultiStateQuantumObject>((MultiStateQuantumObject)unityObject);
}
else if (unityObject.GetType() == typeof(QuantumShuffleObject))
{
worldObj = QSBWorldSync.GetWorldObject<QSBQuantumShuffleObject, QuantumShuffleObject>((QuantumShuffleObject)unityObject);
}
else
{
DebugLog.ToConsole($"Warning - couldn't work out type of QuantumObject {unityObject.name}.", MessageType.Warning);
}
return worldObj;
}
public static IQSBQuantumObject GetObject(int id)
{
var objects = QSBWorldSync
.GetWorldObjects<IQSBQuantumObject>()
.ToList()[id];
.ToList();
if (objects.Count == 0)
{
DebugLog.ToConsole($"Error - tried to get IQSBQuantumObject, but there are none!", MessageType.Error);
return null;
}
if (objects.Count <= id)
{
DebugLog.ToConsole($"Error - Index {id} does not exist in list of IQSBObjects! (Count:{objects.Count})", MessageType.Error);
return null;
}
if (id < 0)
{
DebugLog.ToConsole($"Error - tried to get IQSBQuantumObject with index less than zero...", MessageType.Error);
return null;
}
return objects[id];
}
public static int GetId(IQSBQuantumObject obj)
{
var objects = QSBWorldSync
.GetWorldObjects<IQSBQuantumObject>()
.ToList();
if (obj == null)
{
DebugLog.ToConsole($"Error - tried to get id of null IQSBQuantumObject!", MessageType.Error);
return -1;
}
if (objects.Count == 0)
{
DebugLog.ToConsole($"Error - tried to get id of IQSBQuantumObject, but there are none!", MessageType.Error);
return -1;
}
if (!objects.Contains(obj))
{
DebugLog.ToConsole($"Error - tried to get id of IQSBQuantumObject that doesn't exist in WorldObject list?!", MessageType.Error);
return -1;
}
return objects.IndexOf(obj);
}
}
}

View File

@ -12,7 +12,10 @@ namespace QSB.QuantumSync.WorldObjects
public override void OnRemoval()
{
base.OnRemoval();
UnityEngine.Object.Destroy(DebugBoxText.gameObject);
if (DebugBoxText != null)
{
UnityEngine.Object.Destroy(DebugBoxText.gameObject);
}
}
public override void Init(MultiStateQuantumObject attachedObject, int id)

View File

@ -42,7 +42,7 @@ namespace QSB.QuantumSync.WorldObjects
// controlled by another player, dont care that we activate it
return;
}
var id = QuantumManager.Instance.GetId(this);
var id = QuantumManager.GetId(this);
// no one is controlling this object right now, request authority
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, id, QSBPlayerManager.LocalPlayerId);
}
@ -59,7 +59,7 @@ namespace QSB.QuantumSync.WorldObjects
// not being controlled by us, don't care if we leave area
return;
}
var id = QuantumManager.Instance.GetId(this);
var id = QuantumManager.GetId(this);
// send event to other players that we're releasing authority
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, id, 0u);
}

View File

@ -5,28 +5,36 @@ using QSB.Utility;
using QSB.WorldSync;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace QSB.QuantumSync.WorldObjects
{
internal class QSBSocketedQuantumObject : QSBQuantumObject<SocketedQuantumObject>
{
public Text DebugBoxText;
public override void Init(SocketedQuantumObject quantumObject, int id)
{
ObjectId = id;
AttachedObject = quantumObject;
base.Init(quantumObject, id);
if (QSBCore.DebugMode)
{
DebugBoxText = DebugBoxManager.CreateBox(AttachedObject.transform, 0, ObjectId.ToString()).GetComponent<Text>();
}
}
public override void OnRemoval()
{
base.OnRemoval();
if (DebugBoxText != null)
{
Object.Destroy(DebugBoxText.gameObject);
}
}
public void MoveToSocket(SocketStateChangeMessage message)
{
/*
var visibilityTrackers = AttachedObject.GetValue<VisibilityTracker[]>("_visibilityTrackers");
var visible = visibilityTrackers.Where(x => x is ShapeVisibilityTracker).Any(x => QuantumManager.IsVisibleUsingCameraFrustum(x as ShapeVisibilityTracker, false));
if (visible)
{
DebugLog.DebugWrite($"Error - trying to move {AttachedObject.name} while still visible!", MessageType.Error);
}
*/
var qsbSocket = QSBWorldSync.GetWorldObject<QSBQuantumSocket>(message.SocketId);
if (qsbSocket == null)
{

View File

@ -22,18 +22,11 @@ namespace QSB.SectorSync
{
Instance = this;
QSBSceneManager.OnUniverseSceneLoaded += (OWScene scene) => RebuildSectors();
QSBSceneManager.OnUniverseSceneLoaded += (OWScene scene) => QSBCore.Helper.Events.Unity.RunWhen(() => Locator.GetPlayerSectorDetector() != null, StartThing);
DebugLog.DebugWrite("Sector Manager ready.", MessageType.Success);
}
public void OnDestroy() => QSBSceneManager.OnUniverseSceneLoaded -= (OWScene scene) => RebuildSectors();
private void StartThing()
{
Locator.GetPlayerSectorDetector().OnEnterSector += (Sector sector) => DebugLog.DebugWrite($"Player enter sector {sector.name}", MessageType.Success);
Locator.GetPlayerSectorDetector().OnExitSector += (Sector sector) => DebugLog.DebugWrite($"Player exit sector {sector.name}", MessageType.Warning);
}
public void RebuildSectors()
{
DebugLog.DebugWrite("Rebuilding sectors...", MessageType.Warning);

View File

@ -1,30 +1,25 @@
using QSB.Events;
using QSB.Player;
using QSB.SectorSync.WorldObjects;
using QSB.Utility;
using System.Linq;
using UnityEngine;
namespace QSB.SectorSync
{
public class SectorSync : MonoBehaviour
public class SectorSync : MonoBehaviour, IRepeating
{
private const float CheckInterval = 0.5f;
private float _checkTimer = CheckInterval;
private void OnEnable() => RepeatingManager.Repeatings.Add(this);
private void OnDisable() => RepeatingManager.Repeatings.Remove(this);
public void Update()
public void Invoke()
{
if (!QSBSectorManager.Instance.IsReady)
{
return;
}
_checkTimer += Time.unscaledDeltaTime;
if (_checkTimer < CheckInterval)
{
return;
}
QSBPlayerManager.GetSyncObjects<TransformSync.TransformSync>()
.Where(x => x.HasAuthority).ToList().ForEach(CheckTransformSyncSector);
_checkTimer = 0;
}
private void CheckTransformSyncSector(TransformSync.TransformSync transformSync)

View File

@ -19,10 +19,12 @@ namespace QSB.TransformSync
public QSBSector ReferenceSector { get; set; }
private const float SmoothTime = 0.1f;
private const float DistanceLeeway = 5f;
private bool _isInitialized;
private Vector3 _positionSmoothVelocity;
private Quaternion _rotationSmoothVelocity;
private bool _isVisible;
private float _previousDistance;
protected override void Start()
{
@ -107,8 +109,21 @@ namespace QSB.TransformSync
Show();
}
SyncedTransform.localPosition = Vector3.SmoothDamp(SyncedTransform.localPosition, transform.position, ref _positionSmoothVelocity, SmoothTime);
SyncedTransform.localRotation = QuaternionHelper.SmoothDamp(SyncedTransform.localRotation, transform.rotation, ref _rotationSmoothVelocity, Time.deltaTime);
SyncedTransform.localPosition = SmartSmoothDamp(SyncedTransform.localPosition, transform.position);
SyncedTransform.localRotation = QuaternionHelper.SmoothDamp(SyncedTransform.localRotation, transform.rotation, ref _rotationSmoothVelocity, SmoothTime);
}
private Vector3 SmartSmoothDamp(Vector3 currentPosition, Vector3 targetPosition)
{
var distance = Vector3.Distance(currentPosition, targetPosition);
if (distance > _previousDistance + DistanceLeeway)
{
// moved too far! assume sector sync warp / actual warp
_previousDistance = distance;
return targetPosition;
}
_previousDistance = distance;
return Vector3.SmoothDamp(currentPosition, targetPosition, ref _positionSmoothVelocity, SmoothTime);
}
public void SetReferenceSector(QSBSector sector)

View File

@ -7,6 +7,10 @@ namespace QSB.Utility
// Stolen from here: https://gist.github.com/maxattack/4c7b4de00f5c1b95a33b
public static Quaternion SmoothDamp(Quaternion rot, Quaternion target, ref Quaternion deriv, float time)
{
if (Time.deltaTime < Mathf.Epsilon)
{
return rot;
}
// account for double-cover
var dot = Quaternion.Dot(rot, target);
var multi = dot > 0f ? 1f : -1f;
@ -21,12 +25,14 @@ namespace QSB.Utility
Mathf.SmoothDamp(rot.z, target.z, ref deriv.z, time),
Mathf.SmoothDamp(rot.w, target.w, ref deriv.w, time)
).normalized;
// compute deriv
var dtInv = 1f / Time.deltaTime;
deriv.x = (result.x - rot.x) * dtInv;
deriv.y = (result.y - rot.y) * dtInv;
deriv.z = (result.z - rot.z) * dtInv;
deriv.w = (result.w - rot.w) * dtInv;
// ensure deriv is tangent
var derivError = Vector4.Project(new Vector4(deriv.x, deriv.y, deriv.z, deriv.w), result);
deriv.x -= derivError.x;
deriv.y -= derivError.y;
deriv.z -= derivError.z;
deriv.w -= derivError.w;
return new Quaternion(result.x, result.y, result.z, result.w);
}
}

View File

@ -7,7 +7,7 @@ namespace QSB.Utility
{
public static List<IRepeating> Repeatings = new List<IRepeating>();
private const float TimeInterval = 0.2f;
private const float TimeInterval = 0.4f;
private float _checkTimer = TimeInterval;
private void Update()

View File

@ -46,7 +46,14 @@ namespace QSB.WorldSync
var itemsToRemove = WorldObjects.Where(x => x is TWorldObject);
foreach (var item in itemsToRemove)
{
item.OnRemoval();
try
{
item.OnRemoval();
}
catch (Exception e)
{
DebugLog.ToConsole($"Error - Exception in OnRemoval() for {item.GetType()}. Message : {e.Message}, Stack trace : {e.StackTrace}", MessageType.Error);
}
}
DebugLog.DebugWrite($"Removing {typeof(TWorldObject).Name} : {WorldObjects.Count(x => x is TWorldObject)} instances.");
WorldObjects.RemoveAll(x => x is TWorldObject);
@ -97,7 +104,12 @@ namespace QSB.WorldSync
{
return;
}
var qsbSlot = slotList.First(x => x.AttachedObject == slot);
var qsbSlot = slotList.FirstOrDefault(x => x.AttachedObject == slot);
if (qsbSlot == null)
{
DebugLog.ToConsole($"Error - No QSBOrbSlot found for {slot.name}!", MessageType.Error);
return;
}
var orbSync = OrbSyncList.First(x => x.AttachedOrb == affectingOrb);
if (orbSync.HasAuthority)
{

View File

@ -7,7 +7,7 @@ namespace QSB.WorldSync
{
public int ObjectId { get; protected set; }
public T AttachedObject { get; protected set; }
public string Name => AttachedObject.name;
public string Name => AttachedObject == null ? "<NullObject!>" : AttachedObject.name;
public abstract void Init(T attachedObject, int id);
public virtual void OnRemoval() { }

View File

@ -3,7 +3,8 @@
"settings": {
"defaultServerIP": "localhost",
"port": 7777,
"debugMode": true,
"showLinesInDebug": false
"debugMode": false,
"showLinesInDebug": false,
"socketedObjToDebug": -1
}
}

View File

@ -4,47 +4,46 @@ namespace QuantumUNET.Components
{
public class QNetworkManagerHUD : MonoBehaviour
{
public QNetworkManager manager;
public bool showGUI = true;
public int offsetX;
public int offsetY;
public QNetworkManager Manager;
public bool ShowGUI = true;
private void Awake() => manager = GetComponent<QNetworkManager>();
private void Awake()
=> Manager = GetComponent<QNetworkManager>();
private void OnGUI()
{
if (showGUI)
if (ShowGUI)
{
var num = 10 + offsetX;
var num2 = 40 + offsetY;
var flag = manager.client == null || manager.client.connection == null || manager.client.connection.connectionId == -1;
if (!manager.IsClientConnected() && !QNetworkServer.active)
var xOffset = 10;
var yOffset = 30;
var flag = Manager.client == null || Manager.client.connection == null || Manager.client.connection.connectionId == -1;
if (!Manager.IsClientConnected() && !QNetworkServer.active)
{
if (flag)
{
if (Application.platform != RuntimePlatform.WebGLPlayer)
{
if (GUI.Button(new Rect(num, num2, 200f, 20f), "Host"))
if (GUI.Button(new Rect(xOffset, yOffset, 200f, 20f), "Host"))
{
manager.StartHost();
Manager.StartHost();
}
num2 += 24;
yOffset += 20;
}
if (GUI.Button(new Rect(num, num2, 105f, 20f), "Connect"))
if (GUI.Button(new Rect(xOffset, yOffset, 105f, 20f), "Connect"))
{
manager.StartClient();
Manager.StartClient();
}
manager.networkAddress = GUI.TextField(new Rect(num + 100, num2, 95f, 20f), manager.networkAddress);
num2 += 24;
Manager.networkAddress = GUI.TextField(new Rect(xOffset + 100, yOffset, 95f, 20f), Manager.networkAddress);
yOffset += 20;
}
else
{
GUI.Label(new Rect(num, num2, 200f, 20f),
$"Connecting to {manager.networkAddress}:{manager.networkPort}..");
num2 += 24;
if (GUI.Button(new Rect(num, num2, 200f, 20f), "Cancel Connection Attempt"))
GUI.Label(new Rect(xOffset, yOffset, 200f, 20f),
$"Connecting to {Manager.networkAddress}:{Manager.networkPort}..");
yOffset += 24;
if (GUI.Button(new Rect(xOffset, yOffset, 200f, 20f), "Cancel Connection Attempt"))
{
manager.StopClient();
Manager.StopClient();
}
}
}
@ -52,39 +51,39 @@ namespace QuantumUNET.Components
{
if (QNetworkServer.active)
{
var text = $"Hosting on port {manager.networkPort}";
if (manager.useWebSockets)
var text = $"Hosting on port {Manager.networkPort}";
if (Manager.useWebSockets)
{
text += " (using WebSockets)";
}
GUI.Label(new Rect(num, num2, 300f, 20f), text);
num2 += 24;
GUI.Label(new Rect(xOffset, yOffset, 300f, 20f), text);
yOffset += 20;
}
if (manager.IsClientConnected())
if (Manager.IsClientConnected())
{
GUI.Label(new Rect(num, num2, 300f, 20f), $"Connected to {manager.networkAddress}, port {manager.networkPort}");
num2 += 24;
GUI.Label(new Rect(xOffset, yOffset, 300f, 20f), $"Connected to {Manager.networkAddress}, port {Manager.networkPort}");
yOffset += 20;
}
}
if (manager.IsClientConnected() && !QClientScene.ready)
if (Manager.IsClientConnected() && !QClientScene.ready)
{
if (GUI.Button(new Rect(num, num2, 200f, 20f), "Client Ready"))
if (GUI.Button(new Rect(xOffset, yOffset, 200f, 20f), "Client Ready"))
{
QClientScene.Ready(manager.client.connection);
QClientScene.Ready(Manager.client.connection);
if (QClientScene.localPlayers.Count == 0)
{
QClientScene.AddPlayer(0);
}
}
num2 += 24;
yOffset += 20;
}
if (QNetworkServer.active || manager.IsClientConnected())
if (QNetworkServer.active || Manager.IsClientConnected())
{
if (GUI.Button(new Rect(num, num2, 200f, 20f), "Stop"))
if (GUI.Button(new Rect(xOffset, yOffset, 200f, 20f), "Stop"))
{
manager.StopHost();
Manager.StopHost();
}
num2 += 24;
yOffset += 20;
}
}
}