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

Quantum sync fixes
This commit is contained in:
_nebula 2021-02-19 10:14:30 +00:00 committed by GitHub
commit 8c6b91d633
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 410 additions and 259 deletions

View File

@ -24,6 +24,7 @@ namespace QSB.ConversationSync
_boxPrefab = QSBCore.ConversationAssetBundle.LoadAsset<GameObject>("assets/dialoguebubble.prefab");
// TODO : make dynamic so it can be different sizes!
// the dynamic font seems to be super lo-res at this size...?
var font = (Font)Resources.Load(@"fonts\english - latin\spacemono-bold");
if (font == null)
{

View File

@ -12,7 +12,25 @@ namespace QSB.Player
{
public static class QSBPlayerManager
{
public static uint LocalPlayerId => PlayerTransformSync.LocalInstance?.NetIdentity?.NetId.Value ?? uint.MaxValue;
public static uint LocalPlayerId
{
get
{
var localInstance = PlayerTransformSync.LocalInstance;
if (localInstance == null)
{
DebugLog.DebugWrite($"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);
return uint.MaxValue;
}
return localInstance.NetIdentity.NetId.Value;
}
}
public static PlayerInfo LocalPlayer => GetPlayer(LocalPlayerId);
public static List<PlayerInfo> PlayerList { get; } = new List<PlayerInfo>();

View File

@ -210,6 +210,7 @@
<Compile Include="Utility\DebugBoxManager.cs" />
<Compile Include="Utility\DebugZOverride.cs" />
<Compile Include="Utility\Extensions.cs" />
<Compile Include="Utility\IRepeating.cs" />
<Compile Include="Utility\OnEnableDisableTracker.cs" />
<Compile Include="Utility\Popcron.Gizmos\Constants.cs" />
<Compile Include="Utility\Popcron.Gizmos\Drawers\CubeDrawer.cs" />
@ -221,6 +222,7 @@
<Compile Include="Utility\Popcron.Gizmos\Drawers\LineDrawer.cs" />
<Compile Include="Utility\Popcron.Gizmos\Drawers\PolygonDrawer.cs" />
<Compile Include="Utility\Popcron.Gizmos\Drawers\SquareDrawer.cs" />
<Compile Include="Utility\RepeatingManager.cs" />
<Compile Include="Utility\Tuple.cs" />
<Compile Include="Utility\UnitTestDetector.cs" />
<Compile Include="WorldSync\Events\BoolWorldObjectMessage.cs" />

View File

@ -6,14 +6,17 @@ using QSB.ElevatorSync;
using QSB.GeyserSync;
using QSB.OrbSync;
using QSB.Patches;
using QSB.Player;
using QSB.QuantumSync;
using QSB.SectorSync;
using QSB.TimeSync;
using QSB.TranslationSync;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using QuantumUNET.Components;
using System.Linq;
using System.Reflection;
using UnityEngine;
/*
@ -88,6 +91,7 @@ namespace QSB
gameObject.AddComponent<TimeSyncUI>();
gameObject.AddComponent<QuantumManager>();
gameObject.AddComponent<SpiralManager>();
gameObject.AddComponent<RepeatingManager>();
DebugBoxManager.Init();
@ -98,6 +102,77 @@ namespace QSB
public void Update() =>
QNetworkIdentity.UNetStaticUpdate();
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}");
if (!QSBCore.HasWokenUp || !QSBCore.DebugMode)
{
return;
}
if (QSBSceneManager.CurrentScene != OWScene.SolarSystem)
{
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;
var tracker = Locator.GetQuantumMoon().GetValue<ShapeVisibilityTracker>("_visibilityTracker");
foreach (var camera in QSBPlayerManager.GetPlayerCameras())
{
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;
}
// 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 socketedTrackers = socketedObject.AttachedObject.GetComponentsInChildren<ShapeVisibilityTracker>();
if (socketedTrackers == null || socketedTrackers.Length == 0)
{
GUI.Label(new Rect(220, offset, 200f, 20f), $"- List is null or empty.");
return;
}
if (socketedTrackers.Any(x => x is null))
{
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), $"- {camera.name} : {socketedTrackers.Any(x => (bool)x.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(x, new object[] { camera.GetFrustumPlanes() }))}");
offset += 30f;
}
*/
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(440, offset, 200f, 20f), $"- {(obj as IWorldObject).Name}");
offset += 30f;
}
}
public override void Configure(IModConfig config)
{
DefaultServerIP = config.GetSettingsValue<string>("defaultServerIP");

View File

@ -141,6 +141,11 @@ namespace QSB
{
QSBWorldSync.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
}
if (QSBSceneManager.IsInUniverse)
{
QSBCore.HasWokenUp = true;
}
}
public override void OnServerAddPlayer(QNetworkConnection connection, short playerControllerId) // Called on the server when a client joins
@ -173,9 +178,9 @@ namespace QSB
if (QSBSceneManager.IsInUniverse)
{
QSBSectorManager.Instance.RebuildSectors();
OrbManager.Instance.QueueBuildSlots();
QuantumManager.Instance.RebuildQuantumObjects(QSBSceneManager.CurrentScene);
QSBSectorManager.Instance?.RebuildSectors();
OrbManager.Instance?.QueueBuildSlots();
QuantumManager.Instance?.RebuildQuantumObjects(QSBSceneManager.CurrentScene);
}
var specificType = QNetworkServer.active ? QSBPatchTypes.OnServerClientConnect : QSBPatchTypes.OnNonServerClientConnect;
@ -215,6 +220,7 @@ namespace QSB
QSBPatchManager.DoUnpatchType(QSBPatchTypes.OnClientConnect);
_lobby.CanEditName = true;
QSBCore.HasWokenUp = false;
IsReady = false;
}
@ -232,8 +238,14 @@ namespace QSB
identity.RemoveClientAuthority(connection);
}
}
// Server takes some time to process removal of player/deletion of networkidentity
Invoke(nameof(LateFinalizeDisconnect), 1f);
}
private void LateFinalizeDisconnect()
=> QuantumManager.Instance.CheckExistingPlayers();
public override void OnStopServer()
{
DebugLog.DebugWrite("OnStopServer", MessageType.Info);
@ -244,9 +256,11 @@ namespace QSB
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
RemoveWorldObjects();
QSBCore.HasWokenUp = false;
base.OnStopServer();
}
private void RemoveWorldObjects()
{
QSBWorldSync.RemoveWorldObjects<QSBOrbSlot>();
@ -255,6 +269,5 @@ namespace QSB
QSBWorldSync.RemoveWorldObjects<QSBSector>();
QSBWorldSync.RemoveWorldObjects<IQSBQuantumObject>();
}
}
}

