Merge pull request #581 from misternebula/nh-stuff

Nh stuff
This commit is contained in:
_nebula 2022-12-10 22:05:30 +00:00 committed by GitHub
commit 206dadcfdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 150 additions and 28 deletions

View File

@ -17,6 +17,11 @@ public class SolanumPatches : QSBPatch
[HarmonyPatch(typeof(SolanumAnimController), nameof(SolanumAnimController.LateUpdate))]
public static bool SolanumLateUpdateReplacement(SolanumAnimController __instance)
{
if (!QSBWorldSync.AllObjectsReady)
{
return true;
}
if (__instance._animatorStateEvents == null)
{
__instance._animatorStateEvents = __instance._animator.GetBehaviour<AnimatorStateEvents>();
@ -43,6 +48,10 @@ public class SolanumPatches : QSBPatch
[HarmonyPatch(typeof(NomaiConversationManager), nameof(NomaiConversationManager.Update))]
public static bool ReplacementUpdate(NomaiConversationManager __instance)
{
if (!QSBWorldSync.AllObjectsReady)
{
return true;
}
var qsbObj = __instance._solanumAnimController.GetWorldObject<QSBSolanumAnimController>();
__instance._playerInWatchVolume = qsbObj.Trigger.Occupants.Any();
@ -206,4 +215,4 @@ public class SolanumPatches : QSBPatch
return false;
}
}
}

View File

@ -37,10 +37,13 @@ internal abstract class QSBRotatingElements<T, U> : LinkedWorldObject<T, U>
{
base.OnRemoval();
foreach (var lightSensor in _qsbLightSensors)
if (_qsbLightSensors != null)
{
lightSensor.OnDetectLocalLight -= OnDetectLocalLight;
lightSensor.OnDetectLocalDarkness -= OnDetectLocalDarkness;
foreach (var lightSensor in _qsbLightSensors)
{
lightSensor.OnDetectLocalLight -= OnDetectLocalLight;
lightSensor.OnDetectLocalDarkness -= OnDetectLocalDarkness;
}
}
}

View File

@ -1,9 +1,11 @@
using Cysharp.Threading.Tasks;
using OWML.Common;
using QSB.ItemSync.Messages;
using QSB.ItemSync.WorldObjects.Sockets;
using QSB.Messaging;
using QSB.Player;
using QSB.SectorSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using System.Threading;
using UnityEngine;

View File

@ -17,7 +17,9 @@ public class MeteorManager : WorldObjectManager
// wait for all late initializers (which includes meteor launchers) to finish
await UniTask.WaitUntil(() => LateInitializerManager.isDoneInitializing, cancellationToken: ct);
WhiteHoleVolume = QSBWorldSync.GetUnityObject<WhiteHoleVolume>();
// NH can make multiple so ensure its the stock whitehole
var whiteHole = QSBWorldSync.GetUnityObjects<AstroObject>().First(x => x.GetAstroObjectName() == AstroObject.Name.WhiteHole);
WhiteHoleVolume = whiteHole?.GetComponentInChildren<WhiteHoleVolume>();
QSBWorldSync.Init<QSBFragment, FragmentIntegrity>();
QSBWorldSync.Init<QSBMeteorLauncher, MeteorLauncher>();
QSBWorldSync.Init<QSBMeteor, MeteorController>();

View File

