diff --git a/APITestMod/APITestMod.csproj b/APITestMod/APITestMod.csproj
index c00112a83..de5cb3b87 100644
--- a/APITestMod/APITestMod.csproj
+++ b/APITestMod/APITestMod.csproj
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/APITestMod/manifest.json b/APITestMod/manifest.json
index 0c2a22a99..bf2d1eb90 100644
--- a/APITestMod/manifest.json
+++ b/APITestMod/manifest.json
@@ -4,6 +4,6 @@
"name": "QSB API Test Mod",
"uniqueName": "_nebula.QSBAPITest",
"version": "1.0.0",
- "owmlVersion": "2.9.7",
+ "owmlVersion": "2.11.1",
"dependencies": [ "Raicuparta.QuantumSpaceBuddies", "_nebula.MenuFramework" ]
}
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index b78eb8767..b5c0cce98 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -1,8 +1,8 @@
-> :warning: Warning! :warning:
-Mod development needs a powerful PC!
-Unexpected errors and issues may occur when editing networking code.
-Running multiple instances of the game can be very taxing on your computer.
-We're not responsible if you push your PC too hard.
+> [!WARNING]
+> Mod development needs a powerful PC!\
+> Unexpected errors and issues may occur when editing networking code.\
+> Running multiple instances of the game can be very taxing on your computer.\
+> We're not responsible if you push your PC too hard.
## Prerequisites
- Visual Studio 2022.
@@ -48,6 +48,9 @@ Use the API by copying [the API definition](https://github.com/misternebula/quan
## Debugging
### Debug Actions :
+> [!NOTE]
+> this list is slightly outdated. it will be updated when debug settings are updated
+
Press Q + Numpad Enter to toggle debug mode in game (corresponds with the debug setting "debugMode" in the section below).
Hold Q and press :
@@ -65,6 +68,9 @@ Hold Q and press :
### Debug Settings :
+> [!NOTE]
+> this list is slightly outdated because it will be replaced by mod options at some point
+
Create a file called `debugsettings.json` in the QSB folder.
The template for this file is this :
diff --git a/FizzySteamworks/FizzySteamworks.csproj b/FizzySteamworks/FizzySteamworks.csproj
index 3296f276a..92236d636 100644
--- a/FizzySteamworks/FizzySteamworks.csproj
+++ b/FizzySteamworks/FizzySteamworks.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/MirrorWeaver/MirrorWeaver.csproj b/MirrorWeaver/MirrorWeaver.csproj
index 45b7655b3..43603408d 100644
--- a/MirrorWeaver/MirrorWeaver.csproj
+++ b/MirrorWeaver/MirrorWeaver.csproj
@@ -17,8 +17,8 @@
-
-
+
+
diff --git a/QSB-NH/Patches/GameStateMessagePatches.cs b/QSB-NH/Patches/GameStateMessagePatches.cs
new file mode 100644
index 000000000..df2a746eb
--- /dev/null
+++ b/QSB-NH/Patches/GameStateMessagePatches.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HarmonyLib;
+using Mirror;
+using NewHorizons;
+using QSB;
+using QSB.Patches;
+using QSB.Player;
+using QSB.SaveSync.Messages;
+using QSB.Utility;
+
+namespace QSBNH.Patches;
+
+
+///
+/// extremely jank way to inject system and NH addons when joining.
+/// this should probably be split into its own separate message, but it doesnt really matter :P
+///
+/// BUG: completely explodes if one person has NH and the other does not
+///
+internal class GameStateMessagePatches : QSBPatch
+{
+ public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
+
+ private static string _initialSystem;
+ private static int[] _hostAddonHash;
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(GameStateMessage), nameof(GameStateMessage.Serialize))]
+ public static void GameStateMessage_Serialize(GameStateMessage __instance, NetworkWriter writer)
+ {
+ var currentSystem = QSBNH.Instance.NewHorizonsAPI.GetCurrentStarSystem();
+
+ writer.Write(currentSystem);
+ writer.WriteArray(QSBNH.HashAddonsForSystem(currentSystem));
+ }
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(GameStateMessage), nameof(GameStateMessage.Deserialize))]
+ public static void GameStateMessage_Deserialize(GameStateMessage __instance, NetworkReader reader)
+ {
+ _initialSystem = reader.Read();
+ _hostAddonHash = reader.ReadArray();
+ }
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(GameStateMessage), nameof(GameStateMessage.OnReceiveRemote))]
+ public static void GameStateMessage_OnReceiveRemote()
+ {
+ if (QSBCore.IsHost)
+ {
+ DebugLog.DebugWrite($"Why is the host being given the initial state info?");
+ }
+ else
+ {
+ DebugLog.DebugWrite($"Player#{QSBPlayerManager.LocalPlayerId} is being sent to {_initialSystem}");
+
+ WarpManager.RemoteChangeStarSystem(_initialSystem, false, false, _hostAddonHash);
+ }
+ }
+}
diff --git a/QSB-NH/Patches/NewHorizonsDataPatches.cs b/QSB-NH/Patches/NewHorizonsDataPatches.cs
new file mode 100644
index 000000000..ba949c3fb
--- /dev/null
+++ b/QSB-NH/Patches/NewHorizonsDataPatches.cs
@@ -0,0 +1,33 @@
+using HarmonyLib;
+using NewHorizons.External;
+using QSB;
+using QSB.Patches;
+using QSB.SaveSync;
+using QSB.Utility;
+
+namespace QSBNH.Patches;
+
+///
+/// pretends to be a new profile when in multiplayer so NH saves its data to a new place
+///
+public class NewHorizonsDataPatches : QSBPatch
+{
+ public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(NewHorizonsData), nameof(NewHorizonsData.GetProfileName))]
+ public static bool NewHorizonsData_GetProfileName(out string __result)
+ {
+ if (QSBCore.IsInMultiplayer)
+ {
+ __result = QSBStandaloneProfileManager.SharedInstance?.currentProfile?.profileName + "_mult";
+ DebugLog.DebugWrite($"using fake multiplayer profile {__result} for NH");
+ }
+ else
+ {
+ __result = QSBStandaloneProfileManager.SharedInstance?.currentProfile?.profileName;
+ }
+
+ return false;
+ }
+}
diff --git a/QSB-NH/QSB-NH.csproj b/QSB-NH/QSB-NH.csproj
new file mode 100644
index 000000000..3bd1280b8
--- /dev/null
+++ b/QSB-NH/QSB-NH.csproj
@@ -0,0 +1,32 @@
+
+
+
+ net48
+ QSBNH
+ enable
+ $(OwmlDir)\Mods\Raicuparta.QuantumSpaceBuddies
+ CS1998;CS0649
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\Lib\Mirror.dll
+
+
+ lib\NewHorizons.dll
+ false
+
+
+ ..\Lib\UniTask.dll
+
+
+
+
diff --git a/QSB-NH/QSBNH.cs b/QSB-NH/QSBNH.cs
new file mode 100644
index 000000000..01c8e2ad9
--- /dev/null
+++ b/QSB-NH/QSBNH.cs
@@ -0,0 +1,59 @@
+using Mirror;
+using NewHorizons;
+using OWML.Common;
+using OWML.ModHelper;
+using QSB;
+using QSB.Utility;
+using UnityEngine;
+
+namespace QSBNH
+{
+ public class QSBNH : MonoBehaviour
+ {
+ public static QSBNH Instance;
+
+ public INewHorizons NewHorizonsAPI;
+
+ private void Start()
+ {
+ Instance = this;
+ DebugLog.DebugWrite($"Start of QSB-NH compatibility code.", MessageType.Success);
+ NewHorizonsAPI = QSBCore.Helper.Interaction.TryGetModApi("xen.NewHorizons");
+ }
+
+ public static string HashToMod(int hash)
+ {
+ foreach (var mod in NewHorizons.Main.MountedAddons)
+ {
+ var name = mod.ModHelper.Manifest.UniqueName;
+ if (name.GetStableHashCode() == hash)
+ {
+ return name;
+ }
+ }
+
+ return null;
+ }
+
+ public static int[] HashAddonsForSystem(string system)
+ {
+ if (NewHorizons.Main.BodyDict.TryGetValue(system, out var bodies))
+ {
+ var addonHashes = bodies
+ .Where(x => x.Mod.ModHelper.Manifest.UniqueName != "xen.NewHorizons")
+ .Select(x => x.Mod.ModHelper.Manifest.UniqueName.GetStableHashCode())
+ .Distinct();
+
+ var nhPlanetHashes = bodies
+ .Where(x => x.Mod.ModHelper.Manifest.UniqueName == "xen.NewHorizons")
+ .Select(x => x.Config.name.GetStableHashCode());
+
+ return addonHashes.Concat(nhPlanetHashes).ToArray();
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+}
diff --git a/QSB-NH/QuantumPlanet/QuantumPlanetManager.cs b/QSB-NH/QuantumPlanet/QuantumPlanetManager.cs
new file mode 100644
index 000000000..540221656
--- /dev/null
+++ b/QSB-NH/QuantumPlanet/QuantumPlanetManager.cs
@@ -0,0 +1,13 @@
+using Cysharp.Threading.Tasks;
+using QSB.WorldSync;
+using QSBNH.QuantumPlanet.WorldObjects;
+
+namespace QSBNH.QuantumPlanet;
+public class QuantumPlanetManager : WorldObjectManager
+{
+ public override WorldObjectScene WorldObjectScene => WorldObjectScene.Both;
+ public override bool DlcOnly => false;
+
+ public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) =>
+ QSBWorldSync.Init();
+}
diff --git a/QSB-NH/QuantumPlanet/WorldObjects/QSBQuantumPlanet.cs b/QSB-NH/QuantumPlanet/WorldObjects/QSBQuantumPlanet.cs
new file mode 100644
index 000000000..dbafc8cc7
--- /dev/null
+++ b/QSB-NH/QuantumPlanet/WorldObjects/QSBQuantumPlanet.cs
@@ -0,0 +1,7 @@
+using QSB.QuantumSync.WorldObjects;
+
+namespace QSBNH.QuantumPlanet.WorldObjects;
+
+public class QSBQuantumPlanet : QSBQuantumObject
+{
+}
diff --git a/QSB-NH/WarpManager.cs b/QSB-NH/WarpManager.cs
new file mode 100644
index 000000000..6204856bb
--- /dev/null
+++ b/QSB-NH/WarpManager.cs
@@ -0,0 +1,167 @@
+using HarmonyLib;
+using NewHorizons;
+using QSB.Menus;
+using QSB.Messaging;
+using QSB.Player;
+using QSB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Mirror;
+using QSB.Patches;
+using QSB.Utility;
+
+namespace QSBNH;
+public static class WarpManager
+{
+ internal static bool RemoteWarp = false;
+
+ private static void Kick(string reason)
+ {
+ DebugLog.DebugWrite(reason);
+ MenuManager.Instance.OnKicked(reason);
+ NetworkClient.Disconnect();
+ }
+
+ public static void RemoteChangeStarSystem(string system, bool ship, bool vessel, int[] hostAddonHash)
+ {
+ // Flag to not send a message
+ RemoteWarp = true;
+
+ DebugLog.DebugWrite($"Remote request received to go to {system}");
+
+ if (!NewHorizons.Main.SystemDict.ContainsKey(system))
+ {
+ // If you can't go to that system then you have to be disconnected
+ Kick($"You don't have the mod installed for {system}");
+ }
+ else
+ {
+ var localHash = QSBNH.HashAddonsForSystem(system);
+ if (localHash != hostAddonHash)
+ {
+ var missingAddonHashes = hostAddonHash.Except(localHash);
+ var extraAddonHashes = localHash.Except(hostAddonHash);
+
+ if (missingAddonHashes.Count() > 0)
+ {
+ Kick($"You are missing {missingAddonHashes.Count()} addon(s) that effect {system}");
+ return;
+ }
+
+ if (extraAddonHashes.Count() > 0)
+ {
+ var extraMods = extraAddonHashes.Select(x => QSBNH.HashToMod(x));
+
+ // TODO: Disable these mods for the client and do not kick them
+
+ Kick($"You have {extraAddonHashes.Count()} extra addon(s) that effect {system}. Check the logs.");
+ DebugLog.DebugWrite($"You have mods affecting {system} that the host does not: {string.Join(", ", extraMods)}");
+ return;
+ }
+ }
+
+ NewHorizons.Main.Instance.ChangeCurrentStarSystem(system, ship, vessel);
+ }
+ }
+
+ public class NHWarpMessage : QSBMessage
+ {
+ private string _starSystem;
+ private bool _shipWarp;
+ private bool _vesselWarp;
+
+ public NHWarpMessage(string starSystem, bool shipWarp, bool vesselWarp) : base()
+ {
+ _starSystem = starSystem;
+ _shipWarp = shipWarp;
+ _vesselWarp = vesselWarp;
+ }
+
+ public override void Serialize(NetworkWriter writer)
+ {
+ base.Serialize(writer);
+
+ writer.Write(_starSystem);
+ writer.Write(_shipWarp);
+ writer.Write(_vesselWarp);
+ }
+
+ public override void Deserialize(NetworkReader reader)
+ {
+ base.Deserialize(reader);
+
+ _starSystem = reader.Read();
+ _shipWarp = reader.Read();
+ _vesselWarp = reader.Read();
+ }
+
+ public override void OnReceiveRemote()
+ {
+ DebugLog.DebugWrite($"Player#{From} is telling Player#{To} to warp to {_starSystem}");
+ if (QSBCore.IsHost && !NewHorizons.Main.SystemDict.ContainsKey(_starSystem))
+ {
+ // If the host doesn't have that system then we can't
+ DebugLog.DebugWrite($"The host doesn't have {_starSystem} installed: aborting");
+ }
+ else
+ {
+ if (QSBCore.IsHost)
+ {
+ new NHWarpMessage(_starSystem, _shipWarp, _vesselWarp).Send();
+ }
+
+ RemoteChangeStarSystem(_starSystem, _shipWarp, _vesselWarp, QSBNH.HashAddonsForSystem(_starSystem));
+ }
+ }
+ }
+
+ public class NHWarpPatch : QSBPatch
+ {
+ public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(NewHorizons.Main), nameof(NewHorizons.Main.ChangeCurrentStarSystem))]
+ public static bool NewHorizons_ChangeCurrentStarSystem(string newStarSystem, bool warp, bool vessel)
+ {
+ if (RemoteWarp)
+ {
+ // We're being told to warp so just do it
+ RemoteWarp = false;
+ return true;
+ }
+
+ DebugLog.DebugWrite($"Local request received to go to {newStarSystem}");
+ if (QSBCore.IsHost)
+ {
+ // The host will tell all other users to warp
+ DebugLog.DebugWrite($"Host: Telling others to go to {newStarSystem}");
+ new NHWarpMessage(newStarSystem, warp, vessel).Send();
+ // The host can now warp
+ return true;
+ }
+ else
+ {
+ // We're a client that has to tell the host to start warping people
+ DebugLog.DebugWrite($"Client: Telling host to send us to {newStarSystem}");
+ new NHWarpMessage(newStarSystem, warp, vessel) { To = 0 }.Send();
+
+ // We have to wait for the host to get back to us
+ return false;
+ }
+ }
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(NewHorizons.Main), nameof(NewHorizons.Main.ChangeCurrentStarSystem))]
+ public static void NewHorizons_ChangeCurrentStarSystem(NewHorizons.Main __instance)
+ {
+ if (__instance.IsWarpingFromShip)
+ {
+ // If QSB doesn't say we're piloting the ship then dont keep them on as the one warping
+ __instance.GetType().GetProperty(nameof(NewHorizons.Main.IsWarpingFromShip)).SetValue(__instance, QSBPlayerManager.LocalPlayer.FlyingShip);
+ }
+ }
+ }
+}
diff --git a/QSB-NH/lib/NewHorizons.dll b/QSB-NH/lib/NewHorizons.dll
new file mode 100644
index 000000000..83f0afc8a
Binary files /dev/null and b/QSB-NH/lib/NewHorizons.dll differ
diff --git a/QSB.sln b/QSB.sln
index 8bc9e6c9c..4b1d685bc 100644
--- a/QSB.sln
+++ b/QSB.sln
@@ -34,6 +34,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APITestMod", "APITestMod\AP
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QSBPatcher", "QSBPatcher\QSBPatcher.csproj", "{CA4CBA2B-54D5-4C4B-9B51-957BC6D77D6B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QSB-NH", "QSB-NH\QSB-NH.csproj", "{74F84A39-1C9D-4EF7-889A-485D33B7B324}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -64,6 +66,10 @@ Global
{CA4CBA2B-54D5-4C4B-9B51-957BC6D77D6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA4CBA2B-54D5-4C4B-9B51-957BC6D77D6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA4CBA2B-54D5-4C4B-9B51-957BC6D77D6B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {74F84A39-1C9D-4EF7-889A-485D33B7B324}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {74F84A39-1C9D-4EF7-889A-485D33B7B324}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {74F84A39-1C9D-4EF7-889A-485D33B7B324}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {74F84A39-1C9D-4EF7-889A-485D33B7B324}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/QSB/ConversationSync/ConversationManager.cs b/QSB/ConversationSync/ConversationManager.cs
index f394e6f23..a0205f5f5 100644
--- a/QSB/ConversationSync/ConversationManager.cs
+++ b/QSB/ConversationSync/ConversationManager.cs
@@ -9,6 +9,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
+using QSB.Utility.Deterministic;
using UnityEngine;
using UnityEngine.UI;
@@ -41,8 +42,9 @@ public void Start()
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
{
- QSBWorldSync.Init();
- QSBWorldSync.Init();
+ // dont create worldobjects for NH warp drive stuff
+ QSBWorldSync.Init(QSBWorldSync.GetUnityObjects().Where(x => x.name != "WarpDriveRemoteTrigger").SortDeterministic());
+ QSBWorldSync.Init(QSBWorldSync.GetUnityObjects().Where(x => x.name != "WarpDriveDialogue").SortDeterministic());
}
public uint GetPlayerTalkingToTree(CharacterDialogueTree tree) =>
diff --git a/QSB/ConversationSync/Messages/ConversationStartEndMessage.cs b/QSB/ConversationSync/Messages/ConversationStartEndMessage.cs
index 1a1d8eb2e..8e7baecfa 100644
--- a/QSB/ConversationSync/Messages/ConversationStartEndMessage.cs
+++ b/QSB/ConversationSync/Messages/ConversationStartEndMessage.cs
@@ -1,4 +1,5 @@
-using QSB.ConversationSync.WorldObjects;
+using OWML.Utils;
+using QSB.ConversationSync.WorldObjects;
using QSB.Messaging;
using QSB.Player;
using QSB.Utility;
diff --git a/QSB/ConversationSync/WorldObjects/QSBCharacterDialogueTree.cs b/QSB/ConversationSync/WorldObjects/QSBCharacterDialogueTree.cs
index a631214a2..4f1420f5e 100644
--- a/QSB/ConversationSync/WorldObjects/QSBCharacterDialogueTree.cs
+++ b/QSB/ConversationSync/WorldObjects/QSBCharacterDialogueTree.cs
@@ -1,4 +1,5 @@
using Cysharp.Threading.Tasks;
+using OWML.Utils;
using QSB.ConversationSync.Messages;
using QSB.Messaging;
using QSB.Player;
diff --git a/QSB/Localization/Translation.cs b/QSB/Localization/Translation.cs
index 2ee45acb3..8a2481307 100644
--- a/QSB/Localization/Translation.cs
+++ b/QSB/Localization/Translation.cs
@@ -33,7 +33,6 @@ public class Translation
public string DLCMismatch;
public string GameProgressLimit;
public string AddonMismatch;
- public string IncompatibleMod;
public string PlayerJoinedTheGame;
public string PlayerLeftTheGame;
public string PlayerWasKicked;
diff --git a/QSB/Menus/MenuManager.cs b/QSB/Menus/MenuManager.cs
index 549ec890e..bdee8f690 100644
--- a/QSB/Menus/MenuManager.cs
+++ b/QSB/Menus/MenuManager.cs
@@ -1,5 +1,6 @@
using Mirror;
using OWML.Common;
+using OWML.Utils;
using QSB.Localization;
using QSB.Messaging;
using QSB.Player.TransformSync;
@@ -646,6 +647,7 @@ private void Host(bool newMultiplayerSave)
LoadGame(PlayerData.GetWarpedToTheEye());
// wait until scene load and then wait until Start has ran
+ // why is this done? GameStateMessage etc works on title screen since nonhost has to deal with that
Delay.RunWhen(() => TimeLoop._initialized, QSBNetworkManager.singleton.StartHost);
};
@@ -657,6 +659,7 @@ private void Host(bool newMultiplayerSave)
{
LoadGame(PlayerData.GetWarpedToTheEye());
// wait until scene load and then wait until Start has ran
+ // why is this done? GameStateMessage etc works on title screen since nonhost has to deal with that
Delay.RunWhen(() => TimeLoop._initialized, QSBNetworkManager.singleton.StartHost);
}
}
diff --git a/QSB/MeteorSync/MeteorManager.cs b/QSB/MeteorSync/MeteorManager.cs
index b93704aba..29c841f86 100644
--- a/QSB/MeteorSync/MeteorManager.cs
+++ b/QSB/MeteorSync/MeteorManager.cs
@@ -1,6 +1,7 @@
using Cysharp.Threading.Tasks;
using QSB.MeteorSync.WorldObjects;
using QSB.WorldSync;
+using System.Linq;
using System.Threading;
namespace QSB.MeteorSync;
@@ -16,7 +17,9 @@ public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken
// wait for all late initializers (which includes meteor launchers) to finish
await UniTask.WaitUntil(() => LateInitializerManager.isDoneInitializing, cancellationToken: ct);
- WhiteHoleVolume = QSBWorldSync.GetUnityObject();
+ // NH can make multiple so ensure its the stock whitehole
+ var whiteHole = QSBWorldSync.GetUnityObjects().First(x => x.GetAstroObjectName() == AstroObject.Name.WhiteHole);
+ WhiteHoleVolume = whiteHole?.GetComponentInChildren();
QSBWorldSync.Init();
QSBWorldSync.Init();
QSBWorldSync.Init();
diff --git a/QSB/OrbSync/WorldObjects/QSBOrb.cs b/QSB/OrbSync/WorldObjects/QSBOrb.cs
index 17cb102d4..ae8e5d49d 100644
--- a/QSB/OrbSync/WorldObjects/QSBOrb.cs
+++ b/QSB/OrbSync/WorldObjects/QSBOrb.cs
@@ -1,4 +1,5 @@
-using QSB.Messaging;
+using OWML.Utils;
+using QSB.Messaging;
using QSB.OrbSync.Messages;
using QSB.OrbSync.TransformSync;
using QSB.Utility;
diff --git a/QSB/Patches/QSBPatchManager.cs b/QSB/Patches/QSBPatchManager.cs
index 6a994427c..721475cc6 100644
--- a/QSB/Patches/QSBPatchManager.cs
+++ b/QSB/Patches/QSBPatchManager.cs
@@ -1,5 +1,6 @@
using HarmonyLib;
using OWML.Common;
+using OWML.Utils;
using QSB.Utility;
using System;
using System.Collections.Generic;
diff --git a/QSB/Player/Messages/PlayerJoinMessage.cs b/QSB/Player/Messages/PlayerJoinMessage.cs
index fd6e99569..409e3ae3e 100644
--- a/QSB/Player/Messages/PlayerJoinMessage.cs
+++ b/QSB/Player/Messages/PlayerJoinMessage.cs
@@ -16,8 +16,6 @@ public class PlayerJoinMessage : QSBMessage
private string QSBVersion;
private string GameVersion;
private bool DlcInstalled;
- // empty if no incompatible mods
- private string FirstIncompatibleMod;
private int[] AddonHashes;
@@ -28,18 +26,6 @@ public PlayerJoinMessage(string name)
GameVersion = QSBCore.GameVersion;
DlcInstalled = QSBCore.DLCInstalled;
- var allEnabledMods = QSBCore.Helper.Interaction.GetMods();
-
- FirstIncompatibleMod = "";
-
- foreach (var mod in allEnabledMods)
- {
- if (QSBCore.IncompatibleMods.Contains(mod.ModHelper.Manifest.UniqueName))
- {
- FirstIncompatibleMod = mod.ModHelper.Manifest.UniqueName;
- }
- }
-
AddonHashes = QSBCore.Addons.Keys
.Except(QSBCore.CosmeticAddons)
.Select(x => x.GetStableHashCode())
@@ -53,7 +39,6 @@ public override void Serialize(NetworkWriter writer)
writer.Write(QSBVersion);
writer.Write(GameVersion);
writer.Write(DlcInstalled);
- writer.Write(FirstIncompatibleMod);
writer.Write(AddonHashes);
}
@@ -65,7 +50,6 @@ public override void Deserialize(NetworkReader reader)
QSBVersion = reader.ReadString();
GameVersion = reader.ReadString();
DlcInstalled = reader.Read();
- FirstIncompatibleMod = reader.ReadString();
AddonHashes = reader.Read();
}
@@ -119,12 +103,6 @@ public override void OnReceiveRemote()
new PlayerKickMessage(From, string.Format(QSBLocalization.Current.AddonMismatch, AddonHashes.Length, addonHashes.Length)).Send();
return;
}
-
- if (FirstIncompatibleMod != "" && !QSBCore.IncompatibleModsAllowed)
- {
- DebugLog.ToConsole($"Error - Client {PlayerName} connecting with incompatible mod. (First mod found was {FirstIncompatibleMod})");
- new PlayerKickMessage(From, string.Format(QSBLocalization.Current.IncompatibleMod, FirstIncompatibleMod)).Send();
- }
}
var player = QSBPlayerManager.GetPlayer(From);
diff --git a/QSB/Player/TransformSync/PlayerTransformSync.cs b/QSB/Player/TransformSync/PlayerTransformSync.cs
index 813ea05e1..27f79e290 100644
--- a/QSB/Player/TransformSync/PlayerTransformSync.cs
+++ b/QSB/Player/TransformSync/PlayerTransformSync.cs
@@ -1,4 +1,5 @@
using OWML.Common;
+using OWML.Utils;
using QSB.Messaging;
using QSB.Patches;
using QSB.Player.Messages;
diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj
index af2e6277d..5be7bf64f 100644
--- a/QSB/QSB.csproj
+++ b/QSB/QSB.csproj
@@ -75,7 +75,7 @@
-
+
diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs
index e033123f8..342da975d 100644
--- a/QSB/QSBCore.cs
+++ b/QSB/QSBCore.cs
@@ -66,7 +66,6 @@ public class QSBCore : ModBehaviour
Application.version.Split('.').Take(3).Join(delimiter: ".");
public static bool DLCInstalled => EntitlementsManager.IsDlcOwned() == EntitlementsManager.AsyncOwnershipStatus.Owned;
public static bool UseKcpTransport { get; private set; }
- public static bool IncompatibleModsAllowed { get; private set; }
public static bool ShowPlayerNames { get; private set; }
public static bool ShipDamage { get; private set; }
public static bool ShowExtraHUDElements { get; private set; }
@@ -84,17 +83,7 @@ public class QSBCore : ModBehaviour
private static string randomSkinType;
private static string randomJetpackType;
-
- public static readonly string[] IncompatibleMods =
- {
- // incompatible mods
- "Raicuparta.NomaiVR",
- "xen.NewHorizons",
- "Vesper.AutoResume",
- "Vesper.OuterWildsMMO",
- "_nebula.StopTime",
- "PacificEngine.OW_Randomizer",
- };
+ public static Assembly QSBNHAssembly = null;
public static event Action OnSkinsBundleLoaded;
@@ -227,7 +216,7 @@ public void Start()
Helper = ModHelper;
DebugLog.ToConsole($"* Start of QSB version {QSBVersion} - authored by {Helper.Manifest.Author}", MessageType.Info);
- CheckCompatibilityMods();
+ CheckNewHorizons();
DebugSettings = Helper.Storage.Load("debugsettings.json") ?? new DebugSettings();
@@ -415,7 +404,6 @@ public override void Configure(IModConfig config)
QSBNetworkManager.UpdateTransport();
DefaultServerIP = config.GetSettingsValue("defaultServerIP");
- IncompatibleModsAllowed = config.GetSettingsValue("incompatibleModsAllowed");
ShowPlayerNames = config.GetSettingsValue("showPlayerNames");
ShipDamage = config.GetSettingsValue("shipDamage");
ShowExtraHUDElements = config.GetSettingsValue("showExtraHud");
@@ -463,23 +451,13 @@ private void Update()
}
}
- private void CheckCompatibilityMods()
+ private void CheckNewHorizons()
{
- 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)
+ if (ModHelper.Interaction.ModExists("xen.NewHorizons"))
{
- 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);
+ // NH compat has to be in a different DLL since it uses IAddComponentOnStart, and depends on the NH DLL.
+ QSBNHAssembly = Assembly.LoadFrom(Path.Combine(ModHelper.Manifest.ModFolderPath, "QSB-NH.dll"));
+ gameObject.AddComponent(QSBNHAssembly.GetType("QSBNH.QSBNH", true));
}
}
}
diff --git a/QSB/QSBSceneManager.cs b/QSB/QSBSceneManager.cs
index 7f0f1be7d..cc29a0f89 100644
--- a/QSB/QSBSceneManager.cs
+++ b/QSB/QSBSceneManager.cs
@@ -1,4 +1,5 @@
using OWML.Common;
+using OWML.Utils;
using QSB.Utility;
using System;
diff --git a/QSB/QuantumSync/Patches/Common/Visibility/VisibilityShapePatches.cs b/QSB/QuantumSync/Patches/Common/Visibility/VisibilityShapePatches.cs
index 8937eb328..c101785a1 100644
--- a/QSB/QuantumSync/Patches/Common/Visibility/VisibilityShapePatches.cs
+++ b/QSB/QuantumSync/Patches/Common/Visibility/VisibilityShapePatches.cs
@@ -1,4 +1,5 @@
using HarmonyLib;
+using OWML.Utils;
using QSB.Patches;
using QSB.Utility;
diff --git a/QSB/ShipSync/Patches/ShipPatches.cs b/QSB/ShipSync/Patches/ShipPatches.cs
index 8eca58c21..aaef8f6eb 100644
--- a/QSB/ShipSync/Patches/ShipPatches.cs
+++ b/QSB/ShipSync/Patches/ShipPatches.cs
@@ -1,4 +1,5 @@
using HarmonyLib;
+using OWML.Utils;
using QSB.Messaging;
using QSB.Patches;
using QSB.ShipSync.Messages;
diff --git a/QSB/ShipSync/WorldObjects/QSBShipComponent.cs b/QSB/ShipSync/WorldObjects/QSBShipComponent.cs
index 27762abfe..5ad2881dc 100644
--- a/QSB/ShipSync/WorldObjects/QSBShipComponent.cs
+++ b/QSB/ShipSync/WorldObjects/QSBShipComponent.cs
@@ -1,4 +1,5 @@
-using QSB.Messaging;
+using OWML.Utils;
+using QSB.Messaging;
using QSB.ShipSync.Messages.Component;
using QSB.Utility;
using QSB.WorldSync;
diff --git a/QSB/ShipSync/WorldObjects/QSBShipHull.cs b/QSB/ShipSync/WorldObjects/QSBShipHull.cs
index 4e2ace73c..165cbbb30 100644
--- a/QSB/ShipSync/WorldObjects/QSBShipHull.cs
+++ b/QSB/ShipSync/WorldObjects/QSBShipHull.cs
@@ -1,4 +1,5 @@
-using QSB.Messaging;
+using OWML.Utils;
+using QSB.Messaging;
using QSB.ShipSync.Messages.Hull;
using QSB.Utility;
using QSB.WorldSync;
diff --git a/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs b/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs
index 7b0f487a9..f528e2dd1 100644
--- a/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs
+++ b/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs
@@ -1,4 +1,5 @@
using HarmonyLib;
+using OWML.Utils;
using QSB.Messaging;
using QSB.Patches;
using QSB.Tools.ProbeTool.Messages;
diff --git a/QSB/Translations/de.json b/QSB/Translations/de.json
index 9a440ea48..6bd90036e 100644
--- a/QSB/Translations/de.json
+++ b/QSB/Translations/de.json
@@ -28,7 +28,6 @@
"DLCMismatch": "DLC Installationsstatus stimmt nicht überein. (Client:{0}, Server:{1})",
"GameProgressLimit": "Spiel ist zu weit fortgeschritten.",
"AddonMismatch": "Addons stimmen nicht überein. (Client:{0} addons, Server:{1} addons)",
- "IncompatibleMod": "Es wird eine inkompatible/unerlaubte Modifikation genutzt. Die erste gefundene Modifikation war {0}",
"PlayerJoinedTheGame": "{0} trat bei!",
"PlayerLeftTheGame": "{0} verließ!",
"PlayerWasKicked": "{0} wurde gekickt.",
diff --git a/QSB/Translations/en.json b/QSB/Translations/en.json
index d6b909c4e..13e1277d9 100644
--- a/QSB/Translations/en.json
+++ b/QSB/Translations/en.json
@@ -28,7 +28,6 @@
"DLCMismatch": "DLC installation state does not match. (Client:{0}, Server:{1})",
"GameProgressLimit": "Game has progressed too far.",
"AddonMismatch": "Addon mismatch. (Client:{0} addons, Server:{1} addons)",
- "IncompatibleMod": "Using an incompatible/disallowed mod. First mod found was {0}",
"PlayerJoinedTheGame": "{0} joined!",
"PlayerLeftTheGame": "{0} left!",
"PlayerWasKicked": "{0} was kicked.",
diff --git a/QSB/Translations/fr.json b/QSB/Translations/fr.json
index 263db10c7..37d79af47 100644
--- a/QSB/Translations/fr.json
+++ b/QSB/Translations/fr.json
@@ -28,7 +28,6 @@
"DLCMismatch": "Les états d'installation du DLC ne correspondent pas. (Client:{0}, Serveur:{1})",
"GameProgressLimit": "Le jeu a trop progressé.",
"AddonMismatch": "Non-concordance des addons. (Client:{0} addons, Serveur:{1} addons)",
- "IncompatibleMod": "Tu utilises un mod incompatible/non autorisé. Le premier mod trouvé était {0}",
"PlayerJoinedTheGame": "{0} a rejoint!",
"PlayerLeftTheGame": "{0} est parti!",
"PlayerWasKicked": "{0} a été expulsé.",
diff --git a/QSB/Translations/pt-br.json b/QSB/Translations/pt-br.json
index 39851562f..88c5223c8 100644
--- a/QSB/Translations/pt-br.json
+++ b/QSB/Translations/pt-br.json
@@ -28,7 +28,6 @@
"DLCMismatch": "O estado da instalação da DLC não correspondem. (Cliente:{0}, Servidor:{1})",
"GameProgressLimit": "O jogo progrediu além do limite.",
"AddonMismatch": "Incompatibilidade de Addons. (Cliente:{0} addons, Servidor:{1} addons)",
- "IncompatibleMod": "Usando um mod incompativel ou não permitido. Primeiro mod encontrado foi {0}",
"PlayerJoinedTheGame": "{0} entrou!",
"PlayerLeftTheGame": "{0} saiu!",
"PlayerWasKicked": "{0} foi expulso.",
diff --git a/QSB/Translations/ru.json b/QSB/Translations/ru.json
index 4cea3b7df..f11ee8532 100644
--- a/QSB/Translations/ru.json
+++ b/QSB/Translations/ru.json
@@ -28,7 +28,6 @@
"DLCMismatch": "Состояние присутствия DLC отличается. (Клиент:{0}, Сервер:{1})",
"GameProgressLimit": "Игра продолжалась слишком долго.",
"AddonMismatch": "Аддоны различаются. (Клиент:{0} аддонов, Сервер:{1} аддонов)",
- "IncompatibleMod": "Используется несовместимый(ые)/неразрешенный(ые) мод(ы). Первый из них - {0}",
"PlayerJoinedTheGame": "{0} подключился!",
"PlayerWasKicked": "{0} был отключён.",
"KickedFromServer": "Отключён от сервера. Причина : {0}",
diff --git a/QSB/Translations/spanish.json b/QSB/Translations/spanish.json
index 3ad4ae52b..ea8626f20 100644
--- a/QSB/Translations/spanish.json
+++ b/QSB/Translations/spanish.json
@@ -28,7 +28,6 @@
"DLCMismatch": "El estado de instalación del DLC no coincide. (Cliente:{0}, Servidor:{1})",
"GameProgressLimit": "El juego ha progresado mas del límite permitido.",
"AddonMismatch": "Incompatibilidad de Addons. (Cliente:{0} addons, Servidor:{1} addons)",
- "IncompatibleMod": "Se está usando un mod incompatible/no permitido. El primer mod encontrado ha sido {0}",
"PlayerJoinedTheGame": "¡{0} se ha unido!",
"PlayerWasKicked": "{0} ha sido expulsado.",
"KickedFromServer": "Expulsado del servidor. Razón : {0}",
diff --git a/QSB/Translations/tr.json b/QSB/Translations/tr.json
index 4465a68ac..2038eed5f 100644
--- a/QSB/Translations/tr.json
+++ b/QSB/Translations/tr.json
@@ -28,7 +28,6 @@
"DLCMismatch": "DLC yüklenme durumu uyumlu değil. (İstemci:{0}, Sunucu:{1})",
"GameProgressLimit": "Oyun çok fazla ilerlemiş.",
"AddonMismatch": "Yüklü eklentiler uyumsuz. (İstemci:{0} eklentileri, Sunucu:{1} eklentileri)",
- "IncompatibleMod": "İzin verilmeyen veya uyumsuz mod kullanılıyor. İlk bulunan mod {0}",
"PlayerJoinedTheGame": "{0} katıldı!",
"PlayerLeftTheGame": "{0} ayrıldı.",
"PlayerWasKicked": "{0} atıldı.",
diff --git a/QSB/Translations/zh_CN.json b/QSB/Translations/zh_CN.json
index 069fe802f..23f69d2e1 100644
--- a/QSB/Translations/zh_CN.json
+++ b/QSB/Translations/zh_CN.json
@@ -28,7 +28,6 @@
"DLCMismatch": "DLC安装情况不匹配。(客户端:{0},服务端:{1})",
"GameProgressLimit": "游戏中时间太久了。",
"AddonMismatch": "插件不匹配(客户端:{0}插件,服务端:{1}插件)",
- "IncompatibleMod": "使用了不兼容/不允许的模组,检测到的第一个模组是{0}",
"PlayerJoinedTheGame": "{0}加入了游戏!",
"PlayerWasKicked": "{0}被踢出了游戏。",
"KickedFromServer": "被踢出了游戏,理由是:{0}",
diff --git a/QSB/Utility/DebugActions.cs b/QSB/Utility/DebugActions.cs
index e56ecda71..1cf23019a 100644
--- a/QSB/Utility/DebugActions.cs
+++ b/QSB/Utility/DebugActions.cs
@@ -1,4 +1,5 @@
using OWML.Common;
+using OWML.Utils;
using QSB.EchoesOfTheEye.DreamLantern;
using QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
using QSB.ItemSync.WorldObjects.Items;
diff --git a/QSB/Utility/DebugGUI.cs b/QSB/Utility/DebugGUI.cs
index 4d2bd3a3a..4fc4b60c0 100644
--- a/QSB/Utility/DebugGUI.cs
+++ b/QSB/Utility/DebugGUI.cs
@@ -205,6 +205,8 @@ private static void DrawGui()
WriteLine(2, $" - Ref. Sector : {(referenceSector == null ? "NULL" : referenceSector.Name)}", referenceSector == null ? Color.red : Color.white);
WriteLine(2, $" - Ref. Transform : {(referenceTransform == null ? "NULL" : referenceTransform.name)}", referenceTransform == null ? Color.red : Color.white);
+ WriteLine(2, $" - Local Position : {player.Body.transform.localPosition}");
+ WriteLine(2, $" - Position : {player.Body.transform.position}");
}
}
diff --git a/QSB/Utility/Deterministic/DeterministicRigidbodyPatches.cs b/QSB/Utility/Deterministic/DeterministicRigidbodyPatches.cs
index d342e0300..6742a4415 100644
--- a/QSB/Utility/Deterministic/DeterministicRigidbodyPatches.cs
+++ b/QSB/Utility/Deterministic/DeterministicRigidbodyPatches.cs
@@ -1,4 +1,5 @@
using HarmonyLib;
+using OWML.Utils;
using QSB.Patches;
using System.Collections.Generic;
using UnityEngine;
diff --git a/QSB/Utility/Extensions.cs b/QSB/Utility/Extensions.cs
index 188abab73..c7f415dc5 100644
--- a/QSB/Utility/Extensions.cs
+++ b/QSB/Utility/Extensions.cs
@@ -71,21 +71,6 @@ public static void SpawnWithServerOwnership(this GameObject go) =>
#region C#
- public static void SafeInvoke(this MulticastDelegate multicast, params object[] args)
- {
- foreach (var del in multicast.GetInvocationList())
- {
- try
- {
- del.DynamicInvoke(args);
- }
- catch (TargetInvocationException ex)
- {
- DebugLog.ToConsole($"Error invoking delegate! {ex.InnerException}", MessageType.Error);
- }
- }
- }
-
public static float Map(this float value, float inputFrom, float inputTo, float outputFrom, float outputTo, bool clamp)
{
var mappedValue = (value - inputFrom) / (inputTo - inputFrom) * (outputTo - outputFrom) + outputFrom;
@@ -165,30 +150,21 @@ public static TSource MaxBy(this IEnumerable source, Fun
public static bool IsInRange(this IList list, int index) => index >= 0 && index < list.Count;
- public static void RaiseEvent(this T instance, string eventName, params object[] args)
+ public static IEnumerable GetDerivedTypes(this Type type)
{
- const BindingFlags flags = BindingFlags.Instance
- | BindingFlags.Static
- | BindingFlags.Public
- | BindingFlags.NonPublic
- | BindingFlags.DeclaredOnly;
- if (typeof(T)
- .GetField(eventName, flags)?
- .GetValue(instance) is not MulticastDelegate multiDelegate)
+ var assemblies = QSBCore.Addons.Values
+ .Select(x => x.GetType().Assembly)
+ .Append(type.Assembly);
+
+ if (QSBCore.QSBNHAssembly != null)
{
- return;
+ assemblies = assemblies.Append(QSBCore.QSBNHAssembly);
}
- multiDelegate.SafeInvoke(args);
- }
-
- public static IEnumerable GetDerivedTypes(this Type type) =>
- QSBCore.Addons.Values
- .Select(x => x.GetType().Assembly)
- .Append(type.Assembly)
- .SelectMany(x => x.GetTypes())
+ return assemblies.SelectMany(x => x.GetTypes())
.Where(x => !x.IsInterface && !x.IsAbstract && type.IsAssignableFrom(x))
.OrderBy(x => x.FullName);
+ }
public static Guid ToGuid(this int value)
{
diff --git a/QSB/WorldSync/Messages/RequestInitialStatesMessage.cs b/QSB/WorldSync/Messages/RequestInitialStatesMessage.cs
index 6a311f8de..a9e65242e 100644
--- a/QSB/WorldSync/Messages/RequestInitialStatesMessage.cs
+++ b/QSB/WorldSync/Messages/RequestInitialStatesMessage.cs
@@ -1,4 +1,5 @@
-using QSB.Messaging;
+using OWML.Utils;
+using QSB.Messaging;
using QSB.Utility;
using System;
diff --git a/QSB/ZeroGCaveSync/Patches/ZeroGCavePatches.cs b/QSB/ZeroGCaveSync/Patches/ZeroGCavePatches.cs
index ccc8043ae..6054dc632 100644
--- a/QSB/ZeroGCaveSync/Patches/ZeroGCavePatches.cs
+++ b/QSB/ZeroGCaveSync/Patches/ZeroGCavePatches.cs
@@ -1,4 +1,5 @@
using HarmonyLib;
+using OWML.Utils;
using QSB.Messaging;
using QSB.Patches;
using QSB.Utility;
diff --git a/QSB/ZeroGCaveSync/WorldObjects/QSBSatelliteNode.cs b/QSB/ZeroGCaveSync/WorldObjects/QSBSatelliteNode.cs
index 1f3133a72..fff749716 100644
--- a/QSB/ZeroGCaveSync/WorldObjects/QSBSatelliteNode.cs
+++ b/QSB/ZeroGCaveSync/WorldObjects/QSBSatelliteNode.cs
@@ -1,4 +1,5 @@
-using QSB.Messaging;
+using OWML.Utils;
+using QSB.Messaging;
using QSB.Utility;
using QSB.WorldSync;
using QSB.ZeroGCaveSync.Messages;
diff --git a/QSB/default-config.json b/QSB/default-config.json
index 023245c85..306a1221d 100644
--- a/QSB/default-config.json
+++ b/QSB/default-config.json
@@ -28,12 +28,6 @@
"value": "localhost",
"tooltip": "Used if you leave the connect prompt blank."
},
- "incompatibleModsAllowed": {
- "title": "Incompatible Mods Allowed",
- "type": "toggle",
- "value": false,
- "tooltip": "Kicks players if they have certain mods."
- },
"showPlayerNames": {
"title": "Show Player Names",
"type": "toggle",
diff --git a/QSB/manifest.json b/QSB/manifest.json
index 4f0b51e0e..4b922e4ac 100644
--- a/QSB/manifest.json
+++ b/QSB/manifest.json
@@ -3,15 +3,17 @@
"filename": "QSB.dll",
"author": "Nebula, John, Alek, & Rai",
"name": "Quantum Space Buddies",
- "warning": {
- "title": "Follow these steps before playing multiplayer :",
- "body": "- Disable *all* other mods. (Can heavily affect performance)\n- Make sure you are not running any other network-intensive applications."
- },
"uniqueName": "Raicuparta.QuantumSpaceBuddies",
- "version": "1.0.1",
- "owmlVersion": "2.9.8",
+ "version": "1.1.0",
+ "owmlVersion": "2.11.1",
"dependencies": [ "_nebula.MenuFramework", "JohnCorby.VanillaFix" ],
"pathsToPreserve": [ "debugsettings.json" ],
+ "conflicts": [
+ "Vesper.AutoResume",
+ "Vesper.OuterWildsMMO",
+ "_nebula.StopTime",
+ "PacificEngine.OW_CommonResources"
+ ],
"requireLatestVersion": true,
"patcher": "QSBPatcher.exe",
"donateLinks": [ "https://www.paypal.me/nebula2056", "https://www.paypal.me/johncorby" ]
diff --git a/README.md b/README.md
index b3e834287..e1b2239a3 100644
--- a/README.md
+++ b/README.md
@@ -61,17 +61,27 @@ There still might be one or two small mechanics that aren't synced - let us know
Also, you might encounter bugs that mean you can't progress in multiplayer. Again, let us know if you find one!
### Compatibility with other mods
-TL;DR - Don't use any mods with QSB that aren't marked as QSB compatible.
-QSB relies on object hierarchy to sync objects, so any mod that changes that risks breaking QSB. Also, QSB relies on certain game events being called when things happen in-game. Any mod that makes these things happen without calling the correct events will break QSB. Some mods will work fine and have been tested, like CrouchMod. Others may only work partly, like EnableDebugMode and TAICheat.
+QSB relies on object hierarchy to sync objects, so any mod that changes that risks breaking QSB.
+QSB also relies on certain game events being called when things happen in-game, so any mod that makes these things happen without calling the correct events will break QSB.
-### Is this mod compatible with NomaiVR?
+Most small mods will work fine. The more complex and far reaching the mod, the less likely it will work completely.
+Try as many mods as you like, but don't be surprised if things break.
-Short answer - Kind of.
+#### NomaiVr
-Long answer - We've done our best to try to keep them compatible, but no work has been done to explicitly make them play nice. Some things may work, others may not.
-Getting both mods to work together is a big undertaking, and would require rewrites to a lot of code in both mods.
-If you want to play with VR, make sure the server host has "Incompatible Mods Allowed" enabled.
+[Here](https://github.com/qsb-dev/quantum-space-buddies/issues?q=is%3Aissue+is%3Aopen+label%3ANomaiVR) are the known issues. You are welcome to add to this list by creating issues.
+
+Most things seem to work _enough_. There are some visual bugs, and I believe a few softlocks, but the experience shouldn't be too bad.
+
+We haven't done too much work to make them compatible, so the things that are broken are unlikely to be fixed.
+
+#### New Horizons
+
+[Here](https://github.com/qsb-dev/quantum-space-buddies/issues?q=is%3Aissue+is%3Aopen+label%3A%22New+Horizons%22) are the known issues. You are welcome to add to this list by creating issues.
+
+We do our best to stay mostly compatible with base New Horizons, but the compatibility of each addon is mixed.
+Most of them at least partially work. Most custom mechanics will not work until the addon developer explicitly adds QSB support.
### Why do I keep getting thrown around the ship?
diff --git a/SteamRerouter/SteamRerouter.csproj b/SteamRerouter/SteamRerouter.csproj
index 306c29ec7..f447e88cc 100644
--- a/SteamRerouter/SteamRerouter.csproj
+++ b/SteamRerouter/SteamRerouter.csproj
@@ -17,7 +17,7 @@
-
-
+
+