View File

@ -29,7 +29,6 @@ namespace QSB.QuantumSync.Events
{
return;
}
var moon = Locator.GetQuantumMoon();
var wasPlayerEntangled = moon.IsPlayerEntangled();
var location = new RelativeLocationData(Locator.GetPlayerTransform().GetComponent<OWRigidbody>(), moon.transform);
@ -49,7 +48,22 @@ namespace QSB.QuantumSync.Events
moonBody.SetVelocity(OWPhysics.CalculateOrbitVelocity(owRigidbody, moonBody, message.OrbitAngle) + owRigidbody.GetVelocity());
moon.SetValue("_stateIndex", message.StateIndex);
moon.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(moon, new object[] { message.StateIndex });
if (moon.IsPlayerInside())
{
moon.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(moon, new object[] { message.StateIndex });
}
else
{
moon.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(moon, new object[] { -1 });
moon.GetValue<AudioSignal>("_quantumSignal").SetSignalActivation(message.StateIndex != 5, 2f);
}
moon.GetValue<ReferenceFrameVolume>("_referenceFrameVolume").gameObject.SetActive(message.StateIndex != 5);
moonBody.SetIsTargetable(message.StateIndex != 5);
foreach (var obj in moon.GetValue<GameObject[]>("_deactivateAtEye"))
{
obj.SetActive(message.StateIndex != 5);
}
GlobalMessenger<OWRigidbody>.FireEvent("QuantumMoonChangeState", moonBody);
if (wasPlayerEntangled)
{

View File

@ -1,9 +1,5 @@
using OWML.Common;
using QSB.Events;
using QSB.Events;
using QSB.Player;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
namespace QSB.QuantumSync.Events
{
@ -30,36 +26,29 @@ namespace QSB.QuantumSync.Events
return false;
}
var objects = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>();
var obj = objects.ToList()[message.ObjectId];
var obj = QuantumManager.Instance.GetObject(message.ObjectId);
// Deciding if to change the object's owner
// Message
// | = 0 | > 0 |
// = 0 | Yes*| Yes |
// = 0 | No | Yes |
// > 0 | Yes | No |
// if Obj==Message then No
// Obj
// *Doesn't change anything,
// so can be yes or no
return obj.ControllingPlayer == 0 || message.AuthorityOwner == 0;
return (obj.ControllingPlayer == 0 || message.AuthorityOwner == 0)
&& (obj.ControllingPlayer != message.AuthorityOwner);
}
public override void OnReceiveLocal(bool server, QuantumAuthorityMessage message)
{
var objects = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>();
var obj = objects.ToList()[message.ObjectId];
var obj = QuantumManager.Instance.GetObject(message.ObjectId);
obj.ControllingPlayer = message.AuthorityOwner;
}
public override void OnReceiveRemote(bool server, QuantumAuthorityMessage message)
{
var objects = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>();
var obj = objects.ToList()[message.ObjectId];
if (obj.ControllingPlayer != 0 && message.AuthorityOwner != 0)
{
DebugLog.ToConsole($"Warning - object {(obj as IWorldObject).Name} already has owner {obj.ControllingPlayer}, but trying to be replaced by {message.AuthorityOwner}!", MessageType.Warning);
}
var obj = QuantumManager.Instance.GetObject(message.ObjectId);
obj.ControllingPlayer = message.AuthorityOwner;
if (obj.ControllingPlayer == 0 && obj.IsEnabled)
{

View File

@ -1,4 +1,5 @@
using QSB.Patches;
using System.Reflection;
namespace QSB.QuantumSync.Patches
{
@ -6,8 +7,20 @@ namespace QSB.QuantumSync.Patches
{
public override QSBPatchTypes Type => QSBPatchTypes.OnNonServerClientConnect;
public override void DoPatches() => QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumMoon>("ChangeQuantumState", typeof(ClientQuantumPatches), nameof(ReturnFalsePatch));
public override void DoUnpatches() => QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("ChangeQuantumState");
public override void DoPatches()
{
QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumMoon>("ChangeQuantumState", typeof(ClientQuantumPatches), nameof(ReturnFalsePatch));
QSBCore.Helper.HarmonyHelper.AddPostfix<QuantumMoon>("Start", typeof(ClientQuantumPatches), nameof(Moon_CollapseOnStart));
}
public override void DoUnpatches()
{
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("ChangeQuantumState");
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("Start");
}
public static void Moon_CollapseOnStart(QuantumMoon __instance)
=> __instance.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { -1 });
public static bool ReturnFalsePatch() => false;
}

View File

@ -7,6 +7,7 @@ using QSB.WorldSync;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace QSB.QuantumSync.Patches
@ -26,6 +27,7 @@ namespace QSB.QuantumSync.Patches
QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumShrine>("ChangeQuantumState", typeof(QuantumPatches), nameof(Shrine_ChangeQuantumState));
QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumShrine>("OnEntry", typeof(QuantumPatches), nameof(Shrine_OnEntry));
QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumShrine>("OnExit", typeof(QuantumPatches), nameof(Shrine_OnExit));
QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumMoon>("CheckPlayerFogProximity", typeof(QuantumPatches), nameof(Moon_CheckPlayerFogProximity));
}
public override void DoUnpatches()
@ -39,33 +41,31 @@ namespace QSB.QuantumSync.Patches
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumShrine>("ChangeQuantumState");
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumShrine>("OnEntry");
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumShrine>("OnExit");
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("CheckPlayerFogProximity");
}
public static bool Socketed_ChangeQuantumState(SocketedQuantumObject __instance)
=> QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject>(QuantumManager.Instance.GetId(__instance)).ControllingPlayer == QSBPlayerManager.LocalPlayerId;
=> QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject, SocketedQuantumObject>(__instance).ControllingPlayer == QSBPlayerManager.LocalPlayerId;
public static void Socketed_MoveToSocket(SocketedQuantumObject __instance, QuantumSocket socket)
{
var id = QuantumManager.Instance.GetId(__instance);
var worldObject = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject>(id);
if (worldObject == null)
var objectWorldObject = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject, SocketedQuantumObject>(__instance);
var socketWorldObject = QSBWorldSync.GetWorldObject<QSBQuantumSocket, QuantumSocket>(socket);
if (objectWorldObject == null)
{
DebugLog.ToConsole($"Worldobject is null for id {id}!");
DebugLog.ToConsole($"Worldobject is null for {__instance.name}!");
return;
}
if (worldObject.ControllingPlayer != QSBPlayerManager.LocalPlayerId)
if (objectWorldObject.ControllingPlayer != QSBPlayerManager.LocalPlayerId)
{
return;
}
var objId = QuantumManager.Instance.GetId(__instance);
var socketId = QuantumManager.Instance.GetId(socket);
//DebugLog.DebugWrite($"{__instance.name} to socket {socketId}");
QSBEventManager.FireEvent(
EventNames.QSBSocketStateChange,
objId,
socketId,
objectWorldObject.ObjectId,
socketWorldObject.ObjectId,
__instance.transform.localRotation);
}
@ -76,7 +76,8 @@ namespace QSB.QuantumSync.Patches
ref Transform[] ____shuffledObjects,
ref bool __result)
{
if (QSBWorldSync.GetWorldObject<QSBQuantumShuffleObject>(QuantumManager.Instance.GetId(__instance)).ControllingPlayer != QSBPlayerManager.LocalPlayerId)
var shuffleWorldObject = QSBWorldSync.GetWorldObject<QSBQuantumShuffleObject, QuantumShuffleObject>(__instance);
if (shuffleWorldObject.ControllingPlayer != QSBPlayerManager.LocalPlayerId)
{
return false;
}
@ -97,7 +98,7 @@ namespace QSB.QuantumSync.Patches
//DebugLog.DebugWrite($"{__instance.name} shuffled.");
QSBEventManager.FireEvent(
EventNames.QSBQuantumShuffle,
QuantumManager.Instance.GetId(__instance),
shuffleWorldObject.ObjectId,
____indexList.ToArray());
__result = true;
return false;
@ -105,7 +106,7 @@ namespace QSB.QuantumSync.Patches
public static bool MultiState_ChangeQuantumState(MultiStateQuantumObject __instance)
{
var qsbObj = QSBWorldSync.GetWorldObject<QSBMultiStateQuantumObject>(QuantumManager.Instance.GetId(__instance));
var qsbObj = QSBWorldSync.GetWorldObject<QSBMultiStateQuantumObject, MultiStateQuantumObject>(__instance);
var isInControl = qsbObj.ControllingPlayer == QSBPlayerManager.LocalPlayerId;
return isInControl;
}
@ -126,7 +127,7 @@ namespace QSB.QuantumSync.Patches
//DebugLog.DebugWrite($"{owner.AttachedObject.name} to quantum state {Array.IndexOf(owner.QuantumStates, __instance)}");
QSBEventManager.FireEvent(
EventNames.QSBMultiStateChange,
QuantumManager.Instance.GetId(owner.AttachedObject),
owner.ObjectId,
Array.IndexOf(owner.QuantumStates, __instance));
}
@ -144,7 +145,8 @@ namespace QSB.QuantumSync.Patches
var playersInMoon = QSBPlayerManager.PlayerList.Where(x => x.IsInMoon);
if (playersInMoon.Any(x => !x.IsInShrine)
|| playersInMoon.Any(x => x.FlashLight != null && x.FlashLight.FlashlightOn)
|| (QSBPlayerManager.LocalPlayer.IsInShrine && PlayerState.IsFlashlightOn()))
|| (QSBPlayerManager.LocalPlayer.IsInShrine && PlayerState.IsFlashlightOn())
|| playersInMoon.Count() == 0)
{
__result = false;
return false;
@ -158,7 +160,8 @@ namespace QSB.QuantumSync.Patches
public static bool Shrine_ChangeQuantumState(QuantumShrine __instance)
{
var isInControl = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject>(QuantumManager.Instance.GetId(__instance)).ControllingPlayer == QSBPlayerManager.LocalPlayerId;
var shrineWorldObject = QSBWorldSync.GetWorldObject<QSBSocketedQuantumObject, SocketedQuantumObject>(__instance);
var isInControl = shrineWorldObject.ControllingPlayer == QSBPlayerManager.LocalPlayerId;
return isInControl;
}
@ -203,5 +206,83 @@ namespace QSB.QuantumSync.Patches
}
return false;
}
public static bool Moon_CheckPlayerFogProximity(
QuantumMoon __instance,
int ____stateIndex,
float ____eyeStateFogOffset,
ref bool ____isPlayerInside,
float ____fogRadius,
float ____fogThickness,
float ____fogRolloffDistance,
string ____revealFactID,
OWRigidbody ____moonBody,
bool ____hasSunCollapsed,
Transform ____vortexReturnPivot,
OWAudioSource ____vortexAudio,
ref int ____collapseToIndex,
VisibilityTracker ____visibilityTracker,
QuantumFogEffectBubbleController ____playerFogBubble,
QuantumFogEffectBubbleController ____shipLandingCamFogBubble)
{
var playerDistance = Vector3.Distance(__instance.transform.position, Locator.GetPlayerCamera().transform.position);
var fogOffset = (____stateIndex != 5) ? 0f : ____eyeStateFogOffset;
var distanceFromFog = playerDistance - (____fogRadius + fogOffset);
var fogAlpha = 0f;
if (!____isPlayerInside)
{
fogAlpha = Mathf.InverseLerp(____fogThickness + ____fogRolloffDistance, ____fogThickness, distanceFromFog);
if (distanceFromFog < 0f)
{
if ((bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) || QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true))
{
____isPlayerInside = true;
__instance.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { ____stateIndex });
Locator.GetShipLogManager().RevealFact(____revealFactID, true, true);
QSBEventManager.FireEvent("PlayerEnterQuantumMoon");
}
else
{
__instance.GetType().GetMethod("Collapse", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { true });
}
}
}
else if (____isPlayerInside)
{
fogAlpha = Mathf.InverseLerp(-____fogThickness - ____fogRolloffDistance, -____fogThickness, distanceFromFog);
if (distanceFromFog >= 0f)
{
if (____stateIndex != 5)
{
____isPlayerInside = false;
if (!(bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) && !QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true))
{
__instance.GetType().GetMethod("Collapse", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { true });
}
__instance.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { -1 });
QSBEventManager.FireEvent("PlayerExitQuantumMoon");
}
else
{
var vector = Locator.GetPlayerTransform().position - __instance.transform.position;
Locator.GetPlayerBody().SetVelocity(____moonBody.GetPointVelocity(Locator.GetPlayerTransform().position) - (vector.normalized * 5f));
var d = 80f;
Locator.GetPlayerBody().SetPosition(__instance.transform.position + (____vortexReturnPivot.up * d));
if (!Physics.autoSyncTransforms)
{
Physics.SyncTransforms();
}
var component = Locator.GetPlayerCamera().GetComponent<PlayerCameraController>();
component.SetDegreesY(component.GetMinDegreesY());
____vortexAudio.SetLocalVolume(0f);
____collapseToIndex = 1;
__instance.GetType().GetMethod("Collapse", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { true });
}
}
}
____playerFogBubble.SetFogAlpha(fogAlpha);
____shipLandingCamFogBubble.SetFogAlpha(fogAlpha);
return false;
}
}
}