@ -37,6 +37,13 @@ internal class ModelShipManager : WorldObjectManager
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
{
// NH can remove this
var modelShip = QSBWorldSync.GetUnityObject<RemoteFlightConsole>()._modelShipBody;
if (!modelShip)
{
return;
}
if (QSBCore.IsHost)
{
Instantiate(QSBNetworkManager.singleton.ModelShipPrefab).SpawnWithServerAuthority();

View File

@ -69,11 +69,14 @@ public class QSBCore : ModBehaviour
public static DebugSettings DebugSettings { get; private set; } = new();
public static Storage Storage { get; private set; } = new();
public const string NEW_HORIZONS = "xen.NewHorizons";
public const string NEW_HORIZONS_COMPAT = "xen.NHQSBCompat";
public static readonly string[] IncompatibleMods =
{
// incompatible mods
"Raicuparta.NomaiVR",
"xen.NewHorizons",
// "xen.NewHorizons",
"Vesper.AutoResume",
"Vesper.OuterWildsMMO",
"_nebula.StopTime",
@ -127,6 +130,8 @@ public class QSBCore : ModBehaviour
Helper = ModHelper;
DebugLog.ToConsole($"* Start of QSB version {QSBVersion} - authored by {Helper.Manifest.Author}", MessageType.Info);
CheckCompatibilityMods();
DebugSettings = Helper.Storage.Load<DebugSettings>("debugsettings.json") ?? new DebugSettings();
Storage = Helper.Storage.Load<Storage>("storage.json") ?? new Storage();
@ -270,6 +275,26 @@ public class QSBCore : ModBehaviour
DebugLog.ToConsole($"DEBUG MODE = {DebugSettings.DebugMode}");
}
}
private void CheckCompatibilityMods()
{
var mainMod = "";
var compatMod = "";
var missingCompat = false;
if (Helper.Interaction.ModExists(NEW_HORIZONS) && !Helper.Interaction.ModExists(NEW_HORIZONS_COMPAT))
{
mainMod = NEW_HORIZONS;
compatMod = NEW_HORIZONS_COMPAT;
missingCompat = true;
}
if (missingCompat)
{
DebugLog.ToConsole($"FATAL - You have mod \"{mainMod}\" installed, which is not compatible with QSB without the compatibility mod \"{compatMod}\". " +
$"Either disable the mod, or install/enable the compatibility mod.", MessageType.Fatal);
}
}
}
/*

View File

@ -91,11 +91,15 @@ public class QSBSectorManager : WorldObjectManager
// time loop spinning ring
{
// NH can remove this
var TimeLoopRing_Body = GameObject.Find("TimeLoopRing_Body");
var Sector_TimeLoopInterior = GameObject.Find("Sector_TimeLoopInterior").GetComponent<Sector>();
// use the same trigger as the parent sector
FakeSector.Create(TimeLoopRing_Body, Sector_TimeLoopInterior,
x => x._triggerRoot = Sector_TimeLoopInterior._triggerRoot);
if (TimeLoopRing_Body)
{
var Sector_TimeLoopInterior = GameObject.Find("Sector_TimeLoopInterior").GetComponent<Sector>();
// use the same trigger as the parent sector
FakeSector.Create(TimeLoopRing_Body, Sector_TimeLoopInterior,
x => x._triggerRoot = Sector_TimeLoopInterior._triggerRoot);
}
}
// TH elevators

View File

@ -7,6 +7,7 @@ using System.Threading;
namespace QSB.Syncs.Occasional;
// BUG: somehow, not including DontDestroyOnLoad things makes this fuck up with NH
internal class OccasionalManager : WorldObjectManager
{
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
@ -21,6 +22,11 @@ internal class OccasionalManager : WorldObjectManager
foreach (var proxy in cannon._realDebrisSectorProxies)
{
// NH can remove these
if (!proxy)
{
continue;
}
SpawnOccasional(proxy.transform.root.GetAttachedOWRigidbody(), gdBody);
}
@ -58,4 +64,4 @@ internal class OccasionalManager : WorldObjectManager
Bodies.Clear();
}
}
}

View File

@ -11,6 +11,7 @@ using QSB.Utility;
using QSB.Utility.LinkedWorldObject;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using UnityEngine;
@ -20,7 +21,8 @@ namespace QSB.WorldSync;
public static class QSBWorldSync
{
public static WorldObjectManager[] Managers;
public static string WorldObjectsHash { get; private set; }
public static Dictionary<string, string> ManagerHashes { get; private set; } = new();
public static Dictionary<string, List<IWorldObject>> ManagerToBuiltObjects { get; private set; } = new();
/// <summary>
/// Set when all WorldObjectManagers have called Init() on all their objects (AKA all the objects are created)
@ -85,12 +87,20 @@ public static class QSBWorldSync
DeterministicManager.OnWorldObjectsAdded();
WorldObjectsHash = WorldObjects.Select(x => x.GetType().Name).GetMD5Hash();
DebugLog.DebugWrite($"WorldObject hash is {WorldObjectsHash}");
foreach (var item in ManagerToBuiltObjects)
{
var worldObjects = item.Value;
var hash = worldObjects.Select(x => x.GetType().Name).GetMD5Hash();
ManagerHashes[item.Key] = hash;
}
if (!QSBCore.IsHost)
{
new WorldObjectsHashMessage().Send();
foreach (var item in ManagerHashes)
{
new WorldObjectsHashMessage(item.Key, item.Value).Send();
}
new RequestLinksMessage().Send();
}
@ -135,6 +145,9 @@ public static class QSBWorldSync
AllObjectsAdded = false;
AllObjectsReady = false;
ManagerToBuiltObjects = new();
ManagerHashes = new();
GameReset();
foreach (var worldObject in WorldObjects)
@ -193,7 +206,8 @@ public static class QSBWorldSync
{
// So objects have time to be deleted, made, whatever
// i.e. wait until Start has been called
Delay.RunNextFrame(() => BuildWorldObjects(loadScene).Forget());
// TODO: see if this number of frames actually works. TWEAK!
Delay.RunFramesLater(10, () => BuildWorldObjects(loadScene).Forget());
}
};
@ -306,12 +320,55 @@ public static class QSBWorldSync
=> GetUnityObjects<TUnityObject>().Single();
/// <summary>
/// not deterministic across platforms
/// not deterministic across platforms.
/// excludes prefabs and DontDestroyOnLoad objects.
/// </summary>
public static IEnumerable<TUnityObject> GetUnityObjects<TUnityObject>()
where TUnityObject : MonoBehaviour
=> Resources.FindObjectsOfTypeAll<TUnityObject>()
.Where(x => x.gameObject.scene.name != null);
.Where(x => x.gameObject.scene.name is not (null or "DontDestroyOnLoad"));
// https://stackoverflow.com/a/48570616
public static string NameOfCallingClass()
{
string fullName;
Type declaringType;
var skipFrames = 2;
do
{
var method = new StackFrame(skipFrames, false).GetMethod();
declaringType = method.DeclaringType;
if (declaringType == null)
{
return method.Name;
}
skipFrames++;
fullName = CleanupFullName(declaringType.FullName);
}
while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase) || declaringType == typeof(QSBWorldSync));
return fullName;
}
private static string CleanupFullName(string fullName)
{
var ret = fullName;
var indexOfPlus = fullName.LastIndexOf('+');
if (indexOfPlus != -1)
{
ret = fullName.Remove(indexOfPlus);
}
var indexOfDot = ret.LastIndexOf('.');
if (indexOfDot != -1)
{
ret = ret.Substring(indexOfDot + 1);
}
return ret;
}
public static void Init<TWorldObject, TUnityObject>()
where TWorldObject : WorldObject<TUnityObject>, new()
@ -382,6 +439,17 @@ public static class QSBWorldSync
return;
}
var className = NameOfCallingClass();
if (!ManagerToBuiltObjects.ContainsKey(className))
{
ManagerToBuiltObjects.Add(className, new List<IWorldObject> { worldObject });
}
else
{
ManagerToBuiltObjects[className].Add(worldObject);
}
WorldObjects.Add(worldObject);
RequestInitialStatesMessage.SendInitialState += worldObject.SendInitialState;

View File

@ -8,23 +8,19 @@ namespace QSB.WorldSync;
/// <summary>
/// sends QSBWorldSync.WorldObjectsHash to the server for sanity checking
/// </summary>
internal class WorldObjectsHashMessage : QSBMessage<string>
internal class WorldObjectsHashMessage : QSBMessage<(string managerName, string hash)>
{
public WorldObjectsHashMessage() : base(QSBWorldSync.WorldObjectsHash) => To = 0;
public WorldObjectsHashMessage(string managerName, string hash) : base((managerName, hash)) => To = 0;
public override void OnReceiveRemote()
{
var serverHash = QSBWorldSync.WorldObjectsHash;
var serverHash = QSBWorldSync.ManagerHashes[Data.managerName];
if (serverHash != Data)
if (serverHash != Data.hash)
{
// oh fuck oh no oh god
DebugLog.ToConsole($"Kicking {From} because their WorldObjects hash is wrong. (server:{serverHash}, client:{Data})", MessageType.Error);
new PlayerKickMessage(From, $"WorldObject hash error. (Server:{serverHash}, Client:{Data})").Send();
}
else
{
DebugLog.DebugWrite($"WorldObject hash from {From} verified!", MessageType.Success);
DebugLog.ToConsole($"Kicking {From} because their WorldObjects hash for {Data.managerName} is wrong. (server:{serverHash}, client:{Data.hash})", MessageType.Error);
new PlayerKickMessage(From, $"WorldObject hash error for {Data.managerName}. (Server:{serverHash}, Client:{Data.hash})").Send();
}
}
}