diff --git a/NewHorizons/Components/EOTE/DreamWorldEndTimes.cs b/NewHorizons/Components/EOTE/DreamWorldEndTimes.cs
new file mode 100644
index 00000000..839d286f
--- /dev/null
+++ b/NewHorizons/Components/EOTE/DreamWorldEndTimes.cs
@@ -0,0 +1,32 @@
+using NewHorizons.Utility.Files;
+using OWML.Common;
+using UnityEngine;
+
+namespace NewHorizons.Components.EOTE
+{
+ public class DreamWorldEndTimes : MonoBehaviour
+ {
+ private AudioType _endTimesAudio = AudioType.EndOfTime;
+ private AudioType _endTimesDreamAudio = AudioType.EndOfTime_Dream;
+
+ public void SetEndTimesAudio(AudioType audio)
+ {
+ _endTimesAudio = audio;
+ }
+
+ public void AssignEndTimes(OWAudioSource endTimesSource) => Assign(endTimesSource, _endTimesAudio);
+
+ public void SetEndTimesDreamAudio(AudioType audio)
+ {
+ _endTimesDreamAudio = audio;
+ }
+
+ public void AssignEndTimesDream(OWAudioSource endTimesSource) => Assign(endTimesSource, _endTimesDreamAudio);
+
+ public static void Assign(OWAudioSource endTimesSource, AudioType audio)
+ {
+ endTimesSource.Stop();
+ endTimesSource.AssignAudioLibraryClip(audio);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NewHorizons/External/Configs/StarSystemConfig.cs b/NewHorizons/External/Configs/StarSystemConfig.cs
index 28ecc4dd..a5fcb088 100644
--- a/NewHorizons/External/Configs/StarSystemConfig.cs
+++ b/NewHorizons/External/Configs/StarSystemConfig.cs
@@ -82,11 +82,14 @@ namespace NewHorizons.External.Configs
[Obsolete("travelAudioFilePath is deprecated, please use travelAudio instead")]
public string travelAudioFilePath;
- ///
- /// The audio that will play when travelling in space. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
- ///
+ [Obsolete("travelAudio is deprecated, please use travelAudio instead")]
public string travelAudio;
+ ///
+ /// Replace music that plays globally
+ ///
+ public GlobalMusicModule GlobalMusic;
+
///
/// Configure warping to this system with the vessel
///
@@ -192,6 +195,45 @@ namespace NewHorizons.External.Configs
public string backPath;
}
+ [JsonObject]
+ public class GlobalMusicModule
+ {
+ ///
+ /// The audio that will play when travelling in space. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
+ ///
+ public string travelAudio;
+
+ ///
+ /// The audio that will play right before the loop ends. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
+ ///
+ public string endTimesAudio;
+
+ ///
+ /// The audio that will play right before the loop ends while inside the dreamworld. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
+ ///
+ public string endTimesDreamAudio;
+
+ ///
+ /// The audio that will play when travelling through a bramble dimension. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
+ ///
+ public string brambleDimensionAudio;
+
+ ///
+ /// The audio that will play when you leave the ash twin project after taking out the advanced warp core. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
+ ///
+ public string finalEndTimesIntroAudio;
+
+ ///
+ /// The audio that will loop after the final end times intro. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
+ ///
+ public string finalEndTimesLoopAudio;
+
+ ///
+ /// The audio that will loop after the final end times intro while inside a bramble dimension. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
+ ///
+ public string finalEndTimesBrambleDimensionAudio;
+ }
+
[JsonObject]
public class VesselModule
{
@@ -283,7 +325,6 @@ namespace NewHorizons.External.Configs
// If current one is null take the other
factRequiredForWarp = string.IsNullOrEmpty(factRequiredForWarp) ? otherConfig.factRequiredForWarp : factRequiredForWarp;
Skybox = Skybox == null ? otherConfig.Skybox : Skybox;
- travelAudio = string.IsNullOrEmpty(travelAudio) ? otherConfig.travelAudio : travelAudio;
// False by default so if one is true go true
mapRestricted = mapRestricted || otherConfig.mapRestricted;
@@ -302,6 +343,21 @@ namespace NewHorizons.External.Configs
Vessel ??= otherConfig.Vessel;
}
+ if (GlobalMusic != null && otherConfig.GlobalMusic != null)
+ {
+ GlobalMusic.travelAudio = string.IsNullOrEmpty(GlobalMusic.travelAudio) ? otherConfig.GlobalMusic.travelAudio : GlobalMusic.travelAudio;
+ GlobalMusic.endTimesAudio = string.IsNullOrEmpty(GlobalMusic.endTimesAudio) ? otherConfig.GlobalMusic.endTimesAudio : GlobalMusic.endTimesAudio;
+ GlobalMusic.endTimesDreamAudio = string.IsNullOrEmpty(GlobalMusic.endTimesDreamAudio) ? otherConfig.GlobalMusic.endTimesDreamAudio : GlobalMusic.endTimesDreamAudio;
+ GlobalMusic.brambleDimensionAudio = string.IsNullOrEmpty(GlobalMusic.brambleDimensionAudio) ? otherConfig.GlobalMusic.brambleDimensionAudio : GlobalMusic.brambleDimensionAudio;
+ GlobalMusic.finalEndTimesIntroAudio = string.IsNullOrEmpty(GlobalMusic.finalEndTimesIntroAudio) ? otherConfig.GlobalMusic.finalEndTimesIntroAudio : GlobalMusic.finalEndTimesIntroAudio;
+ GlobalMusic.finalEndTimesLoopAudio = string.IsNullOrEmpty(GlobalMusic.finalEndTimesLoopAudio) ? otherConfig.GlobalMusic.finalEndTimesLoopAudio : GlobalMusic.finalEndTimesLoopAudio;
+ GlobalMusic.finalEndTimesBrambleDimensionAudio = string.IsNullOrEmpty(GlobalMusic.finalEndTimesBrambleDimensionAudio) ? otherConfig.GlobalMusic.finalEndTimesBrambleDimensionAudio : GlobalMusic.finalEndTimesBrambleDimensionAudio;
+ }
+ else
+ {
+ GlobalMusic ??= otherConfig.GlobalMusic;
+ }
+
entryPositions = Concatenate(entryPositions, otherConfig.entryPositions);
curiosities = Concatenate(curiosities, otherConfig.curiosities);
initialReveal = Concatenate(initialReveal, otherConfig.initialReveal);
@@ -319,6 +375,11 @@ namespace NewHorizons.External.Configs
#pragma warning disable 612, 618
if (!string.IsNullOrEmpty(travelAudioClip)) travelAudio = travelAudioClip;
if (!string.IsNullOrEmpty(travelAudioFilePath)) travelAudio = travelAudioFilePath;
+ if (!string.IsNullOrEmpty(travelAudio))
+ {
+ if (GlobalMusic == null) GlobalMusic = new GlobalMusicModule();
+ if (string.IsNullOrEmpty(GlobalMusic.travelAudio)) GlobalMusic.travelAudio = travelAudio;
+ }
if (coords != null || vesselPosition != null || vesselRotation != null || warpExitPosition != null || warpExitRotation != null)
{
if (Vessel == null)
diff --git a/NewHorizons/Handlers/StarChartHandler.cs b/NewHorizons/Handlers/StarChartHandler.cs
index b1ef9eea..3b874ee9 100644
--- a/NewHorizons/Handlers/StarChartHandler.cs
+++ b/NewHorizons/Handlers/StarChartHandler.cs
@@ -121,7 +121,7 @@ namespace NewHorizons.Handlers
public static void OnRevealFact(string factID)
{
- if (_factIDToStarSystem.TryGetValue(factID, out var systemUnlocked))
+ if (_factIDToStarSystem != null && _factIDToStarSystem.TryGetValue(factID, out var systemUnlocked))
{
NHLogger.Log($"Just learned [{factID}] and unlocked [{systemUnlocked}]");
if (!Main.HasWarpDrive)
diff --git a/NewHorizons/Handlers/SystemCreationHandler.cs b/NewHorizons/Handlers/SystemCreationHandler.cs
index 5936434a..db2951a3 100644
--- a/NewHorizons/Handlers/SystemCreationHandler.cs
+++ b/NewHorizons/Handlers/SystemCreationHandler.cs
@@ -8,6 +8,8 @@ using NewHorizons.Utility.OuterWilds;
using UnityEngine;
using Object = UnityEngine.Object;
using NewHorizons.OtherMods;
+using NewHorizons.Components.EOTE;
+using Epic.OnlineServices.Presence;
namespace NewHorizons.Handlers
{
@@ -46,9 +48,52 @@ namespace NewHorizons.Handlers
TimeLoopUtilities.SetLoopDuration(system.Config.loopDuration);
}
- if (!string.IsNullOrEmpty(system.Config.travelAudio))
+ if (system.Config.GlobalMusic != null)
{
- Delay.FireOnNextUpdate(() => AudioUtilities.SetAudioClip(Locator.GetGlobalMusicController()._travelSource, system.Config.travelAudio, system.Mod));
+ if (!string.IsNullOrEmpty(system.Config.GlobalMusic.travelAudio))
+ {
+ var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.travelAudio, system.Mod);
+ Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._travelSource.AssignAudioLibraryClip(audioType));
+ }
+
+ if (!string.IsNullOrEmpty(system.Config.GlobalMusic.endTimesAudio))
+ {
+ var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.endTimesAudio, system.Mod);
+ Delay.FireOnNextUpdate(() => {
+ Locator.GetGlobalMusicController().gameObject.GetAddComponent().SetEndTimesAudio(audioType);
+ Locator.GetGlobalMusicController()._endTimesSource.AssignAudioLibraryClip(audioType);
+ });
+ }
+
+ if (!string.IsNullOrEmpty(system.Config.GlobalMusic.endTimesDreamAudio))
+ {
+ var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.endTimesDreamAudio, system.Mod);
+ Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController().gameObject.GetAddComponent().SetEndTimesDreamAudio(audioType));
+ }
+
+ if (!string.IsNullOrEmpty(system.Config.GlobalMusic.brambleDimensionAudio))
+ {
+ var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.brambleDimensionAudio, system.Mod);
+ Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._darkBrambleSource.AssignAudioLibraryClip(audioType));
+ }
+
+ if (!string.IsNullOrEmpty(system.Config.GlobalMusic.finalEndTimesIntroAudio))
+ {
+ var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.finalEndTimesIntroAudio, system.Mod);
+ Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._finalEndTimesIntroSource.AssignAudioLibraryClip(audioType));
+ }
+
+ if (!string.IsNullOrEmpty(system.Config.GlobalMusic.finalEndTimesLoopAudio))
+ {
+ var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.finalEndTimesLoopAudio, system.Mod);
+ Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._finalEndTimesLoopSource.AssignAudioLibraryClip(audioType));
+ }
+
+ if (!string.IsNullOrEmpty(system.Config.GlobalMusic.finalEndTimesBrambleDimensionAudio))
+ {
+ var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.finalEndTimesBrambleDimensionAudio, system.Mod);
+ Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._finalEndTimesDarkBrambleSource.AssignAudioLibraryClip(audioType));
+ }
}
}
}
diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs
index 7aac5449..3b38bd35 100644
--- a/NewHorizons/Main.cs
+++ b/NewHorizons/Main.cs
@@ -690,7 +690,7 @@ namespace NewHorizons
if (SystemDict.ContainsKey(starSystemName))
{
- if (string.IsNullOrEmpty(SystemDict[starSystemName].Config.travelAudio) && SystemDict[starSystemName].Config.Skybox == null)
+ if (SystemDict[starSystemName].Config.GlobalMusic == null && SystemDict[starSystemName].Config.Skybox == null)
SystemDict[starSystemName].Mod = mod;
SystemDict[starSystemName].Config.Merge(starSystemConfig);
}
diff --git a/NewHorizons/Patches/GlobalMusicControllerPatches.cs b/NewHorizons/Patches/GlobalMusicControllerPatches.cs
index 776cb8e8..9697beb7 100644
--- a/NewHorizons/Patches/GlobalMusicControllerPatches.cs
+++ b/NewHorizons/Patches/GlobalMusicControllerPatches.cs
@@ -1,10 +1,14 @@
-using HarmonyLib;
+using HarmonyLib;
+using NewHorizons.Components.EOTE;
+using NewHorizons.Utility;
+using System.Collections.Generic;
+using System.Reflection.Emit;
using UnityEngine;
namespace NewHorizons.Patches;
[HarmonyPatch(typeof(GlobalMusicController))]
-public class GlobalMusicControllerPatches
+public static class GlobalMusicControllerPatches
{
private static AudioDetector _audioDetector;
@@ -21,7 +25,7 @@ public class GlobalMusicControllerPatches
PlayerState.AtFlightConsole() &&
!PlayerState.IsHullBreached() &&
!__instance._playingFinalEndTimes &&
- _audioDetector._activeVolumes.Count == 0; // change - don't play if in another audio volume
+ _audioDetector._activeVolumes.Count <= 1; // change - don't play if in another audio volume other than ambient
var playing = __instance._darkBrambleSource.isPlaying &&
!__instance._darkBrambleSource.IsFadingOut();
if (shouldBePlaying && !playing)
@@ -33,6 +37,93 @@ public class GlobalMusicControllerPatches
__instance._darkBrambleSource.FadeOut(5f);
}
+ return false;
+ }
+
+ ///
+ /// Replaces any 85f with
+ ///
+ [HarmonyTranspiler]
+ [HarmonyPatch(nameof(GlobalMusicController.UpdateEndTimesMusic))]
+ public static IEnumerable GlobalMusicController_UpdateEndTimesMusic(IEnumerable instructions, ILGenerator generator)
+ {
+ return new CodeMatcher(instructions, generator).MatchForward(true,
+ new CodeMatch(OpCodes.Call),
+ new CodeMatch(OpCodes.Ldc_R4, 85f),
+ new CodeMatch(OpCodes.Ble_Un)
+ ).Advance(-1).RemoveInstruction().Insert(
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(NewHorizonsExtensions), nameof(NewHorizonsExtensions.GetSecondsBeforeSupernovaPlayTime)))
+ ).MatchForward(true,
+ new CodeMatch(OpCodes.Call),
+ new CodeMatch(OpCodes.Ldc_R4, 85f),
+ new CodeMatch(OpCodes.Bge_Un)
+ ).Advance(-1).RemoveInstruction().Insert(
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(NewHorizonsExtensions), nameof(NewHorizonsExtensions.GetSecondsBeforeSupernovaPlayTime)))
+ ).MatchForward(false,
+ new CodeMatch(OpCodes.Ldc_R4, 85f),
+ new CodeMatch(OpCodes.Call),
+ new CodeMatch(OpCodes.Sub)
+ ).RemoveInstruction().Insert(
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(NewHorizonsExtensions), nameof(NewHorizonsExtensions.GetSecondsBeforeSupernovaPlayTime)))
+ ).InstructionEnumeration();
+ }
+
+ // Custom end times for dreamworld
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(GlobalMusicController.OnEnterDreamWorld))]
+ public static bool GlobalMusicController_OnEnterDreamWorld(GlobalMusicController __instance)
+ {
+ if (__instance._playingFinalEndTimes)
+ {
+ __instance._finalEndTimesIntroSource.Stop();
+ __instance._finalEndTimesLoopSource.Stop();
+ __instance._finalEndTimesDarkBrambleSource.FadeIn(1f);
+ }
+ else
+ {
+ if (__instance.TryGetComponent(out DreamWorldEndTimes dreamWorldEndTimes))
+ {
+ dreamWorldEndTimes.AssignEndTimesDream(__instance._endTimesSource);
+ }
+ else
+ {
+ __instance._endTimesSource.Stop();
+ __instance._endTimesSource.AssignAudioLibraryClip(AudioType.EndOfTime_Dream);
+ }
+ __instance._playingEndTimes = false;
+ }
+
+ return false;
+ }
+
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(GlobalMusicController.OnExitDreamWorld))]
+ public static bool GlobalMusicController_OnExitDreamWorld(GlobalMusicController __instance)
+ {
+ if (__instance._playingFinalEndTimes)
+ {
+ __instance._finalEndTimesLoopSource.FadeIn(1f);
+ __instance._finalEndTimesDarkBrambleSource.Stop();
+ }
+ else
+ {
+ if (__instance.TryGetComponent(out DreamWorldEndTimes dreamWorldEndTimes))
+ {
+ dreamWorldEndTimes.AssignEndTimes(__instance._endTimesSource);
+ }
+ else
+ {
+ __instance._endTimesSource.Stop();
+ __instance._endTimesSource.AssignAudioLibraryClip(AudioType.EndOfTime);
+ }
+ __instance._playingEndTimes = false;
+ }
+
return false;
}
}
diff --git a/NewHorizons/Schemas/star_system_schema.json b/NewHorizons/Schemas/star_system_schema.json
index 8c479fe8..814773c5 100644
--- a/NewHorizons/Schemas/star_system_schema.json
+++ b/NewHorizons/Schemas/star_system_schema.json
@@ -59,9 +59,9 @@
"type": "boolean",
"description": "Set to `true` if you want the player to stay in this star system if they die in it."
},
- "travelAudio": {
- "type": "string",
- "description": "The audio that will play when travelling in space. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ "GlobalMusic": {
+ "description": "Replace music that plays globally",
+ "$ref": "#/definitions/GlobalMusicModule"
},
"Vessel": {
"description": "Configure warping to this system with the vessel",
@@ -143,6 +143,40 @@
}
}
},
+ "GlobalMusicModule": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "travelAudio": {
+ "type": "string",
+ "description": "The audio that will play when travelling in space. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ },
+ "endTimesAudio": {
+ "type": "string",
+ "description": "The audio that will play right before the loop ends. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ },
+ "endTimesDreamAudio": {
+ "type": "string",
+ "description": "The audio that will play right before the loop ends while inside the dreamworld. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ },
+ "brambleDimensionAudio": {
+ "type": "string",
+ "description": "The audio that will play when travelling through a bramble dimension. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ },
+ "finalEndTimesIntroAudio": {
+ "type": "string",
+ "description": "The audio that will play when you leave the ash twin project after taking out the advanced warp core. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ },
+ "finalEndTimesLoopAudio": {
+ "type": "string",
+ "description": "The audio that will loop after the final end times intro. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ },
+ "finalEndTimesBrambleDimensionAudio": {
+ "type": "string",
+ "description": "The audio that will loop after the final end times intro while inside a bramble dimension. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
+ }
+ }
+ },
"VesselModule": {
"type": "object",
"additionalProperties": false,
diff --git a/NewHorizons/Utility/Files/AudioUtilities.cs b/NewHorizons/Utility/Files/AudioUtilities.cs
index ca01b44a..fe09d46e 100644
--- a/NewHorizons/Utility/Files/AudioUtilities.cs
+++ b/NewHorizons/Utility/Files/AudioUtilities.cs
@@ -121,7 +121,9 @@ namespace NewHorizons.Utility.Files
}
else
{
- return dh.audioClip;
+ var audioClip = dh.audioClip;
+ audioClip.name = Path.GetFileNameWithoutExtension(path);
+ return audioClip;
}
}
}
@@ -140,7 +142,9 @@ namespace NewHorizons.Utility.Files
}
else
{
- return DownloadHandlerAudioClip.GetContent(www);
+ var audioClip = DownloadHandlerAudioClip.GetContent(www);
+ audioClip.name = Path.GetFileNameWithoutExtension(path);
+ return audioClip;
}
}
}
diff --git a/NewHorizons/Utility/Files/ImageUtilities.cs b/NewHorizons/Utility/Files/ImageUtilities.cs
index 3c01bd16..218f64ed 100644
--- a/NewHorizons/Utility/Files/ImageUtilities.cs
+++ b/NewHorizons/Utility/Files/ImageUtilities.cs
@@ -25,8 +25,12 @@ namespace NewHorizons.Utility.Files
return _textureCache.ContainsKey(key);
}
+ #region obsolete
// needed for backwards compat :P
+ // idk what mod used it
+ [Obsolete]
public static Texture2D GetTexture(IModBehaviour mod, string filename, bool useMipmaps, bool wrap) => GetTexture(mod, filename, useMipmaps, wrap, false);
+ #endregion
// bug: cache only considers file path, not wrap/mips/linear. oh well
public static Texture2D GetTexture(IModBehaviour mod, string filename, bool useMipmaps = true, bool wrap = false, bool linear = false)
{
diff --git a/NewHorizons/Utility/NewHorizonExtensions.cs b/NewHorizons/Utility/NewHorizonExtensions.cs
index 66f5babf..9f4da941 100644
--- a/NewHorizons/Utility/NewHorizonExtensions.cs
+++ b/NewHorizons/Utility/NewHorizonExtensions.cs
@@ -1,3 +1,4 @@
+using HarmonyLib;
using NewHorizons.External.Configs;
using NewHorizons.External.Modules.VariableSize;
using NewHorizons.External.SerializableData;
@@ -435,5 +436,28 @@ namespace NewHorizons.Utility
playerCameraEffectController._owCamera.postProcessingSettings.bloom.threshold = 0f;
playerCameraEffectController._owCamera.postProcessingSettings.eyeMaskEnabled = true;
}
+
+ public static float GetSecondsBeforeSupernovaPlayTime(this GlobalMusicController globalMusicController)
+ {
+ var clip = globalMusicController._endTimesSource.audioLibraryClip;
+ if (clip == AudioType.EndOfTime || clip == AudioType.EndOfTime_Dream)
+ return GlobalMusicController.secondsBeforeSupernovaPlayTime;
+ return globalMusicController._endTimesSource.clip.length;
+ }
+
+ public static CodeMatcher LogInstructions(this CodeMatcher matcher, string prefix)
+ {
+ matcher.InstructionEnumeration().LogInstructions(prefix);
+ return matcher;
+ }
+
+ public static IEnumerable LogInstructions(this IEnumerable instructions, string prefix)
+ {
+ var message = prefix;
+ foreach (var instruction in instructions)
+ message += $"\n{instruction}";
+ Debug.LogError(message);
+ return instructions;
+ }
}
}