Skip to content

Commit

Permalink
Merge pull request #668 from qsb-dev/nh-compat
Browse files Browse the repository at this point in the history
NH compatibility
  • Loading branch information
misternebula authored Apr 24, 2024
2 parents 5cfaf77 + c9a657d commit 401f3de
Show file tree
Hide file tree
Showing 13 changed files with 372 additions and 24 deletions.
58 changes: 58 additions & 0 deletions QSB-NH/Patches/GameStateMessagePatches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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;


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<string>();
_hostAddonHash = reader.ReadArray<int>();
}

[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);
}
}
}
32 changes: 32 additions & 0 deletions QSB-NH/QSB-NH.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<RootNamespace>QSBNH</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputPath Condition="Exists('$(OwmlDir)')">$(OwmlDir)\Mods\Raicuparta.QuantumSpaceBuddies</OutputPath>
</PropertyGroup>

<ItemGroup>
<Folder Include="lib\" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\QSB\QSB.csproj" />
</ItemGroup>

<ItemGroup>
<Reference Include="Mirror">
<HintPath>..\Lib\Mirror.dll</HintPath>
</Reference>
<Reference Include="NewHorizons">
<HintPath>lib\NewHorizons.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UniTask">
<HintPath>..\Lib\UniTask.dll</HintPath>
</Reference>
</ItemGroup>

</Project>
59 changes: 59 additions & 0 deletions QSB-NH/QSBNH.cs
Original file line number Diff line number Diff line change
@@ -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<INewHorizons>("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;
}
}
}
}
13 changes: 13 additions & 0 deletions QSB-NH/QuantumPlanet/QuantumPlanetManager.cs
Original file line number Diff line number Diff line change
@@ -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<QSBQuantumPlanet, NewHorizons.Components.Quantum.QuantumPlanet>();
}
7 changes: 7 additions & 0 deletions QSB-NH/QuantumPlanet/WorldObjects/QSBQuantumPlanet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using QSB.QuantumSync.WorldObjects;

namespace QSBNH.QuantumPlanet.WorldObjects;

public class QSBQuantumPlanet : QSBQuantumObject<NewHorizons.Components.Quantum.QuantumPlanet>
{
}
168 changes: 168 additions & 0 deletions QSB-NH/WarpManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
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<string>();
_shipWarp = reader.Read<bool>();
_vesselWarp = reader.Read<bool>();
}

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));
}
}
}

[HarmonyPatch]
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);
}
}
}
}
Binary file added QSB-NH/lib/NewHorizons.dll
Binary file not shown.
6 changes: 6 additions & 0 deletions QSB.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions QSB/ConversationSync/ConversationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using QSB.Utility.Deterministic;
using UnityEngine;
using UnityEngine.UI;

Expand Down Expand Up @@ -41,8 +42,9 @@ public void Start()

public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
{
QSBWorldSync.Init<QSBRemoteDialogueTrigger, RemoteDialogueTrigger>();
QSBWorldSync.Init<QSBCharacterDialogueTree, CharacterDialogueTree>();
// dont create worldobjects
QSBWorldSync.Init<QSBRemoteDialogueTrigger, RemoteDialogueTrigger>(QSBWorldSync.GetUnityObjects<RemoteDialogueTrigger>().Where(x => x.name != "WarpDriveRemoteTrigger").SortDeterministic());
QSBWorldSync.Init<QSBCharacterDialogueTree, CharacterDialogueTree>(QSBWorldSync.GetUnityObjects<CharacterDialogueTree>().Where(x => x.name != "WarpDriveDialogue").SortDeterministic());
}

public uint GetPlayerTalkingToTree(CharacterDialogueTree tree) =>
Expand Down
Loading

0 comments on commit 401f3de

Please sign in to comment.