## Major features
- New API methods to: Add ship logs from xml, add dialogue from xml,
create a new planet from json string. All of these methods work directly
with strings or XElements and don't load files on their own.

## Improvements
- Pitch anglerfish sounds based on scale. Resolves #160.

## Bug fixes
- Fixes ship being broken when spawning on the center of the universe.
Resolves #648
- Fix Stranger cloak breaking on second loop onwards. Resolves #673.
This commit is contained in:
Nick 2023-07-27 00:14:27 -04:00 committed by GitHub
commit 07f67484d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 360 additions and 116 deletions

View File

@ -13,6 +13,9 @@ namespace NewHorizons.Builder.General
public static class SpawnPointBuilder public static class SpawnPointBuilder
{ {
private static bool suitUpQueued = false; private static bool suitUpQueued = false;
public static SpawnPoint ShipSpawn { get; private set; }
public static Vector3 ShipSpawnOffset { get; private set; }
public static SpawnPoint Make(GameObject planetGO, SpawnModule module, OWRigidbody owRigidBody) public static SpawnPoint Make(GameObject planetGO, SpawnModule module, OWRigidbody owRigidBody)
{ {
SpawnPoint playerSpawn = null; SpawnPoint playerSpawn = null;
@ -35,41 +38,21 @@ namespace NewHorizons.Builder.General
if (module.shipSpawn != null) if (module.shipSpawn != null)
{ {
GameObject spawnGO = GeneralPropBuilder.MakeNew("ShipSpawnPoint", planetGO, null, module.shipSpawn); var spawnGO = GeneralPropBuilder.MakeNew("ShipSpawnPoint", planetGO, null, module.shipSpawn);
spawnGO.SetActive(false); spawnGO.SetActive(false);
spawnGO.layer = Layer.PlayerSafetyCollider; spawnGO.layer = Layer.PlayerSafetyCollider;
var shipSpawn = spawnGO.AddComponent<SpawnPoint>(); ShipSpawn = spawnGO.AddComponent<SpawnPoint>();
shipSpawn._isShipSpawn = true; ShipSpawn._isShipSpawn = true;
shipSpawn._attachedBody = owRigidBody; ShipSpawn._attachedBody = owRigidBody;
shipSpawn._spawnLocation = SpawnLocation.None; ShipSpawn._spawnLocation = SpawnLocation.None;
// #601 we need to actually set the right trigger volumes here // #601 we need to actually set the right trigger volumes here
shipSpawn._triggerVolumes = new OWTriggerVolume[0]; ShipSpawn._triggerVolumes = new OWTriggerVolume[0];
// TODO: this should happen elsewhere ShipSpawnOffset = module.shipSpawn.offset ?? (module.shipSpawn.alignRadial.GetValueOrDefault() ? Vector3.up * 4 : Vector3.zero);
var ship = SearchUtilities.Find("Ship_Body");
if (ship != null)
{
ship.transform.position = spawnGO.transform.position;
ship.transform.rotation = spawnGO.transform.rotation;
// Move it up a bit more when aligning to surface
if (module.shipSpawn.offset != null)
{
ship.transform.position += spawnGO.transform.TransformDirection(module.shipSpawn.offset);
}
else if (module.shipSpawn.alignRadial.GetValueOrDefault())
{
ship.transform.position += ship.transform.up * 4f;
}
ship.GetRequiredComponent<MatchInitialMotion>().SetBodyToMatch(owRigidBody);
}
spawnGO.SetActive(true); spawnGO.SetActive(true);
// Ship doesn't get activated sometimes
Delay.RunWhen(() => Main.IsSystemReady, () => ship.gameObject.SetActive(true));
} }
if ((Main.Instance.IsWarpingFromVessel || (!Main.Instance.IsWarpingFromShip && (module.playerSpawn?.startWithSuit ?? false))) && !suitUpQueued) if ((Main.Instance.IsWarpingFromVessel || (!Main.Instance.IsWarpingFromShip && (module.playerSpawn?.startWithSuit ?? false))) && !suitUpQueued)

View File

@ -7,6 +7,7 @@ using NewHorizons.Utility.OWML;
using OWML.Common; using OWML.Common;
using System.IO; using System.IO;
using System.Xml; using System.Xml;
using System.Xml.Linq;
using UnityEngine; using UnityEngine;
namespace NewHorizons.Builder.Props namespace NewHorizons.Builder.Props
@ -15,6 +16,14 @@ namespace NewHorizons.Builder.Props
{ {
// Returns the character dialogue tree and remote dialogue trigger, if applicable. // Returns the character dialogue tree and remote dialogue trigger, if applicable.
public static (CharacterDialogueTree, RemoteDialogueTrigger) Make(GameObject go, Sector sector, DialogueInfo info, IModBehaviour mod) public static (CharacterDialogueTree, RemoteDialogueTrigger) Make(GameObject go, Sector sector, DialogueInfo info, IModBehaviour mod)
{
var xml = File.ReadAllText(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, info.xmlFile));
var dialogueName = Path.GetFileNameWithoutExtension(info.xmlFile);
return Make(go, sector, info, xml, dialogueName);
}
// Create dialogue directly from xml string instead of loading it from a file
public static (CharacterDialogueTree, RemoteDialogueTrigger) Make(GameObject go, Sector sector, DialogueInfo info, string xml, string dialogueName)
{ {
NHLogger.LogVerbose($"[DIALOGUE] Created a new character dialogue [{info.rename}] on [{info.parentPath}]"); NHLogger.LogVerbose($"[DIALOGUE] Created a new character dialogue [{info.rename}] on [{info.parentPath}]");
@ -26,7 +35,7 @@ namespace NewHorizons.Builder.Props
return (null, null); return (null, null);
} }
var dialogue = MakeConversationZone(go, sector, info, mod.ModHelper); var dialogue = MakeConversationZone(go, sector, info, xml, dialogueName);
RemoteDialogueTrigger remoteTrigger = null; RemoteDialogueTrigger remoteTrigger = null;
if (info.remoteTrigger != null) if (info.remoteTrigger != null)
@ -76,7 +85,7 @@ namespace NewHorizons.Builder.Props
return remoteDialogueTrigger; return remoteDialogueTrigger;
} }
private static CharacterDialogueTree MakeConversationZone(GameObject planetGO, Sector sector, DialogueInfo info, IModHelper mod) private static CharacterDialogueTree MakeConversationZone(GameObject planetGO, Sector sector, DialogueInfo info, string xml, string dialogueName)
{ {
var conversationZone = GeneralPropBuilder.MakeNew("ConversationZone", planetGO, sector, info, defaultParentPath: info.pathToAnimController); var conversationZone = GeneralPropBuilder.MakeNew("ConversationZone", planetGO, sector, info, defaultParentPath: info.pathToAnimController);
@ -100,13 +109,11 @@ namespace NewHorizons.Builder.Props
var dialogueTree = conversationZone.AddComponent<NHCharacterDialogueTree>(); var dialogueTree = conversationZone.AddComponent<NHCharacterDialogueTree>();
var xml = File.ReadAllText(Path.Combine(mod.Manifest.ModFolderPath, info.xmlFile));
var text = new TextAsset(xml) var text = new TextAsset(xml)
{ {
// Text assets need a name to be used with VoiceMod // Text assets need a name to be used with VoiceMod
name = Path.GetFileNameWithoutExtension(info.xmlFile) name = dialogueName
}; };
dialogueTree.SetTextXml(text); dialogueTree.SetTextXml(text);
AddTranslation(xml); AddTranslation(xml);

View File

@ -55,15 +55,20 @@ namespace NewHorizons.Builder.ShipLog
{ {
string systemName = body.Config.starSystem; string systemName = body.Config.starSystem;
XElement astroBodyFile = XElement.Load(Path.Combine(body.Mod.ModHelper.Manifest.ModFolderPath, body.Config.ShipLog.xmlFile)); XElement astroBodyFile = XElement.Load(Path.Combine(body.Mod.ModHelper.Manifest.ModFolderPath, body.Config.ShipLog.xmlFile));
XElement astroBodyId = astroBodyFile.Element("ID"); AddShipLogXML(manager, astroBodyFile, body);
}
public static void AddShipLogXML(ShipLogManager manager, XElement xml, NewHorizonsBody body)
{
XElement astroBodyId = xml.Element("ID");
if (astroBodyId == null) if (astroBodyId == null)
{ {
NHLogger.LogError("Failed to load ship logs for " + systemName + "!"); NHLogger.LogError("Failed to load ship logs for " + body.Config.name + "!");
} }
else else
{ {
var entryIDs = new List<string>(); var entryIDs = new List<string>();
foreach (XElement entryElement in astroBodyFile.DescendantsAndSelf("Entry")) foreach (XElement entryElement in xml.DescendantsAndSelf("Entry"))
{ {
XElement curiosityName = entryElement.Element("Curiosity"); XElement curiosityName = entryElement.Element("Curiosity");
XElement id = entryElement.Element("ID"); XElement id = entryElement.Element("ID");
@ -98,8 +103,8 @@ namespace NewHorizons.Builder.ShipLog
} }
AddTranslation(entryElement); AddTranslation(entryElement);
} }
TextAsset newAsset = new TextAsset(astroBodyFile.ToString()); var newAsset = new TextAsset(xml.ToString());
List<TextAsset> newBodies = new List<TextAsset>(manager._shipLogXmlAssets) { newAsset }; var newBodies = new List<TextAsset>(manager._shipLogXmlAssets) { newAsset };
manager._shipLogXmlAssets = newBodies.ToArray(); manager._shipLogXmlAssets = newBodies.ToArray();
ShipLogHandler.AddConfig(astroBodyId.Value, entryIDs, body); ShipLogHandler.AddConfig(astroBodyId.Value, entryIDs, body);
} }

View File

@ -1,6 +1,7 @@
using NewHorizons.Components.Stars; using NewHorizons.Components.Stars;
using NewHorizons.Handlers; using NewHorizons.Handlers;
using NewHorizons.Utility.OWML; using NewHorizons.Utility.OWML;
using System.Linq;
using UnityEngine; using UnityEngine;
namespace NewHorizons.Components.EOTE namespace NewHorizons.Components.EOTE
@ -11,6 +12,8 @@ namespace NewHorizons.Components.EOTE
private CloakFieldController _currentController; private CloakFieldController _currentController;
public void Start() public void Start()
{
if (CloakHandler.Cloaks.Any())
{ {
// Enable and disable all cloaks, else Stranger state is weird at the start // Enable and disable all cloaks, else Stranger state is weird at the start
foreach (var cloak in CloakHandler.Cloaks) foreach (var cloak in CloakHandler.Cloaks)
@ -18,6 +21,10 @@ namespace NewHorizons.Components.EOTE
SetCurrentCloak(cloak); SetCurrentCloak(cloak);
cloak.enabled = false; cloak.enabled = false;
} }
// Make sure a cloak is enabled
SetCurrentCloak(CloakHandler.Cloaks.First());
}
} }
// Always makes sure the Locator's cloak field controller is the one that is between the player and the sun // Always makes sure the Locator's cloak field controller is the one that is between the player and the sun

View File

@ -201,6 +201,8 @@ namespace NewHorizons.Components.Ship
GlobalMessenger.FireEvent("EnterShip"); GlobalMessenger.FireEvent("EnterShip");
PlayerState.OnEnterShip(); PlayerState.OnEnterShip();
PlayerSpawnHandler.SpawnShip();
} }
} }
} }

