diff --git a/QNetWeaver/QNetWeaver.csproj b/QNetWeaver/QNetWeaver.csproj index be1b5de5..b60b466a 100644 --- a/QNetWeaver/QNetWeaver.csproj +++ b/QNetWeaver/QNetWeaver.csproj @@ -52,8 +52,9 @@ ..\..\..\..\..\..\Program Files\Unity\Hub\Editor\2017.4.33f1\Editor\Data\Managed\Unity.Cecil.Pdb.dll - - ..\..\..\..\..\..\Program Files\Unity\Hub\Editor\2017.4.33f1\Editor\Data\Managed\Unity.UNetWeaver.dll + + False + lib\Unity.UNetWeaver.dll @@ -68,5 +69,8 @@ + + + \ No newline at end of file diff --git a/QNetWeaver/lib/Unity.UNetWeaver.dll b/QNetWeaver/lib/Unity.UNetWeaver.dll new file mode 100644 index 00000000..84c5baec Binary files /dev/null and b/QNetWeaver/lib/Unity.UNetWeaver.dll differ diff --git a/QSB/Events/EventNames.cs b/QSB/Events/EventNames.cs index 81a70cc2..39a06366 100644 --- a/QSB/Events/EventNames.cs +++ b/QSB/Events/EventNames.cs @@ -89,5 +89,8 @@ public static string QSBDebugEvent = "QSBDebugEvent"; public static string QSBEnterNomaiHeadZone = "QSBEnterNomaiHeadZone"; public static string QSBExitNomaiHeadZone = "QSBExitNomaiHeadZone"; + public static string QSBEnterSatelliteCamera = "QSBEnterSatelliteCamera"; + public static string QSBExitSatelliteCamera = "QSBExitSatelliteCamera"; + public static string QSBSatelliteSnapshot = "QSBSatelliteSnapshot"; } } \ No newline at end of file diff --git a/QSB/Events/EventType.cs b/QSB/Events/EventType.cs index be7a01f7..4553f923 100644 --- a/QSB/Events/EventType.cs +++ b/QSB/Events/EventType.cs @@ -6,6 +6,8 @@ * MISC. */ DebugEvent, + SatelliteProjector, + SatelliteProjectorSnapshot, /* * SERVER EVENTS diff --git a/QSB/Events/QSBEventManager.cs b/QSB/Events/QSBEventManager.cs index 68029535..d6780875 100644 --- a/QSB/Events/QSBEventManager.cs +++ b/QSB/Events/QSBEventManager.cs @@ -15,6 +15,7 @@ using QSB.Player.Events; using QSB.ProbeSync.Events; using QSB.QuantumSync.Events; using QSB.RoastingSync.Events; +using QSB.SatelliteSync.Events; using QSB.ShipSync.Events; using QSB.ShipSync.Events.Component; using QSB.ShipSync.Events.Hull; @@ -69,6 +70,8 @@ namespace QSB.Events new ServerStateEvent(), new ClientStateEvent(), new DebugEvent(), + new SatelliteProjectorEvent(), + new SatelliteProjectorSnapshotEvent(), // World Objects new ElevatorEvent(), new GeyserEvent(), diff --git a/QSB/Patches/QSBPatchManager.cs b/QSB/Patches/QSBPatchManager.cs index bf71ee58..d9f082c4 100644 --- a/QSB/Patches/QSBPatchManager.cs +++ b/QSB/Patches/QSBPatchManager.cs @@ -16,6 +16,7 @@ using QSB.Player.Patches; using QSB.PoolSync.Patches; using QSB.QuantumSync.Patches; using QSB.RoastingSync.Patches; +using QSB.SatelliteSync.Patches; using QSB.ShipSync.Patches; using QSB.StatueSync.Patches; using QSB.TimeSync.Patches; @@ -67,7 +68,8 @@ namespace QSB.Patches new MapPatches(), new RespawnPatches(), new LauncherPatches(), - new SolanumPatches() + new SolanumPatches(), + new SatelliteProjectorPatches() }; TypeToInstance = new Dictionary diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj index 79e1b2b9..f65b9fd1 100644 --- a/QSB/QSB.csproj +++ b/QSB/QSB.csproj @@ -200,6 +200,10 @@ + + + + diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs index ef1c7bc0..c72b4687 100644 --- a/QSB/QSBCore.cs +++ b/QSB/QSBCore.cs @@ -16,6 +16,7 @@ using QSB.Player; using QSB.Player.TransformSync; using QSB.PoolSync; using QSB.QuantumSync; +using QSB.SatelliteSync; using QSB.SectorSync; using QSB.ShipSync; using QSB.StatueSync; @@ -102,6 +103,7 @@ namespace QSB gameObject.AddComponent(); gameObject.AddComponent(); gameObject.AddComponent(); + gameObject.AddComponent(); // WorldObject managers gameObject.AddComponent(); diff --git a/QSB/SatelliteSync/Events/SatelliteProjectorEvent.cs b/QSB/SatelliteSync/Events/SatelliteProjectorEvent.cs new file mode 100644 index 00000000..b2d8356e --- /dev/null +++ b/QSB/SatelliteSync/Events/SatelliteProjectorEvent.cs @@ -0,0 +1,42 @@ +using QSB.Events; +using QSB.Messaging; + +namespace QSB.SatelliteSync.Events +{ + class SatelliteProjectorEvent : QSBEvent + { + public override EventType Type => EventType.SatelliteProjector; + + public override void SetupListener() + { + GlobalMessenger.AddListener(EventNames.QSBEnterSatelliteCamera, () => Handler(true)); + GlobalMessenger.AddListener(EventNames.QSBExitSatelliteCamera, () => Handler(false)); + } + + public override void CloseListener() + { + GlobalMessenger.RemoveListener(EventNames.QSBEnterSatelliteCamera, () => Handler(true)); + GlobalMessenger.RemoveListener(EventNames.QSBExitSatelliteCamera, () => Handler(false)); + } + + private void Handler(bool usingProjector) => SendEvent(CreateMessage(usingProjector)); + + private BoolMessage CreateMessage(bool usingProjector) => new BoolMessage + { + AboutId = LocalPlayerId, + Value = usingProjector + }; + + public override void OnReceiveRemote(bool isHost, BoolMessage message) + { + if (message.Value) + { + SatelliteProjectorManager.Instance.RemoteEnter(); + } + else + { + SatelliteProjectorManager.Instance.RemoteExit(); + } + } + } +} diff --git a/QSB/SatelliteSync/Events/SatelliteProjectorSnapshotEvent.cs b/QSB/SatelliteSync/Events/SatelliteProjectorSnapshotEvent.cs new file mode 100644 index 00000000..5dbba575 --- /dev/null +++ b/QSB/SatelliteSync/Events/SatelliteProjectorSnapshotEvent.cs @@ -0,0 +1,34 @@ +using QSB.Events; +using QSB.Messaging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace QSB.SatelliteSync.Events +{ + class SatelliteProjectorSnapshotEvent : QSBEvent + { + public override EventType Type => EventType.SatelliteProjectorSnapshot; + + public override void SetupListener() + { + GlobalMessenger.AddListener(EventNames.QSBSatelliteSnapshot, (bool forward) => Handler(forward)); + } + + public override void CloseListener() + { + GlobalMessenger.RemoveListener(EventNames.QSBSatelliteSnapshot, (bool forward) => Handler(forward)); + } + + private void Handler(bool forward) => SendEvent(CreateMessage(forward)); + + private BoolMessage CreateMessage(bool forward) => new BoolMessage + { + AboutId = LocalPlayerId, + Value = forward + }; + + public override void OnReceiveRemote(bool isHost, BoolMessage message) => SatelliteProjectorManager.Instance.RemoteTakeSnapshot(message.Value); + } +} diff --git a/QSB/SatelliteSync/Patches/SatelliteProjectorPatches.cs b/QSB/SatelliteSync/Patches/SatelliteProjectorPatches.cs new file mode 100644 index 00000000..5f8c9f14 --- /dev/null +++ b/QSB/SatelliteSync/Patches/SatelliteProjectorPatches.cs @@ -0,0 +1,62 @@ +using HarmonyLib; +using QSB.Events; +using QSB.Patches; +using UnityEngine; + +namespace QSB.SatelliteSync.Patches +{ + [HarmonyPatch] + class SatelliteProjectorPatches : QSBPatch + { + public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect; + + [HarmonyPrefix] + [HarmonyPatch(typeof(SatelliteSnapshotController), nameof(SatelliteSnapshotController.OnPressInteract))] + public static bool UseProjector() + { + QSBEventManager.FireEvent(EventNames.QSBEnterSatelliteCamera); + return true; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SatelliteSnapshotController), nameof(SatelliteSnapshotController.TurnOffProjector))] + public static bool LeaveProjector() + { + QSBEventManager.FireEvent(EventNames.QSBExitSatelliteCamera); + return true; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SatelliteSnapshotController), nameof(SatelliteSnapshotController.Update))] + public static bool UpdateReplacement(SatelliteSnapshotController __instance) + { + if (!OWInput.IsInputMode(InputMode.SatelliteCam)) + { + return false; + } + + if (OWInput.IsNewlyPressed(InputLibrary.toolActionPrimary, InputMode.All)) + { + QSBEventManager.FireEvent(EventNames.QSBSatelliteSnapshot, true); + __instance._satelliteCamera.transform.localEulerAngles = __instance._initCamLocalRot; + __instance.RenderSnapshot(); + return false; + } + + if (__instance._allowRearview && OWInput.IsNewlyPressed(InputLibrary.toolActionSecondary, InputMode.All)) + { + QSBEventManager.FireEvent(EventNames.QSBSatelliteSnapshot, false); + __instance._satelliteCamera.transform.localEulerAngles = __instance._initCamLocalRot + new Vector3(0f, 180f, 0f); + __instance.RenderSnapshot(); + return false; + } + + if (OWInput.IsNewlyPressed(InputLibrary.cancel, InputMode.All)) + { + __instance.TurnOffProjector(); + } + + return false; + } + } +} diff --git a/QSB/SatelliteSync/SatelliteProjectorManager.cs b/QSB/SatelliteSync/SatelliteProjectorManager.cs new file mode 100644 index 00000000..2d49cf05 --- /dev/null +++ b/QSB/SatelliteSync/SatelliteProjectorManager.cs @@ -0,0 +1,86 @@ +using QSB.Utility; +using System.Linq; +using UnityEngine; + +namespace QSB.SatelliteSync +{ + class SatelliteProjectorManager : MonoBehaviour + { + public static SatelliteProjectorManager Instance { get; private set; } + + public SatelliteSnapshotController Projector { get; private set; } + + public void Start() + { + Instance = this; + QSBSceneManager.OnUniverseSceneLoaded += OnSceneLoaded; + } + + public void OnDestroy() + { + QSBSceneManager.OnUniverseSceneLoaded -= OnSceneLoaded; + } + + private void OnSceneLoaded(OWScene oldScene, OWScene newScene) + { + if (newScene == OWScene.SolarSystem) + { + Projector = Resources.FindObjectsOfTypeAll().First(); + Projector._loopingSource.spatialBlend = 1f; + Projector._oneShotSource.spatialBlend = 1f; + } + } + + public void RemoteEnter() + { + Projector.enabled = true; + Projector._interactVolume.DisableInteraction(); + + if (Projector._showSplashTexture) + { + Projector._splashObject.SetActive(false); + Projector._diagramObject.SetActive(true); + Projector._projectionScreen.gameObject.SetActive(false); + } + + if (Projector._fadeLight != null) + { + Projector._fadeLight.StartFade(0f, 2f, 0f); + } + + var audioClip = Projector._oneShotSource.PlayOneShot(AudioType.TH_ProjectorActivate, 1f); + Projector._loopingSource.FadeIn(audioClip.length, false, false, 1f); + } + + public void RemoteExit() + { + Projector.enabled = false; + Projector._interactVolume.EnableInteraction(); + Projector._interactVolume.ResetInteraction(); + + if (Projector._showSplashTexture) + { + Projector._splashObject.SetActive(true); + Projector._diagramObject.SetActive(false); + Projector._projectionScreen.gameObject.SetActive(false); + } + + if (Projector._fadeLight != null) + { + Projector._fadeLight.StartFade(Projector._initLightIntensity, 2f, 0f); + } + + var audioClip = Projector._oneShotSource.PlayOneShot(AudioType.TH_ProjectorStop, 1f); + Projector._loopingSource.FadeOut(audioClip.length, OWAudioSource.FadeOutCompleteAction.STOP, 0f); + } + + public void RemoteTakeSnapshot(bool forward) + { + Projector._satelliteCamera.transform.localEulerAngles = forward + ? Projector._initCamLocalRot + : Projector._initCamLocalRot + new Vector3(0f, 180f, 0f); + + Projector.RenderSnapshot(); + } + } +} diff --git a/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs b/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs index c96b8506..ae9e0fcf 100644 --- a/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs +++ b/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs @@ -71,12 +71,20 @@ namespace QSB.Tools.ProbeLauncherTool.Patches // TODO : ehhhh idk about this. maybe copy each sound source so we have a 2d version (for local) and a 3d version (for remote)? // this would probably be a whole qsb version on it's own - [HarmonyPostfix] + [HarmonyPrefix] [HarmonyPatch(typeof(ProbeLauncherEffects), nameof(ProbeLauncherEffects.PlayRetrievalClip))] - public static void ProbeLauncherEffects_PlayRetrievalClip(OWAudioSource ____owAudioSource) => ____owAudioSource.GetAudioSource().spatialBlend = 1f; + public static bool ProbeLauncherEffects_PlayRetrievalClip(OWAudioSource ____owAudioSource) + { + ____owAudioSource.GetAudioSource().spatialBlend = 1f; + return true; + } - [HarmonyPostfix] + [HarmonyPrefix] [HarmonyPatch(typeof(ProbeLauncherEffects), nameof(ProbeLauncherEffects.PlayLaunchClip))] - public static void ProbeLauncherEffects_PlayLaunchClip(OWAudioSource ____owAudioSource) => ____owAudioSource.GetAudioSource().spatialBlend = 1f; + public static bool ProbeLauncherEffects_PlayLaunchClip(OWAudioSource ____owAudioSource) + { + ____owAudioSource.GetAudioSource().spatialBlend = 1f; + return true; + } } } diff --git a/QSB/default-config.json b/QSB/default-config.json index ffe88285..fedee1d0 100644 --- a/QSB/default-config.json +++ b/QSB/default-config.json @@ -3,7 +3,7 @@ "settings": { "defaultServerIP": "localhost", "port": 7777, - "debugMode": false, + "debugMode": true, "showLinesInDebug": false } } \ No newline at end of file diff --git a/QSBTests/PatchTests.cs b/QSBTests/PatchTests.cs index 26ece311..29d3ebdd 100644 --- a/QSBTests/PatchTests.cs +++ b/QSBTests/PatchTests.cs @@ -1,36 +1,41 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using QSB.Patches; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; namespace QSBTests { [TestClass] public class PatchTests { - //[TestMethod] - //public void CheckUnreferencedPatches() - //{ - // var qsbAssembly = Assembly.Load("QSB"); - // var allPatchTypes = qsbAssembly - // .GetTypes() - // .Where(x => typeof(QSBPatch).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); + [TestMethod] + public void CheckUnreferencedPatches() + { + var qsbAssembly = Assembly.Load("QSB"); + var allPatchTypes = qsbAssembly + .GetTypes() + .Where(x => typeof(QSBPatch).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); - // QSBPatchManager.Init(); - // var patchInstances = (List)typeof(QSBPatchManager) - // .GetField("_patchList", BindingFlags.NonPublic | BindingFlags.Static) - // .GetValue(typeof(QSBPatchManager)); + QSBPatchManager.Init(); + var patchInstances = (List)typeof(QSBPatchManager) + .GetField("_patchList", BindingFlags.NonPublic | BindingFlags.Static) + .GetValue(typeof(QSBPatchManager)); - // var failedTypes = new List(); - // foreach (var type in allPatchTypes) - // { - // if (!patchInstances.Any(x => x.GetType() == type)) - // { - // failedTypes.Add(type); - // } - // } + var failedTypes = new List(); + foreach (var type in allPatchTypes) + { + if (!patchInstances.Any(x => x.GetType() == type)) + { + failedTypes.Add(type); + } + } - // if (failedTypes.Count > 0) - // { - // Assert.Fail(string.Join(", ", failedTypes.Select(x => x.Name))); - // } - //} + if (failedTypes.Count > 0) + { + Assert.Fail(string.Join(", ", failedTypes.Select(x => x.Name))); + } + } } } diff --git a/QuantumUNET/QuantumUNET.csproj b/QuantumUNET/QuantumUNET.csproj index 74f0f29a..f7f44bb5 100644 --- a/QuantumUNET/QuantumUNET.csproj +++ b/QuantumUNET/QuantumUNET.csproj @@ -52,8 +52,9 @@ $(GameDir)\OuterWilds_Data\Managed\UnityEngine.IMGUIModule.dll - - $(GameDir)\OuterWilds_Data\Managed\UnityEngine.Networking.dll + + False + ..\QSB\lib\UnityEngine.Networking.dll False diff --git a/README.md b/README.md index 8a16bd69..c3a6ab7b 100644 --- a/README.md +++ b/README.md @@ -91,10 +91,10 @@ QSB relies on exact orders of objects found using Resources.FindObjectsOfTypeAll | Quantum objects | Yes | | Repairing ship parts | Yes | | Repairing "satellite" parts | No | -| Ship | Kinda of | +| Ship | Yes | | Ship log | Yes | -| Solanum | No | -| Timber Hearth satellite | No | +| Solanum | Yes | +| Timber Hearth satellite | Yes | | Tornadoes | No | QSB also changes some mechanics of the base game, to better fit a multiplayer experience. These include : @@ -137,19 +137,15 @@ Note - _nebula has no idea how Hamachi works and has never used it, so don't ask ## Playing as a client - Run the game. -- You'll see some new buttons on the top left. -- Replace `localhost` with the server's public IP address. -- Press "Connect". You can join servers in the menu or in-game, but it is recommended to join in the main menu. -- If you see "Stop", you are connected. -- If it stops at "Connecting to..." then you or the host has issues with their firewall/router/other. +- On the title/pause menu, select "MULTIPLAYER (CONNECT)". +- Enter the public IP address of the host. +- Hit connect, and pray. ## Playing as a host - Open port `7777` on your router. - Run the game. -- You'll see some new buttons on the top left. -- Press "Host". This can be done in-game or in the menu, but it is recommened to start servers in the menu. -- If you now see the "Stop" button, you are hosting. +- On the title/pause menu, select "MULTIPLAYER (HOST)". - Give your external IPv4 address to your clients ([like what you see here](http://whatismyip.host/)). ## Development Setup @@ -160,10 +156,10 @@ Note - _nebula has no idea how Hamachi works and has never used it, so don't ask - Open the file `QSB/QSB.csproj.user` in your favorite text editor - Edit the entry `` to point to the directory where Outer Wilds is installed - Edit the entry `` to point to your OWML directory (it is installed inside the Mod Manager directory) -- Do the same for QuantumUNET/QuantumUNET.csproj.user +- Do the same for `QuantumUNET/QuantumUNET.csproj.user` and `QSBTests/QSBTests.csproj.user` - Open the project solution file `QSB.sln` in Visual Studio - If needed, right click `References` in the Solution Explorer > Manage NuGet Packages > Update OWML to fix missing references -- Run this to stop tracking QSB.csproj.user: ```git update-index --skip-worktree QSB/QSB.csproj.user``` +- Run this to stop tracking QSB.csproj.user: ```git update-index --skip-worktree QSB/QSB.csproj.user``` (and do the same for the other .user files) To fix the references, right click "References" in the Solution Explorer > "Add Reference", and add all the missing DLLs (references with yellow warning icon). You can find these DLLs in the game's directory (`OuterWilds\OuterWilds_Data\Managed`); diff --git a/UnityEngine.Networking.dll b/UnityEngine.Networking.dll deleted file mode 100644 index 4db9ce9d..00000000 Binary files a/UnityEngine.Networking.dll and /dev/null differ