View File

@ -40,7 +40,7 @@ namespace QSB.QuantumSync.Patches
return false;
}
// RendererVisibilityTracker patches
// RendererVisibilityTracker patches - probably not needed as i don't think RendererVisibilityTracker is ever used?
public static bool RenderIsVisibleUsingCameraFrustum(RendererVisibilityTracker __instance, ref bool __result, Renderer ____renderer, bool ____checkFrustumOcclusion)
{

View File

@ -13,16 +13,10 @@ namespace QSB.QuantumSync.Patches
public override QSBPatchTypes Type => QSBPatchTypes.OnServerClientConnect;
public override void DoPatches()
{
QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumMoon>("ChangeQuantumState", typeof(ServerQuantumPatches), nameof(Moon_ChangeQuantumState));
QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumMoon>("CheckPlayerFogProximity", typeof(ServerQuantumPatches), nameof(Moon_CheckPlayerFogProximity));
}
=> QSBCore.Helper.HarmonyHelper.AddPrefix<QuantumMoon>("ChangeQuantumState", typeof(ServerQuantumPatches), nameof(Moon_ChangeQuantumState));
public override void DoUnpatches()
{
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("ChangeQuantumState");
QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("CheckPlayerFogProximity");
}
=> QSBCore.Helper.HarmonyHelper.Unpatch<QuantumMoon>("ChangeQuantumState");
public static bool Moon_ChangeQuantumState(
QuantumMoon __instance,
@ -86,7 +80,7 @@ namespace QSB.QuantumSync.Patches
}
if (orbitIndex == -1)
{
UnityEngine.Debug.LogError("QUANTUM MOON FAILED TO FIND ORBIT FOR STATE " + stateIndex);
DebugLog.ToConsole($"Error - QM failed to find orbit for state {stateIndex}", MessageType.Error);
}
var orbitRadius = (orbitIndex == -1) ? 10000f : ____orbits[orbitIndex].GetOrbitRadius();
var owRigidbody = (orbitIndex == -1) ? Locator.GetAstroObject(AstroObject.Name.Sun).GetOWRigidbody() : ____orbits[orbitIndex].GetAttachedOWRigidbody();
@ -137,7 +131,7 @@ namespace QSB.QuantumSync.Patches
}
else
{
UnityEngine.Debug.LogError("Quantum moon orbit position occupied! Aborting collapse.");
DebugLog.DebugWrite("Warning - Quantum moon orbit position occupied! Aborting collapse.", MessageType.Warning);
}
}
if (flag)
@ -157,93 +151,12 @@ namespace QSB.QuantumSync.Patches
{
____deactivateAtEye[l].SetActive(____stateIndex != 5);
}
QSBEventManager.FireEvent("QuantumMoonChangeState", ____moonBody);
GlobalMessenger<OWRigidbody>.FireEvent("QuantumMoonChangeState", ____moonBody);
__result = true;
return false;
}
__result = false;
return false;
}
public static bool Moon_CheckPlayerFogProximity(
QuantumMoon __instance,
int ____stateIndex,
float ____eyeStateFogOffset,
ref bool ____isPlayerInside,
float ____fogRadius,
float ____fogThickness,
float ____fogRolloffDistance,
string ____revealFactID,
OWRigidbody ____moonBody,
bool ____hasSunCollapsed,
Transform ____vortexReturnPivot,
OWAudioSource ____vortexAudio,
ref int ____collapseToIndex,
VisibilityTracker ____visibilityTracker,
QuantumFogEffectBubbleController ____playerFogBubble,
QuantumFogEffectBubbleController ____shipLandingCamFogBubble)
{
var playerDistance = Vector3.Distance(__instance.transform.position, Locator.GetPlayerCamera().transform.position);
var fogOffset = (____stateIndex != 5) ? 0f : ____eyeStateFogOffset;
var distanceFromFog = playerDistance - (____fogRadius + fogOffset);
var fogAlpha = 0f;
if (!____isPlayerInside)
{
fogAlpha = Mathf.InverseLerp(____fogThickness + ____fogRolloffDistance, ____fogThickness, distanceFromFog);
if (distanceFromFog < 0f)
{
if ((bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) || QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true))
{
____isPlayerInside = true;
__instance.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { ____stateIndex });
Locator.GetShipLogManager().RevealFact(____revealFactID, true, true);
QSBEventManager.FireEvent("PlayerEnterQuantumMoon");
}
else
{
__instance.GetType().GetMethod("Collapse", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { true });
}
}
}
else if (____isPlayerInside)
{
fogAlpha = Mathf.InverseLerp(-____fogThickness - ____fogRolloffDistance, -____fogThickness, distanceFromFog);
if (distanceFromFog >= 0f)
{
if (____stateIndex != 5)
{
____isPlayerInside = false;
if (!(bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) && !QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true))
{
__instance.GetType().GetMethod("Collapse", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { true });
}
__instance.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { -1 });
QSBEventManager.FireEvent("PlayerExitQuantumMoon");
}
else
{
var vector = Locator.GetPlayerTransform().position - __instance.transform.position;
Locator.GetPlayerBody().SetVelocity(____moonBody.GetPointVelocity(Locator.GetPlayerTransform().position) - (vector.normalized * 5f));
var d = (!____hasSunCollapsed) ? (____fogRadius - 1f) : 80f;
Locator.GetPlayerBody().SetPosition(__instance.transform.position + (____vortexReturnPivot.up * d));
if (!Physics.autoSyncTransforms)
{
Physics.SyncTransforms();
}
var component = Locator.GetPlayerCamera().GetComponent<PlayerCameraController>();
component.SetDegreesY(component.GetMinDegreesY());
____vortexAudio.SetLocalVolume(0f);
____collapseToIndex = 1;
// TODO : Handle players exiting eye state when other players are still on eye state, etc...
__instance.GetType().GetMethod("Collapse", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { true });
}
}
}
____playerFogBubble.SetFogAlpha(fogAlpha);
____shipLandingCamFogBubble.SetFogAlpha(fogAlpha);
return false;
}
}
}