View File

@ -14,6 +14,11 @@ namespace NewHorizons.External.SerializableData
this.a = a; this.a = a;
} }
public static MColor FromColor(Color color)
{
return new MColor((int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255), (int)(color.a * 255));
}
/// <summary> /// <summary>
/// The red component of this colour from 0-255, higher values will make the colour glow if applicable. /// The red component of this colour from 0-255, higher values will make the colour glow if applicable.
/// </summary> /// </summary>

View File

@ -1,3 +1,4 @@
using NewHorizons.Builder.General;
using NewHorizons.Utility; using NewHorizons.Utility;
using NewHorizons.Utility.OWML; using NewHorizons.Utility.OWML;
using System.Collections; using System.Collections;
@ -45,35 +46,73 @@ namespace NewHorizons.Handlers
} }
} }
public static void SpawnShip()
{
var ship = SearchUtilities.Find("Ship_Body");
if (ship != null)
{
ship.SetActive(true);
var pos = SpawnPointBuilder.ShipSpawn.transform.position;
// Move it up a bit more when aligning to surface
if (SpawnPointBuilder.ShipSpawnOffset != null)
{
pos += SpawnPointBuilder.ShipSpawn.transform.TransformDirection(SpawnPointBuilder.ShipSpawnOffset);
}
SpawnBody(ship.GetAttachedOWRigidbody(), SpawnPointBuilder.ShipSpawn, pos);
}
}
private static IEnumerator SpawnCoroutine(int length) private static IEnumerator SpawnCoroutine(int length)
{ {
for(int i = 0; i < length; i++) for(int i = 0; i < length; i++)
{ {
FixVelocity(); FixPlayerVelocity();
yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame();
} }
InvulnerabilityHandler.MakeInvulnerable(false); InvulnerabilityHandler.MakeInvulnerable(false);
if (!Main.Instance.IsWarpingFromShip)
{
if (SpawnPointBuilder.ShipSpawn != null)
{
NHLogger.Log("Spawning player ship");
SpawnShip();
}
else
{
NHLogger.Log("System has no ship spawn. Deactivating it.");
SearchUtilities.Find("Ship_Body")?.SetActive(false);
}
}
} }
private static void FixVelocity() private static void FixPlayerVelocity()
{ {
var playerBody = SearchUtilities.Find("Player_Body").GetAttachedOWRigidbody(); var playerBody = SearchUtilities.Find("Player_Body").GetAttachedOWRigidbody();
var spawn = GetDefaultSpawn();
var resources = playerBody.GetComponent<PlayerResources>(); var resources = playerBody.GetComponent<PlayerResources>();
playerBody.WarpToPositionRotation(spawn.transform.position, spawn.transform.rotation); SpawnBody(playerBody, GetDefaultSpawn());
var spawnVelocity = spawn._attachedBody.GetVelocity();
var spawnAngularVelocity = spawn._attachedBody.GetPointTangentialVelocity(playerBody.transform.position);
var velocity = spawnVelocity + spawnAngularVelocity;
playerBody.SetVelocity(velocity);
NHLogger.LogVerbose($"Player spawn velocity {velocity} Player velocity {playerBody.GetVelocity()} spawn body {spawnVelocity} spawn angular vel {spawnAngularVelocity}");
resources._currentHealth = 100f; resources._currentHealth = 100f;
} }
public static void SpawnBody(OWRigidbody body, SpawnPoint spawn, Vector3? positionOverride = null)
{
var pos = positionOverride ?? spawn.transform.position;
body.WarpToPositionRotation(pos, spawn.transform.rotation);
var spawnVelocity = spawn._attachedBody.GetVelocity();
var spawnAngularVelocity = spawn._attachedBody.GetPointTangentialVelocity(pos);
var velocity = spawnVelocity + spawnAngularVelocity;
body.SetVelocity(velocity);
}
private static Vector3 CalculateMatchVelocity(OWRigidbody owRigidbody, OWRigidbody bodyToMatch, bool ignoreAngularVelocity) private static Vector3 CalculateMatchVelocity(OWRigidbody owRigidbody, OWRigidbody bodyToMatch, bool ignoreAngularVelocity)
{ {
var vector = Vector3.zero; var vector = Vector3.zero;

View File

@ -1,6 +1,7 @@
using OWML.Common; using OWML.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
@ -8,11 +9,13 @@ namespace NewHorizons
{ {
public interface INewHorizons public interface INewHorizons
{ {
#region Obsolete
[Obsolete("Create(Dictionary<string, object> config) is deprecated, please use LoadConfigs(IModBehaviour mod) instead")] [Obsolete("Create(Dictionary<string, object> config) is deprecated, please use LoadConfigs(IModBehaviour mod) instead")]
void Create(Dictionary<string, object> config); void Create(Dictionary<string, object> config);
[Obsolete("Create(Dictionary<string, object> config) is deprecated, please use LoadConfigs(IModBehaviour mod) instead")] [Obsolete("Create(Dictionary<string, object> config) is deprecated, please use LoadConfigs(IModBehaviour mod) instead")]
void Create(Dictionary<string, object> config, IModBehaviour mod); void Create(Dictionary<string, object> config, IModBehaviour mod);
#endregion
/// <summary> /// <summary>
/// Will load all configs in the regular folders (planets, systems, translations, etc) for this mod. /// Will load all configs in the regular folders (planets, systems, translations, etc) for this mod.
@ -26,11 +29,30 @@ namespace NewHorizons
/// </summary> /// </summary>
GameObject GetPlanet(string name); GameObject GetPlanet(string name);
/// <summary>
/// Returns the uniqueIDs of each installed NH addon.
/// </summary>
string[] GetInstalledAddons();
#region Get/set/change star system
/// <summary> /// <summary>
/// The name of the current star system loaded. /// The name of the current star system loaded.
/// </summary> /// </summary>
string GetCurrentStarSystem(); string GetCurrentStarSystem();
/// <summary>
/// Allows you to overwrite the default system. This is where the player is respawned after dying.
/// </summary>
bool SetDefaultSystem(string name);
/// <summary>
/// Allows you to instantly begin a warp to a new star system.
/// Will return false if that system does not exist (cannot be warped to).
/// </summary>
bool ChangeCurrentStarSystem(string name);
#endregion
#region events
/// <summary> /// <summary>
/// An event invoked when the player begins loading the new star system, before the scene starts to load. /// An event invoked when the player begins loading the new star system, before the scene starts to load.
/// Gives the name of the star system being switched to. /// Gives the name of the star system being switched to.
@ -48,7 +70,9 @@ namespace NewHorizons
/// Gives the name of the planet that was just loaded. /// Gives the name of the planet that was just loaded.
/// </summary> /// </summary>
UnityEvent<string> GetBodyLoadedEvent(); UnityEvent<string> GetBodyLoadedEvent();
#endregion
#region Querying configs
/// <summary> /// <summary>
/// Uses JSONPath to query a body /// Uses JSONPath to query a body
/// </summary> /// </summary>
@ -68,23 +92,9 @@ namespace NewHorizons
/// Uses JSONPath to query the current star system /// Uses JSONPath to query the current star system
///</summary> ///</summary>
T QuerySystem<T>(string path); T QuerySystem<T>(string path);
#endregion
/// <summary> #region Spawn props
/// Allows you to overwrite the default system. This is where the player is respawned after dying.
/// </summary>
bool SetDefaultSystem(string name);
/// <summary>
/// Allows you to instantly begin a warp to a new star system.
/// Will return false if that system does not exist (cannot be warped to).
/// </summary>
bool ChangeCurrentStarSystem(string name);
/// <summary>
/// Returns the uniqueIDs of each installed NH addon.
/// </summary>
string[] GetInstalledAddons();
/// <summary> /// <summary>
/// Allows you to spawn a copy of a prop by specifying its path. /// Allows you to spawn a copy of a prop by specifying its path.
/// This is the same as using Props->details in a config, but also returns the spawned gameObject to you. /// This is the same as using Props->details in a config, but also returns the spawned gameObject to you.
@ -109,5 +119,44 @@ namespace NewHorizons
(CharacterDialogueTree, RemoteDialogueTrigger) SpawnDialogue(IModBehaviour mod, GameObject root, string xmlFile, float radius = 1f, (CharacterDialogueTree, RemoteDialogueTrigger) SpawnDialogue(IModBehaviour mod, GameObject root, string xmlFile, float radius = 1f,
float range = 1f, string blockAfterPersistentCondition = null, float lookAtRadius = 1f, string pathToAnimController = null, float range = 1f, string blockAfterPersistentCondition = null, float lookAtRadius = 1f, string pathToAnimController = null,
float remoteTriggerRadius = 0f); float remoteTriggerRadius = 0f);
#endregion
#region Load json/xml directly
/// <summary>
/// Allows creation of a planet by directly passing the json contents as a string.
/// </summary>
/// <param name="config"></param>
/// <param name="mod"></param>
void CreatePlanet(string config, IModBehaviour mod);
/// <summary>
/// Allows defining details of a star system by directly passing the json contents as a string.
/// </summary>
/// <param name="name"></param>
/// <param name="config"></param>
/// <param name="mod"></param>
void DefineStarSystem(string name, string config, IModBehaviour mod);
/// <summary>
/// Allows creation of dialogue by directly passing the xml and dialogueInfo json contents as strings
/// </summary>
/// <param name="textAssetID">TextAsset name used for compatibility with voice mod. Just has to be a unique identifier.</param>
/// <param name="xml">The contents of the dialogue xml file as a string</param>
/// <param name="dialogueInfo">The json dialogue info as a string. See the documentation/schema for what this can contain.</param>
/// <param name="planetGO">The root planet rigidbody that this dialogue is attached to. Any paths in the dialogueInfo are relative to this body.</param>
/// <returns></returns>
(CharacterDialogueTree, RemoteDialogueTrigger) CreateDialogueFromXML(string textAssetID, string xml, string dialogueInfo, GameObject planetGO);
/// <summary>
/// Directly add ship logs from XML. Call this method right before ShipLogManager awake.
/// </summary>
/// <param name="mod">The mod this method is being called from. This is required for loading files.</param>
/// <param name="xml">The ship log xml contents</param>
/// <param name="planetName">The planet that these ship logs correspond to in the map mode</param>
/// <param name="imageFolder">The relative path from your mod manifest.json where the ship log images are located. The filename must be the same as the fact id. Optional.</param>
/// <param name="entryPositions">A dictionary of each fact id to its 2D position in the ship log. Optional.</param>
/// <param name="curiousityColours">A dictionary of each curiousity ID to its colour and highlight colour in the ship log. Optional.</param>
void AddShipLogXML(IModBehaviour mod, XElement xml, string planetName, string imageFolder = null, Dictionary<string, Vector2> entryPositions = null, Dictionary<string, (Color colour, Color highlight)> curiousityColours = null);
#endregion
} }
} }

View File

@ -33,6 +33,7 @@ using NewHorizons.Utility.DebugTools;
using NewHorizons.Utility.DebugTools.Menu; using NewHorizons.Utility.DebugTools.Menu;
using NewHorizons.Components.Ship; using NewHorizons.Components.Ship;
using NewHorizons.Builder.Props.Audio; using NewHorizons.Builder.Props.Audio;
using Epic.OnlineServices;
namespace NewHorizons namespace NewHorizons
{ {
@ -600,6 +601,33 @@ namespace NewHorizons
#region Load #region Load
public void LoadStarSystemConfig(string starSystemName, StarSystemConfig starSystemConfig, string relativePath, IModBehaviour mod)
{
starSystemConfig.Migrate();
starSystemConfig.FixCoordinates();
if (starSystemConfig.startHere)
{
// We always want to allow mods to overwrite setting the main SolarSystem as default but not the other way around
if (starSystemName != "SolarSystem")
{
SetDefaultSystem(starSystemName);
_currentStarSystem = starSystemName;
}
}
if (SystemDict.ContainsKey(starSystemName))
{
if (string.IsNullOrEmpty(SystemDict[starSystemName].Config.travelAudio) && SystemDict[starSystemName].Config.Skybox == null)
SystemDict[starSystemName].Mod = mod;
SystemDict[starSystemName].Config.Merge(starSystemConfig);
}
else
{
SystemDict[starSystemName] = new NewHorizonsSystem(starSystemName, starSystemConfig, relativePath, mod);
}
}
public void LoadConfigs(IModBehaviour mod) public void LoadConfigs(IModBehaviour mod)
{ {
try try
@ -627,35 +655,13 @@ namespace NewHorizons
foreach (var file in systemFiles) foreach (var file in systemFiles)
{ {
var name = Path.GetFileNameWithoutExtension(file); var starSystemName = Path.GetFileNameWithoutExtension(file);
NHLogger.LogVerbose($"Loading system {name}"); NHLogger.LogVerbose($"Loading system {starSystemName}");
var relativePath = file.Replace(folder, ""); var relativePath = file.Replace(folder, "");
var starSystemConfig = mod.ModHelper.Storage.Load<StarSystemConfig>(relativePath, false); var starSystemConfig = mod.ModHelper.Storage.Load<StarSystemConfig>(relativePath, false);
starSystemConfig.Migrate(); LoadStarSystemConfig(starSystemName, starSystemConfig, relativePath, mod);
starSystemConfig.FixCoordinates();
if (starSystemConfig.startHere)
{
// We always want to allow mods to overwrite setting the main SolarSystem as default but not the other way around
if (name != "SolarSystem")
{
SetDefaultSystem(name);
_currentStarSystem = name;
}
}
if (SystemDict.ContainsKey(name))
{
if (string.IsNullOrEmpty(SystemDict[name].Config.travelAudio) && SystemDict[name].Config.Skybox == null)
SystemDict[name].Mod = mod;
SystemDict[name].Config.Merge(starSystemConfig);
}
else
{
SystemDict[name] = new NewHorizonsSystem(name, starSystemConfig, relativePath, mod);
}
} }
} }
if (Directory.Exists(planetsFolder)) if (Directory.Exists(planetsFolder))
@ -766,6 +772,19 @@ namespace NewHorizons
NHLogger.LogVerbose($"Loaded {config.name}"); NHLogger.LogVerbose($"Loaded {config.name}");
body = RegisterPlanetConfig(config, mod, relativePath);
}
catch (Exception e)
{
NHLogger.LogError($"Error encounter when loading {relativePath}:\n{e}");
MenuHandler.RegisterFailedConfig(Path.GetFileName(relativePath));
}
return body;
}
public NewHorizonsBody RegisterPlanetConfig(PlanetConfig config, IModBehaviour mod, string relativePath)
{
if (!SystemDict.ContainsKey(config.starSystem)) if (!SystemDict.ContainsKey(config.starSystem))
{ {
// Since we didn't load it earlier there shouldn't be a star system config // Since we didn't load it earlier there shouldn't be a star system config
@ -787,15 +806,7 @@ namespace NewHorizons
config.Validate(); config.Validate();
config.Migrate(); config.Migrate();
body = new NewHorizonsBody(config, mod, relativePath); return new NewHorizonsBody(config, mod, relativePath);
}
catch (Exception e)
{
NHLogger.LogError($"Error encounter when loading {relativePath}:\n{e}");
MenuHandler.RegisterFailedConfig(Path.GetFileName(relativePath));
}
return body;
} }
public void SetDefaultSystem(string defaultSystem) public void SetDefaultSystem(string defaultSystem)

View File

@ -1,10 +1,14 @@
using NewHorizons.Builder.Props; using NewHorizons.Builder.Props;
using NewHorizons.Builder.Props.Audio; using NewHorizons.Builder.Props.Audio;
using NewHorizons.Builder.ShipLog;
using NewHorizons.External; using NewHorizons.External;
using NewHorizons.External.Configs;
using NewHorizons.External.Modules; using NewHorizons.External.Modules;
using NewHorizons.External.Modules.Props; using NewHorizons.External.Modules.Props;
using NewHorizons.External.Modules.Props.Audio; using NewHorizons.External.Modules.Props.Audio;
using NewHorizons.External.Modules.Props.Dialogue; using NewHorizons.External.Modules.Props.Dialogue;
using NewHorizons.External.SerializableData;
using NewHorizons.OtherMods.MenuFramework;
using NewHorizons.Utility; using NewHorizons.Utility;
using NewHorizons.Utility.OWML; using NewHorizons.Utility.OWML;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -15,8 +19,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Xml.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
using static NewHorizons.External.Modules.ShipLogModule;
namespace NewHorizons namespace NewHorizons
{ {
@ -215,5 +221,88 @@ namespace NewHorizons
return DialogueBuilder.Make(root, null, info, mod); return DialogueBuilder.Make(root, null, info, mod);
} }
public void CreatePlanet(string config, IModBehaviour mod)
{
try
{
var planet = JsonConvert.DeserializeObject<PlanetConfig>(config);
if (planet == null)
{
NHLogger.LogError($"Couldn't load planet via API. Is your Json formatted correctly? {config}");
return;
}
var body = Main.Instance.RegisterPlanetConfig(planet, mod, null);
if (!Main.BodyDict.ContainsKey(body.Config.starSystem)) Main.BodyDict.Add(body.Config.starSystem, new List<NewHorizonsBody>());
Main.BodyDict[body.Config.starSystem].Add(body);
}
catch (Exception ex)
{
NHLogger.LogError($"Error in CreatePlanet API:\n{ex}");
}
}
public void DefineStarSystem(string name, string config, IModBehaviour mod)
{
var starSystemConfig = JsonConvert.DeserializeObject<StarSystemConfig>(config);
Main.Instance.LoadStarSystemConfig(name, starSystemConfig, null, mod);
}
public (CharacterDialogueTree, RemoteDialogueTrigger) CreateDialogueFromXML(string textAssetID, string xml, string dialogueInfo, GameObject planetGO)
{
var info = JsonConvert.DeserializeObject<DialogueInfo>(dialogueInfo);
return DialogueBuilder.Make(planetGO, null, info, xml, textAssetID);
}
public void AddShipLogXML(IModBehaviour mod, XElement xml, string planetName, string imageFolder, Dictionary<string, Vector2> entryPositions, Dictionary<string, (Color colour, Color highlight)> curiousityColours)
{
// This method has to be called each time the ship log manager is created, i.e. each time a system loads so it will only ever be relevant to the current one.
var starSystem = Main.Instance.CurrentStarSystem;
var body = new NewHorizonsBody(new PlanetConfig()
{
name = planetName,
starSystem = starSystem,
ShipLog = new ShipLogModule()
{
spriteFolder = imageFolder
}
}, mod);
if (!Main.BodyDict.ContainsKey(starSystem))
{
Main.BodyDict.Add(starSystem, new List<NewHorizonsBody>());
Main.BodyDict[starSystem].Add(body);
}
else
{
var existingBody = Main.BodyDict[starSystem]
.FirstOrDefault(x => x.Config.name == planetName && x.Mod.ModHelper.Manifest.UniqueName == mod.ModHelper.Manifest.UniqueName);
if (existingBody != null)
{
body = existingBody;
}
else
{
Main.BodyDict[starSystem].Add(body);
}
}
var system = new StarSystemConfig()
{
entryPositions = entryPositions?
.Select((pair) => new EntryPositionInfo() { id = pair.Key, position = pair.Value })
.ToArray(),
curiosities = curiousityColours?
.Select((pair) => new CuriosityColorInfo() { id = pair.Key, color = MColor.FromColor(pair.Value.colour), highlightColor = MColor.FromColor(pair.Value.highlight) })
.ToArray()
};
Main.Instance.LoadStarSystemConfig(starSystem, system, null, mod);
RumorModeBuilder.AddShipLogXML(GameObject.FindObjectOfType<ShipLogManager>(), xml, body);
}
} }
} }