View File

@ -1,10 +1,9 @@
using OWML.Common;
using OWML.Utils;
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;
@ -14,11 +13,6 @@ namespace QSB.QuantumSync
internal class QuantumManager : MonoBehaviour
{
public static QuantumManager Instance { get; private set; }
private List<SocketedQuantumObject> _socketedQuantumObjects;
private List<MultiStateQuantumObject> _multiStateQuantumObjects;
private List<QuantumSocket> _quantumSockets;
private List<QuantumShuffleObject> _quantumShuffleObjects;
public QuantumShrine Shrine;
public bool IsReady;
@ -33,10 +27,10 @@ namespace QSB.QuantumSync
public void RebuildQuantumObjects(OWScene scene)
{
DebugLog.DebugWrite("Rebuilding quantum objects...", MessageType.Warning);
_socketedQuantumObjects = QSBWorldSync.Init<QSBSocketedQuantumObject, SocketedQuantumObject>();
_multiStateQuantumObjects = QSBWorldSync.Init<QSBMultiStateQuantumObject, MultiStateQuantumObject>();
_quantumSockets = QSBWorldSync.Init<QSBQuantumSocket, QuantumSocket>();
_quantumShuffleObjects = QSBWorldSync.Init<QSBQuantumShuffleObject, QuantumShuffleObject>();
QSBWorldSync.Init<QSBSocketedQuantumObject, SocketedQuantumObject>();
QSBWorldSync.Init<QSBMultiStateQuantumObject, MultiStateQuantumObject>();
QSBWorldSync.Init<QSBQuantumSocket, QuantumSocket>();
QSBWorldSync.Init<QSBQuantumShuffleObject, QuantumShuffleObject>();
if (scene == OWScene.SolarSystem)
{
Shrine = Resources.FindObjectsOfTypeAll<QuantumShrine>().First();
@ -44,6 +38,21 @@ namespace QSB.QuantumSync
IsReady = true;
}
public void CheckExistingPlayers()
{
DebugLog.DebugWrite("Checking quantum objects for non-existent players...", MessageType.Info);
var quantumObjects = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>().ToList();
for (var i = 0; i < quantumObjects.Count; i++)
{
var obj = quantumObjects[i];
if (!QSBPlayerManager.PlayerExists(obj.ControllingPlayer))
{
var idToSend = obj.IsEnabled ? QSBPlayerManager.LocalPlayerId : 0u;
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, i, idToSend);
}
}
}
public void OnRenderObject()
{
if (!QSBCore.HasWokenUp || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug)
@ -57,94 +66,32 @@ namespace QSB.QuantumSync
}
}
public void OnGUI()
{
if (!QSBCore.HasWokenUp || !QSBCore.DebugMode)
{
return;
}
if (QSBSceneManager.CurrentScene != OWScene.SolarSystem)
{
return;
}
GUI.Label(new Rect(220, 10, 200f, 20f), $"QM Visible : {Locator.GetQuantumMoon().IsVisible()}");
var offset = 40f;
var tracker = Locator.GetQuantumMoon().GetValue<ShapeVisibilityTracker>("_visibilityTracker");
foreach (var camera in QSBPlayerManager.GetPlayerCameras())
{
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;
}
// 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 socketedTrackers = socketedObject.AttachedObject.GetComponentsInChildren<ShapeVisibilityTracker>();
if (socketedTrackers == null || socketedTrackers.Length == 0)
{
GUI.Label(new Rect(220, offset, 200f, 20f), $"- List is null or empty.");
return;
}
if (socketedTrackers.Any(x => x is null))
{
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), $"- {camera.name} : {socketedTrackers.Any(x => (bool)x.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(x, new object[] { camera.GetFrustumPlanes() }))}");
offset += 30f;
}
*/
offset = 10f;
GUI.Label(new Rect(440, offset, 200f, 20f), $"Players in QM :");
offset += 30f;
foreach (var player in QSBPlayerManager.PlayerList.Where(x => x.IsInMoon))
{
GUI.Label(new Rect(440, offset, 200f, 20f), $"- {player.PlayerId}");
offset += 30f;
}
GUI.Label(new Rect(440, offset, 200f, 20f), $"Players in Shrine :");
offset += 30f;
foreach (var player in QSBPlayerManager.PlayerList.Where(x => x.IsInShrine))
{
GUI.Label(new Rect(440, offset, 200f, 20f), $"- {player.PlayerId}");
offset += 30f;
}
}
public static bool IsVisibleUsingCameraFrustum(ShapeVisibilityTracker tracker, bool skipVisibilityCheck)
public static bool IsVisibleUsingCameraFrustum(ShapeVisibilityTracker tracker, bool ignoreLocalCamera)
{
return tracker.gameObject.activeInHierarchy
&& QSBPlayerManager.GetPlayerCameras(!skipVisibilityCheck)
&& QSBPlayerManager.GetPlayerCameras(!ignoreLocalCamera)
.Any(x => (bool)tracker.GetType()
.GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(tracker, new object[] { x.GetFrustumPlanes() }));
}
public static bool IsVisible(ShapeVisibilityTracker tracker, bool skipVisibilityCheck)
public static bool IsVisible(ShapeVisibilityTracker tracker, bool ignoreLocalCamera)
{
return tracker.gameObject.activeInHierarchy
&& IsVisibleUsingCameraFrustum(tracker, skipVisibilityCheck)
&& QSBPlayerManager.GetPlayerCameras(!skipVisibilityCheck)
&& IsVisibleUsingCameraFrustum(tracker, ignoreLocalCamera)
&& QSBPlayerManager.GetPlayerCameras(!ignoreLocalCamera)
.Any(x => VisibilityOccluder.CanYouSee(tracker, x.mainCamera.transform.position));
}
public int GetId(SocketedQuantumObject obj) => _socketedQuantumObjects.IndexOf(obj);
public int GetId(MultiStateQuantumObject obj) => _multiStateQuantumObjects.IndexOf(obj);
public int GetId(QuantumSocket obj) => _quantumSockets.IndexOf(obj);
public int GetId(QuantumShuffleObject obj) => _quantumShuffleObjects.IndexOf(obj);
public int GetId(IQSBQuantumObject obj)
=> QSBWorldSync
.GetWorldObjects<IQSBQuantumObject>()
.ToList()
.IndexOf(obj);
public IQSBQuantumObject GetObject(int id)
=> QSBWorldSync
.GetWorldObjects<IQSBQuantumObject>()
.ToList()[id];
}
}

View File

@ -2,7 +2,6 @@
using QSB.Player;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
using UnityEngine;
namespace QSB.QuantumSync.WorldObjects
@ -28,18 +27,22 @@ namespace QSB.QuantumSync.WorldObjects
_tracker.AttachedComponent = AttachedObject;
_tracker.OnEnableEvent += OnEnable;
_tracker.OnDisableEvent += OnDisable;
ControllingPlayer = 1u;
ControllingPlayer = 0u;
}
private void OnEnable()
{
IsEnabled = true;
if (!QSBCore.HasWokenUp && !QSBCore.IsServer)
{
return;
}
if (ControllingPlayer != 0)
{
// controlled by another player, dont care that we activate it
return;
}
var id = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>().ToList().IndexOf(this);
var id = QuantumManager.Instance.GetId(this);
// no one is controlling this object right now, request authority
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, id, QSBPlayerManager.LocalPlayerId);
}
@ -47,14 +50,18 @@ namespace QSB.QuantumSync.WorldObjects
private void OnDisable()
{
IsEnabled = false;
if (!QSBCore.HasWokenUp && !QSBCore.IsServer)
{
return;
}
if (ControllingPlayer != QSBPlayerManager.LocalPlayerId)
{
// not being controlled by us, don't care if we leave area
return;
}
var id = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>().ToList().IndexOf(this);
var id = QuantumManager.Instance.GetId(this);
// send event to other players that we're releasing authority
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, id, 0);
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, id, 0u);
}
}
}