View File

@ -0,0 +1,47 @@
using HarmonyLib;
using UnityEngine;
using static AnglerfishController;
namespace NewHorizons.Patches
{
[HarmonyPatch(typeof(AnglerfishAudioController))]
public static class AnglerfishAudioControllerPatches
{
[HarmonyPrefix]
[HarmonyPatch(nameof(AnglerfishAudioController.OnChangeAnglerState))]
public static bool AnglerfishAudioController_OnChangeAnglerState(AnglerfishAudioController __instance, AnglerState anglerState)
{
var scale = __instance.transform.parent.localScale.x;
if (scale == 1)
{
return true;
}
else
{
var modifier = 1f / Mathf.Clamp(scale, 0.5f, 2f);
__instance.UpdateLoopingAudio(anglerState);
if (anglerState == AnglerState.Investigating)
{
__instance._longRangeOneShotSource.pitch = modifier * Random.Range(0.8f, 1f);
__instance._longRangeOneShotSource.PlayOneShot(AudioType.DBAnglerfishDetectDisturbance, 1f);
return false;
}
if (anglerState == AnglerState.Chasing)
{
if (Time.time > AnglerfishAudioController.s_lastDetectTime + 2f)
{
AnglerfishAudioController.s_lastDetectTime = Time.time;
__instance._oneShotSource.pitch = modifier * Random.Range(0.8f, 1f);
__instance._oneShotSource.PlayOneShot(AudioType.DBAnglerfishDetectTarget, 1f);
return false;
}
MonoBehaviour.print("ANGLER DETECT TARGET SOUND BLOCKED");
}
return false;
}
}
}
}

View File

@ -4,7 +4,7 @@
"author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book", "author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book",
"name": "New Horizons", "name": "New Horizons",
"uniqueName": "xen.NewHorizons", "uniqueName": "xen.NewHorizons",
"version": "1.12.7", "version": "1.13.0",
"owmlVersion": "2.9.3", "owmlVersion": "2.9.3",
"dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ],
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ], "conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],