View File

@ -50,7 +50,7 @@ namespace QSB.TimeSync
private void OnWakeUp()
{
DebugLog.DebugWrite($"OnWakeUp", OWML.Common.MessageType.Info);
DebugLog.DebugWrite($"OnWakeUp", MessageType.Info);
if (QNetworkServer.active)
{
QSBCore.HasWokenUp = true;

View File

@ -11,7 +11,8 @@ namespace QSB.TransformSync
static PlayerTransformSync() => AnimControllerPatch.Init();
public override void OnStartLocalPlayer() => LocalInstance = this;
public override void OnStartLocalPlayer()
=> LocalInstance = this;
protected override void OnDestroy()
{

View File

@ -0,0 +1,7 @@
namespace QSB.Utility
{
public interface IRepeating
{
void Invoke();
}
}

View File

@ -1,31 +1,53 @@
using System;
using OWML.Utils;
using System;
using System.Linq;
using UnityEngine;
namespace QSB.Utility
{
public class OnEnableDisableTracker : MonoBehaviour
public class OnEnableDisableTracker : MonoBehaviour, IRepeating
{
public event Action OnEnableEvent;
public event Action OnDisableEvent;
public MonoBehaviour AttachedComponent;
public MonoBehaviour AttachedComponent
{
get => _attachedComponent;
set
{
_attachedComponent = value;
_visibilityTrackers = _attachedComponent.GetValue<VisibilityTracker[]>("_visibilityTrackers");
}
}
private MonoBehaviour _attachedComponent;
private VisibilityTracker[] _visibilityTrackers;
private ComponentState _wasEnabled = ComponentState.NotChecked;
public OnEnableDisableTracker()
=> QSBSceneManager.OnSceneLoaded += (OWScene scene, bool inUniverse) => Destroy(this);
{
RepeatingManager.Repeatings.Add(this);
QSBSceneManager.OnSceneLoaded += (OWScene scene, bool inUniverse) => Destroy(this);
}
private void OnDestroy()
=> QSBSceneManager.OnSceneLoaded -= (OWScene scene, bool inUniverse) => Destroy(this);
{
RepeatingManager.Repeatings.Remove(this);
QSBSceneManager.OnSceneLoaded -= (OWScene scene, bool inUniverse) => Destroy(this);
}
private void Update()
private bool GetAnyVisibilityTrackersActive()
=> _visibilityTrackers.All(x => x.GetValue<Shape[]>("_shapes").All(y => y.enabled));
public void Invoke()
{
if (AttachedComponent == null)
{
DebugLog.ToConsole($"Attached component is null!", OWML.Common.MessageType.Error);
return;
}
var state = AttachedComponent.isActiveAndEnabled ? ComponentState.Enabled : ComponentState.Disabled;
var state = AttachedComponent.isActiveAndEnabled && GetAnyVisibilityTrackersActive() ? ComponentState.Enabled : ComponentState.Disabled;
if (_wasEnabled != state)
{
_wasEnabled = state;

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using UnityEngine;
namespace QSB.Utility
{
internal class RepeatingManager : MonoBehaviour
{
public static List<IRepeating> Repeatings = new List<IRepeating>();
private const float TimeInterval = 0.2f;
private float _checkTimer = TimeInterval;
private void Update()
{
_checkTimer += Time.unscaledDeltaTime;
if (_checkTimer < TimeInterval)
{
return;
}
foreach (var repeat in Repeatings)
{
repeat.Invoke();
}
_checkTimer = 0;
}
}
}

View File

@ -3,15 +3,15 @@ using System.Linq;
namespace QSB.Utility
{
public static class UnitTestDetector
{
static UnitTestDetector()
{
var testAssemblyName = "Microsoft.VisualStudio.TestPlatform.TestFramework";
IsInUnitTest = AppDomain.CurrentDomain.GetAssemblies()
.Any(a => a.FullName.StartsWith(testAssemblyName));
}
public static class UnitTestDetector
{
public static bool IsInUnitTest { get; private set; }
public static bool IsInUnitTest { get; private set; }
}
}
static UnitTestDetector()
{
var testAssemblyName = "Microsoft.VisualStudio.TestPlatform.TestFramework";
IsInUnitTest = AppDomain.CurrentDomain.GetAssemblies()
.Any(a => a.FullName.StartsWith(testAssemblyName));
}
}
}

View File

@ -27,6 +27,20 @@ namespace QSB.WorldSync
where TWorldObject : IWorldObject
=> GetWorldObjects<TWorldObject>().FirstOrDefault(x => x.ObjectId == id);
public static TWorldObject GetWorldObject<TWorldObject, TUnityObject>(TUnityObject unityObject)
where TWorldObject : WorldObject<TUnityObject>
where TUnityObject : MonoBehaviour
{
var allWorldObjects = GetWorldObjects<TWorldObject>();
if (allWorldObjects.Count() == 0)
{
DebugLog.ToConsole($"Error - No worldobjects exist of type {typeof(TWorldObject).Name}!", MessageType.Error);
return null;
}
var correctWorldObject = allWorldObjects.First(x => x.AttachedObject == unityObject);
return correctWorldObject;
}
public static void RemoveWorldObjects<TWorldObject>()
{
var itemsToRemove = WorldObjects.Where(x => x is TWorldObject);
@ -34,7 +48,7 @@ namespace QSB.WorldSync
{
item.OnRemoval();
}
DebugLog.DebugWrite($"Removing types {typeof(TWorldObject).Name}.");
DebugLog.DebugWrite($"Removing {typeof(TWorldObject).Name} : {WorldObjects.Count(x => x is TWorldObject)} instances.");
WorldObjects.RemoveAll(x => x is TWorldObject);
}
@ -42,6 +56,7 @@ namespace QSB.WorldSync
where TWorldObject : WorldObject<TUnityObject>
where TUnityObject : MonoBehaviour
{
RemoveWorldObjects<TWorldObject>();
var list = Resources.FindObjectsOfTypeAll<TUnityObject>().ToList();
DebugLog.DebugWrite($"{typeof(TWorldObject).Name} init : {list.Count} instances.", MessageType.Info);
for (var id = 0; id < list.Count; id++)

View File

@ -1,9 +1,9 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using QSB.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using QSB.Events;
namespace QSBTests
{

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("QSBTests")]

View File

@ -7,7 +7,7 @@ namespace QSBTests
public class UtilityTests
{
[TestMethod]
public void IsInUnitTest()
public void IsInUnitTest()
=> Assert.IsTrue(UnitTestDetector.IsInUnitTest, "UnitTestDetector is not working.");
}
}

View File

@ -8,7 +8,7 @@
public const int ErrorType = 3;
public const int FatalErrorType = 4;
private static int _currentLog;
private static int _currentLog = 2;
private static bool _logDebug => _currentLog <= 0;
private static bool _logLog => _currentLog <= 1;
private static bool _logWarning => _currentLog <= 2;

View File

@ -31,6 +31,11 @@ namespace QuantumUNET
get
{
QNetworkIdentity myView;
if (gameObject == null)
{
QLog.FatalError($"Trying to get QNetworkIdentity of a null gameobject?");
return null;
}
if (m_MyView == null)
{
m_MyView = GetComponent<QNetworkIdentity>();

View File

@ -1,9 +1,11 @@
# Quantum Space Buddies - Outer Wilds Online Multiplayer Mod
![logo](unknown.png)
Quantum Space Buddies (QSB) is a multiplayer mod for Outer Wilds. The mod uses the OWML mod loader and customized UNET code (internally referred to as QNet or QuantumUNET) for networking.
## License
QNet code adapted in part from Unity Technologies' UNET.
Copyright (C) 2020 - 2021 : Henry Pointer (_nebula or misternebula) - Aleksander Waage (AmazingAlek) - Ricardo Lopes (Raicuparta)
This program is free software: you can redistribute it and/or modify

BIN
unknown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB